Numpy重塑视图

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

Oli*_* W. 5

简而言之:你不能总是依赖于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,它必须以某种方式成为数据的所有者(以某种方式在下面解释).

OWNDATAnumpy-discussion 邮件列表上有关于旗帜的更多讨论.在如何判断NumPy是创建视图还是副本?的问题,它是简单地提及,仅仅检查flags.owndatandarray,有时好像失败,它似乎不可靠的,因为你提到.那是因为每个人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是数据的所有者.因此,如果仔细检查,标志实际上是正确的.