Aristotle0 Aristotle0 - 1 month ago 12
Python Question

How to evaluate the sum of values within array blocks

I have data array, with shape 100x100. I want to divide it into 5x5 blocks, and each block has 20x20 grids. The value of each block I want is the sum of all values in it.

Is there a more elegant way to accomplish it?

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


This is based on index, how if based on 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)


Z_new?

Answer

Simply reshape splitting each of those two axes into two each with shape (5,20) and then sum reduce along the axes having the lengths 20, like so -

Z_new = Z.reshape(5,20,5,20).sum(axis=(1,3))

Functionally the same, but potentially faster option with np.einsum -

Z_new = np.einsum('ijkl->ik',Z.reshape(5,20,5,20))

Runtime test -

In [18]: x = np.arange(100)
    ...: y = np.arange(100)
    ...: X, Y = np.meshgrid(x, y)
    ...: Z = np.cos(X)*np.sin(Y)
    ...: 

In [19]: %timeit Z.reshape(5,20,5,20).sum(axis=(1,3))
10000 loops, best of 3: 49.5 µs per loop

In [20]: %timeit np.einsum('ijkl->ik',Z.reshape(5,20,5,20))
10000 loops, best of 3: 46.7 µs per loop
Comments