Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

numpy replace array elements with average of 2*2 blocks

I have an m*n matrix in numpy. I want to divide my matrix into 2*2 blocks and then replace each element with average of the elements in its 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 produce 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 is the most efficient way to do this? Should I use for loops?

like image 627
Navid777 Avatar asked Jul 01 '17 05:07

Navid777


People also ask

What does .all do in NumPy?

all() in Python. The numpy. all() function tests whether all array elements along the mentioned axis evaluate to True.

How do you compare two 2D NumPy arrays?

Method 1: We generally use the == operator to compare two NumPy arrays to generate a new array object. Call ndarray. all() with the new array object as ndarray to return True if the two NumPy arrays are equivalent.

How do you average a 2D array in Python?

To calculate the average of all values in a 2 dimensional NumPy array called matrix, use the numpy. average(matrix) function. The output will display a numpy array that has three average values, one per column of the input given array.


1 Answers

One approach would be to reshape splitting each of those two axes into two more and find mean along the latter of those two, giving us the average values. We will keep the dimensions with keepdims=True, so as to facilitate replicating along the reduced axes later on with np.repeat for the 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)

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

Generically put, the solution would 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)

Performance boost

We could replace that replicating part with an initialization based section, like so -

out = np.empty((m//p,p,n//q,q),dtype=float)
out[:] = b
out.shape = a.shape
like image 133
Divakar Avatar answered Sep 18 '22 01:09

Divakar