Numpy - 两个1D阵列的堆叠内存视图

时间:2015-02-14 17:39:17

标签: python numpy

我知道我可以做到以下几点:

import numpy as np
c = np.random.randn(20, 2)
a = c[:, 0]
b = c[:, 1]

此处,ab分别指向c的第一列和第二列。修改ab将更改c(相反地相同)。

然而,我想要实现的恰恰相反。我想创建一个2D内存视图,其中每列(或行)将指向不同1D阵列的内存。假设我已经有两个1D数组,是否可以为这些数组创建一个2D视图,其中每行/每列都指向它们?

我可以通过以下方式从ca创建b

c = np.c_[a, b]

但是,这会将ab内存复制到c。我可以以某种方式创建c作为'查看' [a b],其中,通过修改c的元素,这反映在相应的ab 1D数组中?

2 个答案:

答案 0 :(得分:4)

我认为不可能。

在您的第一个示例中,ab视图的值是交织在一起的,从这个变体中可以看出:

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])

datac的{​​{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我们看到.flagscC-contiguous不是。但是在该共享数据缓冲区中使用常量步幅访问b值。

单独创建ba时,它们的数据缓冲区是完全独立的。 b跨步机制不能在这两个数据缓冲区之间来回切换。 numpya的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阵列具有相同的步幅。

当然,仅仅因为你能做到并不意味着你应该这样做!你绝对不应该这样做。