Python 视图上的Numpy重塑

Python 视图上的Numpy重塑,python,numpy,reshape,Python,Numpy,Reshape,我对numpy整形手术的结果感到困惑。 在下面的示例中,q.flags表示它不拥有数据,但是q.base既不是x也不是y,那么它是什么呢?我很惊讶地看到q.strips是8,这意味着每次在内存中移动8个字节时它都会得到下一个元素(如果我理解正确的话)。但是,如果除了x之外没有其他数组拥有数据,那么唯一的数据缓冲区是来自x的,这不允许通过移动8个字节来获取q的下一个元素 In [99]: x = np.random.rand(4, 4) In [100]: y = x.T In [101]:

我对numpy整形手术的结果感到困惑。 在下面的示例中,q.flags表示它不拥有数据,但是q.base既不是x也不是y,那么它是什么呢?我很惊讶地看到q.strips是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])
更新:

事实证明,这个问题在numpy讨论论坛上被提出:

简而言之:您不能总是依赖
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
因为
q
没有反映第一个元素的变化,比如
x
y
,所以它一定是数据的所有者(下文将对此进行解释)

有关
OWNDATA
标志的更多讨论,请参阅。在问题中,简单地检查
ndarray
flags.owndata
有时似乎会失败,正如您所提到的,它似乎不可靠。这是因为每个
ndarray
也有一个
base
属性:

如果内存来自其他地方,则是对另一个数组的引用(否则,基为
None
)。操作
y.reformate(4)
创建一个副本,而不是一个视图,因为
y
的步幅是
(8,16)
。要将内存指针重新整形(C-连续)为
(4,)
,内存指针必须跳转
0->16->8->24
,这是单次跨步无法实现的。因此,
q.base
指向由强制复制操作
y.reformate
生成的内存位置,其形状与
y
相同,但复制了元素,因此具有正常的步幅:
(16,8)
<因此,code>q.base不受任何其他名称的约束,因为它是强制复制操作的结果。只有现在才能以
(4,)
形状查看对象
q.base
,因为跨步允许这样做
q
实际上是
q.base
上的一个视图


对于大多数人来说,如果看到
q.flags.owndata
False
,就会感到困惑,因为如上所示,它不是
y
上的视图。但是,它是
y
副本上的视图。但是,该副本,
q.base
,是数据的所有者。因此,如果仔细检查,这些标志实际上是正确的。

我喜欢使用
\uuuuu数组\uu接口

In [811]: x.__array_interface__
Out[811]: 
{'data': (149194496, False),
 'descr': [('', '<f8')],
 'shape': (4, 4),
 'strides': None,
 'typestr': '<f8',
 'version': 3}

In [813]: y.__array_interface__
Out[813]: 
{'data': (149194496, False),
 'descr': [('', '<f8')],
 'shape': (4, 4),
 'strides': (8, 32),
 'typestr': '<f8',
 'version': 3}

In [814]: x.strides
Out[814]: (32, 8)
In [815]: y.strides
Out[815]: (8, 32)
[811]中的
:x.\u数组\u接口__
出[811]:
{'data':(149194496,假),

'descr':[('',谢谢!那么q.base是一个复制的数组,具有表示q所需的对齐方式,然后q是它的一个视图,但是q.base没有被任何其他python名称绑定?我看了numpy讨论文章。在我看来,当它指代“owndata不可靠”时,它指的是在释放ndarray时是否会释放内存。我想,为了确定owndata是否正确反映所使用的内存缓冲区是ndarray.data还是ndarray.base.data,它仍然是一个准确的指示器。只是在这种情况下,q数组有一个没有命名的基数组,它实际上拥有数据。我的理解正确吗?@shaoyl85,你是正确的。我对你的两条评论的回复太长,无法添加到评论中,所以我在帖子中添加了它。谢谢!我认为这是有意义的,我猜“创建副本然后返回视图”的行为有点奇怪和意外。更一致的行为是,当无法返回输入数组的视图时,只返回数组的副本。谢谢!您是否知道“创建副本然后重塑”而不仅仅是“无法返回视图时返回副本”的原理?
In [817]: q.__array_interface__
Out[817]: 
{'data': (165219304, False),
 'descr': [('', '<f8')],
 'shape': (16,),
 'strides': None,
 'typestr': '<f8',
 'version': 3}