Numpy replace array elements with average of 2 * 2 blocks

I have m*n matrix

in numpy

. I want to split my matrix into 2 * 2 blocks and then replace each element with the average of the elements in my block. for example, consider the following array:

[
    [1, 2, 3, 4],
    [5, 6, 7, 8],
    [9, 10, 11, 12],
    [13, 14, 15, 16]
]

      

I want to create this matrix:

[
    [3.5, 3.5, 5.5, 5.5]
    [3.5, 3.5, 5.5, 5.5]
    [11.5, 11.5, 13.5, 13.5]
    [11.5, 11.5, 13.5, 13.5]
]

      

What's the most efficient way to do this? Should I use for loops?

+3


source to share


1 answer


One approach would be to reverse the splitting of each of these two axes into two and find mean

along the last of the two, giving us the average. We'll preserve the dimensions with keepdims=True

to make it easier to replicate along the downsized axes with the help np.repeat

for final output.

Thus, one implementation would be -

b = a.reshape(2,2,2,2).mean((1,3), keepdims=1)
out = np.repeat(np.repeat(b,(2),axis=(1)),(2), axis=3).reshape(4,4)

      

Example run -

In [17]: a
Out[17]: 
array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12],
       [13, 14, 15, 16]])

In [18]: b = a.reshape(2,2,2,2).mean((1,3), keepdims=1)

In [19]: np.repeat(np.repeat(b,(2),axis=(1)),(2), axis=3).reshape(4,4)
Out[19]: 
array([[  3.5,   3.5,   5.5,   5.5],
       [  3.5,   3.5,   5.5,   5.5],
       [ 11.5,  11.5,  13.5,  13.5],
       [ 11.5,  11.5,  13.5,  13.5]])

      



In general, the solution will look like this:

m,n = a.shape
p,q = (2,2) # Block size
b = a.reshape(m//p,p,n//q,q).mean((1,3), keepdims=1)
out = np.repeat(np.repeat(b,(p),axis=(1)),(q), axis=3).reshape(a.shape)

      

Productivity increase

We could replace this replicated part with an initialization based section as well -

out = np.empty((m//p,p,n//q,q),dtype=float)
out[:] = b
out.shape = a.shape

      

+3


source







All Articles