如何计算数组块内的值的总和

Ari*_*le0 5 python numpy

我有数据数组,形状为 100x100。我想把它分成 5x5 块,每个块有 20x20 个网格。我想要的每个块的值是其中所有值的总和。

有没有更优雅的方法来实现它?

x = np.arange(100)
y = np.arange(100)
X, Y = np.meshgrid(x, y)
Z = np.cos(X)*np.sin(Y)
Z_new = np.zeros((5, 5))
for i in range(5):
  for j in range(5):
    Z_new[i, j] = np.sum(Z[i*20:20+i*20, j*20:20+j*20])
Run Code Online (Sandbox Code Playgroud)

这是基于索引的,如果基于 x 呢?

x = np.linspace(0, 1, 100)
y = np.linspace(0, 1, 100)
X, Y = np.meshgrid(x, y)
Z = np.cos(X)*np.sin(Y)
x_new = np.linspace(0, 1, 15)
y_new = np.linspace(0, 1, 15)
Run Code Online (Sandbox Code Playgroud)

Z_新?

Div*_*kar 5

简单地reshape将这两个轴中的每一个分成两个,每个轴都有形状(5,20)以形成一个4D数组,然后沿着具有长度的轴求和20,如下所示 -

Z_new = Z.reshape(5,20,5,20).sum(axis=(1,3))
Run Code Online (Sandbox Code Playgroud)

功能相同,但可能更快的选项np.einsum-

Z_new = np.einsum('ijkl->ik',Z.reshape(5,20,5,20))
Run Code Online (Sandbox Code Playgroud)

通用块大小

扩展到一般情况 -

H,W = 5,5 # block-size
m,n = Z.shape
Z_new = Z.reshape(H,m//H,W,n//W).sum(axis=(1,3))
Run Code Online (Sandbox Code Playgroud)

随着einsum变成-

Z_new = np.einsum('ijkl->ik',Z.reshape(H,m//H,W,n//W))
Run Code Online (Sandbox Code Playgroud)

要计算跨块的平均值/平均值,请使用mean代替sum方法。

通用块大小和归约操作

扩展到使用支持多个参数的reduction操作来减少,这将是 -ufuncsaxesaxis

def blockwise_reduction(a, height, width, reduction_func=np.sum):
    m,n = a.shape
    a4D = a.reshape(height,m//height,width,n//width)
    return reduction_func(a4D,axis=(1,3))
Run Code Online (Sandbox Code Playgroud)

因此,要解决我们的具体情况,它将是:

blockwise_reduction(Z, height=5, width=5)
Run Code Online (Sandbox Code Playgroud)

对于逐块平均计算,它将是 -

blockwise_reduction(Z, height=5, width=5, reduction_func=np.mean)
Run Code Online (Sandbox Code Playgroud)