4

我有一个二维数组,我需要将部分(切片)提取到一个新数组中:

original= numpy.ndarray( shape=(4,4) )
slices= numpy.ndarray( shape=(0,2) )
for x in range(3):
    slice= original[x:x+2,x:x+2] 
    slices=numpy.append(slices, slice,axis=0)

有没有更有效的方法来做到这一点(摆脱 python 循环)?

- - 编辑 - -

为了澄清,我问如何将任意(但类似)形状的 2D 切片从 2D 数组的任意 2D 索引复制到另一个垂直堆叠的 - 不是特别沿着对角线或 2x2 大小。

4

2 回答 2

3

有一个绝妙的技巧stride_tricks,您可以在 SO 和其他上找到具有不同通用性的滚动窗口函数(numpy 本身目前没有),这是根据您所获得的内容量身定制的版本:

def rolling_window(arr, window):
    """Very basic multi dimensional rolling window. window should be the shape of
    of the desired subarrays. Window is either a scalar or a tuple of same size
    as `arr.shape`.
    """
    shape = np.array(arr.shape*2)
    strides = np.array(arr.strides*2)
    window = np.asarray(window)
    shape[arr.ndim:] = window # new dimensions size
    shape[:arr.ndim] -= window - 1
    if np.any(shape < 1):
        raise ValueError('window size is too large')
    return np.lib.stride_tricks.as_strided(arr, shape=shape, strides=strides)

# Now:
view = rolling_window(arr, 2)
view[0,0] # first slice in your loop

请注意,它view包含与原始数组相同的数据!这可能会导致意想不到的结果。但是您似乎只想要对角线,您也可以使用跨步技巧来确保不复制数据(下一个版本将创建一个带有 的视图diagonal,旧版本总是一个副本):

diagonal = np.diagonal(view, axis1=0, axis2=1)
# unfortunatly now the first slice is diagonal[...,0], so just roll it to the start:
diagonal = np.rollaxis(diagonal, -1)

现在diagonal是您在 for 循环中创建的数组(在较新的版本中,.copy()如果您不想要视图,请添加 a)。

编辑:由于slices数组是 2D 而不是 3D 因为您追加,所以这里缺少重塑:

slices = diagonal.reshape(-1,2)

如果您有这么小的数组,这可能不会更快,但它的常量(期望复制diagonal调用中的数据)与数组大小有关。

于 2012-10-14T09:13:57.040 回答
1

这是您的解决方案:

v = np.arange(0,original.shape[0],0.5).astype(int)
result = np.c_[ original[v[1:-1],v[:-2]] , original[v[1:-1],v[2:]] ]

适用于任何大小的方形输入矩阵(您称之为“原始”)。

这个想法是创建一个“辅助数组”v,它只是 [0,0,1,1,2,2,3,3,...],然后使用观察你需要的索引总是简单的v的切片

享受!

于 2012-10-14T01:12:33.223 回答