我知道我可以做到以下几点:
import numpy as np
c = np.random.randn(20, 2)
a = c[:, 0]
b = c[:, 1]
此处,a
和b
分别指向c
的第一列和第二列。修改a
或b
将更改c
(相反地相同)。
然而,我想要实现的恰恰相反。我想创建一个2D内存视图,其中每列(或行)将指向不同1D阵列的内存。假设我已经有两个1D数组,是否可以为这些数组创建一个2D视图,其中每行/每列都指向它们?
我可以通过以下方式从c
和a
创建b
:
c = np.c_[a, b]
但是,这会将a
和b
内存复制到c
。我可以以某种方式创建c
作为'查看' [a b]
,其中,通过修改c
的元素,这反映在相应的a
或b
1D数组中?
答案 0 :(得分:4)
我认为不可能。
在您的第一个示例中,a
和b
视图的值是交织在一起的,从这个变体中可以看出:
In [51]: c=np.arange(10).reshape(5,2)
In [52]: a, b = c[:,0], c[:,1]
In [53]: a
Out[53]: array([0, 2, 4, 6, 8])
In [54]: c.flatten()
Out[54]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
data
和c
的{{1}}缓冲区从相同的内存点开始; a
从4个字节开始进入该缓冲区。
b
即使In [55]: c.__array_interface__
Out[55]:
{'strides': None,
'data': (172552624, False),...}
In [56]: a.__array_interface__
Out[56]:
{'strides': (8,),
'data': (172552624, False),...}
In [57]: b.__array_interface__
Out[57]:
{'strides': (8,),
'data': (172552628, False),...}
分割是按行进行的,a,b
也会在相同的共享数据缓冲区中继续进行。
从b
我们看到.flags
是c
,C-contiguous
不是。但是在该共享数据缓冲区中使用常量步幅访问b
值。
单独创建b
和a
时,它们的数据缓冲区是完全独立的。 b
跨步机制不能在这两个数据缓冲区之间来回切换。 numpy
和a
的2d复合必须使用自己的数据缓冲区。
我可以想象写一个最终看起来像你想要的课程。定义b
的indexing_tricks文件可能会为您提供想法(例如,具有自定义np.c_
方法的类)。但它不具备普通2d阵列的速度优势。并且可能很难实现所有__getitem__
功能。
答案 1 :(得分:2)
虽然@ hpaulj的答案是正确的,但对于你的特定情况,更多的是作为理解numpy内存布局的练习,而不是任何实际应用程序,这里是你如何获得两个1-D数组作为列的视图一个常见的数组:
>>> from numpy.lib.stride_tricks import as_strided
>>> a = np.arange(10)
>>> b = np.arange(20, 30)
>>> col_stride = (b.__array_interface__['data'][0] -
a.__array_interface__['data'][0])
>>> c = as_strided(a, shape=(10, 2), strides=(a.strides[0], col_stride))
>>> c
array([[ 0, 20],
[ 1, 21],
[ 2, 22],
[ 3, 23],
[ 4, 24],
[ 5, 25],
[ 6, 26],
[ 7, 27],
[ 8, 28],
[ 9, 29]])
>>> c[4, 1] = 0
>>> c[6, 0] = 0
>>> a
array([0, 1, 2, 3, 4, 5, 0, 7, 8, 9])
>>> b
array([20, 21, 22, 23, 0, 25, 26, 27, 28, 29])
这里有很多可能出错的地方,主要是数组b
没有增加引用计数,所以如果删除它,它的内存将被释放,但视图仍然会访问它。它也不能扩展到两个以上的1-D阵列,并要求两个1-D阵列具有相同的步幅。
当然,仅仅因为你能做到并不意味着你应该这样做!你绝对不应该这样做。