Numpy:高级切片

Numpy: advanced slices

我需要一种快速的方法来找到字符串中三个相邻元素中的最小元素,并将其添加到中心元素下的元素中。对于边框元素,只有两个上部元素正在检查。

例如我有一个 numpy 数组:

    [1, 2, 3, 4, 5], 
    [0, 0, 0, 0, 0]

我应该得到这个:

    [1, 2, 3, 4, 5], 
    [1, 1, 2, 3, 4]

我有这个代码:

for h in range(1, matrix.shape[0]):
    matrix[h][0] = min(matrix[h - 1][0], matrix[h - 1][1])
    matrix[h][1:-1] = ...(DONT KNOW, WHAT SHOULD BE HERE!!)
    matrix[h][-1] = min(matrix[h - 1][-2], matrix[h - 1][-1])

因为我有太多的数据而且我需要让它变快,所以我如何在不使用更多 for 循环的情况下计算它? Edit: David-z,这是我的项目)

使用numpy.minimum.reduce:

matrix[h][1:-1] = numpy.minimum.reduce([matrix[h-1][0:-2], matrix[h-1][1:-1], matrix[h-1][2:]])

例如:

>>> matrix = numpy.zeros((2,10))
>>> matrix[0, :] = numpy.random.randint(0,100,10)
>>> h = 1
>>> matrix[h][0] = matrix[h-1][:2].min()
>>> matrix[h][1:-1] = numpy.minimum.reduce([matrix[h-1][0:-2], matrix[h-1][1:-1], matrix[h-1][2:]])
>>> matrix[h][-1] = matrix[h-1][-2:].min()
>>> matrix
array([[ 10.,  40.,  90.,  13.,  21.,  58.,  64.,  56.,  34.,  69.],
       [ 10.,  10.,  13.,  13.,  13.,  21.,  56.,  34.,  34.,  34.]])

我会明确地这样做,以便通过显式切片更加清晰

n = 10
x = np.random.randint(0,100,n)
y = np.zeros_like(x,dtype=int)


for ind in range(n):
    if ind == 0:
        lo , hi = None , ind + 2
    elif ind >= n-2:
        lo , hi = ind - 1 , None
    else:
        lo , hi = ind - 1 , ind + 2
    y[ind] = np.min(x[lo:hi])

示例输出是

[21 74 95 96  6 96 78 74  6 92  5 32 72 64 30 13 72 59 19 26]
[21 21 74  6  6  6 74  6  6  5  5  5 32 30 13 13 13 19 19 19]

Daniel's 解决方案略有不同:

从值的行或列表开始:

In [439]: z=[10,40,90,13,21,58,64,56,34,69]

复制第一个和最后一个值;我可以通过连接、索引或简单的 pad 来做到这一点(内部 pad 相当复杂,因为它太通用了):

In [440]: z1=np.pad(z,(1,1),'edge')
In [441]: z1
Out[441]: array([10, 10, 40, 90, 13, 21, 58, 64, 56, 34, 69, 69])

现在制作3行矩阵(大牛解决方案的核心):

In [443]: [z1[0:-2], z1[1:-1], z1[2:]]
Out[443]: 
[array([10, 10, 40, 90, 13, 21, 58, 64, 56, 34]),
 array([10, 40, 90, 13, 21, 58, 64, 56, 34, 69]),
 array([40, 90, 13, 21, 58, 64, 56, 34, 69, 69])]

np.min on axis=0 等同于 minimum.reduce:

In [444]: np.min([z1[0:-2], z1[1:-1], z1[2:]],axis=0)
Out[444]: array([10, 10, 13, 13, 13, 21, 56, 34, 34, 34])

=========

将其扩展为二维数组:

In [454]: y=np.array(z).reshape(2,5)        # same values, reshape
In [455]: y1=np.pad(y,((0,0),(1,1)),'edge')  # 2d pad
In [456]: y1
Out[456]: 
array([[10, 10, 40, 90, 13, 21, 21],
       [58, 58, 64, 56, 34, 69, 69]])
In [457]: Y=np.array([y1[:,0:-2], y1[:,1:-1], y1[:,2:]])
In [458]: Y                            # 3d array
Out[458]: 
array([[[10, 10, 40, 90, 13],
        [58, 58, 64, 56, 34]],

       [[10, 40, 90, 13, 21],
        [58, 64, 56, 34, 69]],

       [[40, 90, 13, 21, 21],
        [64, 56, 34, 69, 69]]])
In [459]: np.min(Y,axis=0)
Out[459]: 
array([[10, 10, 13, 13, 13],
       [58, 56, 34, 34, 34]])

===============

as_strided 替代方案(仅限高级 numpy 用户:))

In [462]: np.lib.stride_tricks.as_strided(z1,shape=(10,3),strides=(4,4)).T
Out[462]: 
array([[10, 10, 40, 90, 13, 21, 58, 64, 56, 34],
       [10, 40, 90, 13, 21, 58, 64, 56, 34, 69],
       [40, 90, 13, 21, 58, 64, 56, 34, 69, 69]])