获取 numpy 数组或异常的平面视图



这个问题及其答案...

reShape((-1,)) 只要数组的步幅允许,它就会获得一个视图,即使这意味着你并不总是得到一个连续的数组。

。提出了另一个问题:假设我有任何可以想象的形状和内存布局的 n 维 numpy 数组,我如何获得它的保证扁平视图,或者如果它不是视图,则保证异常?

我在想这个笔记。 它可以转换为函数

It is not always possible to change the shape of an array without copying the data. If you want an error to be raised when the data is copied, you should assign the new shape to the shape attribute of the array:
a = np.zeros((10, 2))
# A transpose makes the array non-contiguous
b = a.T
# Taking a view makes it possible to modify the shape without modifying
# the initial object.
c = b.view()
c.shape = (20)
Traceback (most recent call last):
...
AttributeError: Incompatible shape for in-place modification. Use
`.reshape()` to make a copy with the desired shape.

哎呀,我看到删除的答案中引用了这句话。

编辑

让我们探索一下

In [17]: x = np.arange(24).reshape(2, 3, 4)
In [18]: x
Out[18]: 
array([[[ 0,  1,  2,  3],
[ 4,  5,  6,  7],
[ 8,  9, 10, 11]],
[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]])
In [19]: x.ravel()
Out[19]: 
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23])
In [20]: x.T
Out[20]: 
array([[[ 0, 12],
[ 4, 16],
[ 8, 20]],
...
[[ 3, 15],
[ 7, 19],
[11, 23]]])

转置的默认顺序"C"拉韦尔产生与基本aranage不同的序列。 显然这是一个副本。

In [21]: x.T.ravel()
Out[21]: 
array([ 0, 12,  4, 16,  8, 20,  1, 13,  5, 17,  9, 21,  2, 14,  6, 18, 10,
22,  3, 15,  7, 19, 11, 23])

但是"F"顺序是相同的 - 这是一个视图

In [22]: x.T.ravel(order='F')
Out[22]: 
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23])

让我们尝试一个列切片:

In [23]: x[:, 2:]
Out[23]: 
array([[[ 8,  9, 10, 11]],
[[20, 21, 22, 23]]])
In [24]: _.strides            # same as x
Out[24]: (96, 32, 8)
In [25]: __.ravel()
Out[25]: array([ 8,  9, 10, 11, 20, 21, 22, 23])
In [26]: x.strides
Out[26]: (96, 32, 8)

拉维尔不是初始arange的"常规"子集。 这是一个副本。

shares_memory证实了我的观察:

In [27]: np.shares_memory(x, Out[22])
Out[27]: True
In [28]: np.shares_memory(x, Out[21])
Out[28]: False
In [29]: np.shares_memory(x, Out[25])
Out[29]: False

让我们尝试引用中建议的技巧:

In [30]: c = Out[23].view()
In [31]: c
Out[31]: 
array([[[ 8,  9, 10, 11]],
[[20, 21, 22, 23]]])
In [32]: c.size
Out[32]: 8
In [34]: c.shape = (8,)
Traceback (most recent call last):
Input In [34] in <module>
c.shape = (8,)
AttributeError: Incompatible shape for in-place modification. Use `.reshape()` to make a copy with the desired shape.

尝试像 [34] 中那样设置shape仅适用于兼容的视图。 它从不复制。

最新更新