如何复制numpy数组,使其与原始数组具有相同的内存布局,包括步幅和任何相关的不连续性?基本上,新的__array_interface__
应该是相同的,除了指针。
理由:我需要针对不连续的数组测试我的代码,我需要运行多个破坏性测试,因此需要一个保留不连续性的副本。
示例(请注意,复制会更改步幅):
>>> import numpy as np
>>> a = np.empty((10, 6))
>>> b = a[::2]
>>> b.strides
(96, 8)
>>> b.copy(order='K').strides
(48, 8)
修改
以下是我根据senderle的答案使用的完整功能:
def exact_copy(data):
if data.base is None:
return data.copy()
base = data.base.copy()
offset = (data.__array_interface__['data'][0] -
data.base.__array_interface__['data'][0])
return np.ndarray(buffer=base.data, shape=data.shape, strides=data.strides,
offset=offset, dtype=data.dtype)
答案 0 :(得分:0)
基本上,你可以这样做,但在大多数情况下你可能不应该 - 效益不是那么大,numpy
中的很多东西对于非连续数据来说更难。
但是,做你想做的事并不难 - 你可以使用strides
公开的ndarray
参数。假设我们从一个里面有一些美味苹果的阵列开始,但还有很多其他的东西。我们如何把苹果拿出来?
>>> xapplesx = numpy.array(list('xxxaxpxpxlxexsxxx'))
>>> xapplesx
array(['x', 'x', 'x', 'a', 'x', 'p', 'x', 'p', 'x', 'l', 'x', 'e', 'x',
's', 'x', 'x', 'x'],
dtype='|S1')
我们希望从索引3
开始,我们希望获取所有其他值并将其放在一维视图中,这意味着我们希望获取每个2
nd值。
所以我们通过了offset=3
和strides=(2,)
:
>>> apples = numpy.ndarray(shape=(6,), dtype='|S1',
buffer=xapplesx, offset=3, strides=(2,))
>>> apples
array(['a', 'p', 'p', 'l', 'e', 's'],
dtype='|S1')
习惯于以这种方式直接使用strides
需要仔细考虑。假设我们想要获得我们的苹果并将它们放在x
以上。现在我们想要一个二维数组,我们必须为两个维度指定步幅。但我们希望第二行数据包含苹果之后的值。因此,我们为该维度指定了1
的步幅:
>>> applesoverx = numpy.ndarray(shape=(2, 6), dtype='|S1',
buffer=xapplesx, offset=3, strides=(1, 2))
>>> applesoverx
array([['a', 'p', 'p', 'l', 'e', 's'],
['x', 'x', 'x', 'x', 'x', 'x']],
dtype='|S1')
如果您在获取正确的buffer
数据时遇到问题,可以执行以下操作:
>>> a = np.arange(12).reshape(4,3)[::-1,:]
>>> x = np.ndarray(shape=a.shape, buffer=a.base.data,
strides=a.strides, offset=72, dtype=a.dtype)
唯一的技巧是你必须计算出正确的偏移量。结果是(我很确定)一个完美的克隆:
>>> x
array([[ 9, 10, 11],
[ 6, 7, 8],
[ 3, 4, 5],
[ 0, 1, 2]])
>>> a
array([[ 9, 10, 11],
[ 6, 7, 8],
[ 3, 4, 5],
[ 0, 1, 2]])
>>> x.shape
(4, 3)
>>> a.shape
(4, 3)
>>> x.strides
(-24, 8)
>>> a.strides
(-24, 8)
>>> id(x.base)
140602344736320
>>> id(a.base)
140602344736320
如果要复制原始数据,可以使用a.base.copy().data
作为buffer
参数。并且(正如Luke指出的那样),你可以用这个确定偏移量(见上文):
a.__array_interface__['data'][0] - a.base.__array_interface__['data'][0]
这为您提供了对给定数组缓冲区开始的指针的引用,如文档here所述。