Abracadabra
Abracadabra

Reputation: 199

Numpy element-wise mean calculation for 2D array

I am new in Python and faced with a problem of calculating element-wise mean value in 2D numpy array. I've searched in the web and didn't find the optimal algorithm for this stuff.

So, for example I have this 2D array:

array = np.arange(20).reshape(4,5)
array

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

I want to get another 2D numpy array with the elements equal to element-wise mean values of previous matrix. Moreover, my target is to have the output matrix with the same shape as the input matrix.

For example I've select a 3*3 block of neighnourhood elements and start with the first element of matrix (zero):

1st element

Since its a 'corner' element we can not calculate the mean of 3 * 3, so I assume we can calculate mean of 2 * 2: (0+1+5+6):4=3

Then we move our 3 * 3 block to the next element:

2nd mean calc

And calculate the mean in the same way and so on for the first row of the matrix. Moving row by row, element by element:

3rd mean

And calculate their mean in the same way: (0+1+2+5+6+7+10+11+12):9=6

And do so on.

Could you tell me please how it is possible to create the matrix of the mean elements with the same shape as an input matrix? Shall I operate it with for loop with 2 variables? And how to deal with 'border' elements where we can not apply full 3 * 3 block of neighbour element?

Will be really appreciated for your help!

P.S. On my calculations I assume to have the final result matrix, for this case:

final matrix

Upvotes: 2

Views: 1389

Answers (2)

Valdi_Bo
Valdi_Bo

Reputation: 30971

You can do your task using solely Numpy.

To compute the mean of an element and its neighbours, define the following function:

def meanSurroud(arr, r, c):
    return np.mean(arr[max(r - 1, 0) : r + 2, max(c - 1, 0) : c + 2])

Then call it for each index in your source array and save the result in a target array:

result = np.empty_like(array, dtype=float)
for ind in np.ndindex(array.shape):
    result[ind] = meanSurroud(array, ind[0], ind[1])

The result is:

array([[ 3. ,  3.5,  4.5,  5.5,  6. ],
       [ 5.5,  6. ,  7. ,  8. ,  8.5],
       [10.5, 11. , 12. , 13. , 13.5],
       [13. , 13.5, 14.5, 15.5, 16. ]])

Upvotes: 1

obchardon
obchardon

Reputation: 10792

If using scipy is an option, you can use a 2D convolution:

import numpy as np
from scipy import signal

# Example input
x = np.array([[ 0,  1,  2,  3,  4],
              [ 5,  6,  7,  8,  9],
              [10, 11, 12, 13, 14],
              [15, 16, 17, 18, 19]])

# The moving window
y = np.ones((3,3))

# We convolve x with y and then we normalize those value with another convolution
#  |        first convolution        |/|              second convolution               |
r = signal.convolve2d(x,y,mode='same')/signal.convolve2d(np.ones(x.shape),y,mode='same')

And it produce:

array([[ 3. ,  3.5,  4.5,  5.5,  6. ],
       [ 5.5,  6. ,  7. ,  8. ,  8.5],
       [10.5, 11. , 12. , 13. , 13.5],
       [13. , 13.5, 14.5, 15.5, 16. ]])

how it works ?

So the first convolution produce the sum of the desired element:

array([[ 12,  21,  27,  33,  24],
       [ 33,  54,  63,  72,  51],
       [ 63,  99, 108, 117,  81],
       [ 52,  81,  87,  93,  64]])

And the second one produce the ponderation (how many element have been summed at each position):

 array([[4., 6., 6., 6., 4.],
        [6., 9., 9., 9., 6.],
        [6., 9., 9., 9., 6.],
        [4., 6., 6., 6., 4.]])

Upvotes: 2

Related Questions