sha*_*l85 5 python numpy reshape
我对在视图上操作的numpy reshape的结果感到困惑.在下面的q.flags中显示它不拥有数据,但q.base既不是x也不是y,那么它是什么?我很惊讶地看到q.strides是8,这意味着它每次在内存中移动8个字节时获得下一个元素(如果我理解正确的话).但是,如果x以外的数组都没有数据,则唯一的数据缓冲区来自x,它不允许通过移动8个字节来获取q的下一个元素.
In [99]: x = np.random.rand(4, 4)
In [100]: y = x.T
In [101]: q = y.reshape(16)
In [102]: q.base is y
Out[102]: False
In [103]: q.base is x
Out[103]: False
In [104]: y.flags
Out[104]:
C_CONTIGUOUS : False
F_CONTIGUOUS : True
OWNDATA : False
WRITEABLE : True
ALIGNED : True
UPDATEIFCOPY : False
In [105]: q.flags
Out[105]:
C_CONTIGUOUS : True
F_CONTIGUOUS : True
OWNDATA : False
WRITEABLE : True
ALIGNED : True
UPDATEIFCOPY : False
In [106]: q.strides
Out[106]: (8,)
In [107]: x
Out[107]:
array([[ 0.62529694, 0.20813211, 0.73932923, 0.43183722],
[ 0.09755023, 0.67082005, 0.78412615, 0.40307291],
[ 0.2138691 , 0.35191283, 0.57455781, 0.2449898 ],
[ 0.36476299, 0.36590522, 0.24371933, 0.24837697]])
In [108]: q
Out[108]:
array([ 0.62529694, 0.09755023, 0.2138691 , 0.36476299, 0.20813211,
0.67082005, 0.35191283, 0.36590522, 0.73932923, 0.78412615,
0.57455781, 0.24371933, 0.43183722, 0.40307291, 0.2449898 ,
0.24837697])
Run Code Online (Sandbox Code Playgroud)
更新:
事实证明,在numpy讨论论坛中已经提出了这个问题:http: //numpy-discussion.10968.n7.nabble.com/OWNDATA-flag-and-reshape-views-vs-copies-td10363.html
简而言之:你不能总是依赖于ndarray.flags['OWNDATA'].
>>> import numpy as np
>>> x = np.random.rand(2,2)
>>> y = x.T
>>> q = y.reshape(4)
>>> y[0,0]
0.86751629121019136
>>> y[0,0] = 1
>>> q
array([ 0.86751629, 0.87671107, 0.65239976, 0.41761267])
>>> x
array([[ 1. , 0.65239976],
[ 0.87671107, 0.41761267]])
>>> y
array([[ 1. , 0.87671107],
[ 0.65239976, 0.41761267]])
>>> y.flags['OWNDATA']
False
>>> x.flags['OWNDATA']
True
>>> q.flags['OWNDATA']
False
>>> np.may_share_memory(x,y)
True
>>> np.may_share_memory(x,q)
False
Run Code Online (Sandbox Code Playgroud)
因为q没有反映第一个元素的变化,比如x或者y,它必须以某种方式成为数据的所有者(以某种方式在下面解释).
OWNDATA在numpy-discussion 邮件列表上有关于旗帜的更多讨论.在如何判断NumPy是创建视图还是副本?的问题,它是简单地提及,仅仅检查flags.owndata的ndarray,有时好像失败,它似乎不可靠的,因为你提到.那是因为每个人ndarray都有一个base属性:
在一个ndarray的基础是,如果存储器别处发起的(否则,该碱是另一个数组的引用None).该操作y.reshape(4)创建了一个副本,而不是视图,因为它的步幅y是(8,16).为了将它重新整形(C-contiguous)(4,),内存指针必须跳转0->16->8->24,这对于单个步幅是不可行的.因此,q.base指向强制复制操作生成的内存位置y.reshape,它具有相同的形状y,但复制了元素,因此再次具有正常的步幅:(16, 8).q.base因此,它不受任何其他名称的约束,因为它是强制复制操作的结果y.reshape(4).只有现在才能q.base在一个(4,)形状中查看对象,因为步幅允许这样做.q然后确实是一个观点q.base.
对于大多数人来说这将是混乱的看到q.flags.owndata就是False,因为,如上图所示,它不是一个视图y.但是,它是一个副本的视图y.然而,该副本q.base是数据的所有者.因此,如果仔细检查,标志实际上是正确的.