2

I want to generate a twodimensional array in Python and I would like to iterate through each element and take an average. An element i should be averaged using the 8 surrounding array elements (including element i).

I generated the twodimensional array with a frame of zeros using Forming a frame of zeros around a matrix in python.

A = np.array([[1,2,3],[4,5,6],[7,8,9]])
x,y = A.shape
n = 1    
B = np.zeros((x+2*n,y+2*n),dtype=int)
B[n:x+n, n:y+n] = A
print(B)

What is the easiest way to take the average?

3
  • The link to the "Forming a frame of zeros around a matrix in python" question doesn't seem to work. Commented Aug 30, 2024 at 13:10
  • @Ichristmann, I made an edit
    – s28
    Commented Aug 30, 2024 at 13:18
  • if you're using numpy, tag the question numpy (I've added it).
    – Mark Reed
    Commented Aug 30, 2024 at 13:57

3 Answers 3

2

What you want is a 2D convolution, use scipy.signal.convolve2d with numpy.ones to get the sum:

from scipy.signal import convolve2d

out = convolve2d(B, np.ones((3, 3), dtype='int'), mode='same')

Output:

array([[ 1,  3,  6,  5,  3],
       [ 5, 12, 21, 16,  9],
       [12, 27, 45, 33, 18],
       [11, 24, 39, 28, 15],
       [ 7, 15, 24, 17,  9]])

If you want the small matrix, no need to pad with zeros:

convolve2d(A, np.ones((3, 3), dtype='int'), mode='same')

# array([[12, 21, 16],
#        [27, 45, 33],
#        [24, 39, 28]])

For the average, repeat the same operation with an array od ones and divide:

kernel = np.ones((3, 3), dtype='int')
out = (convolve2d(A, kernel, mode='same')
      /convolve2d(np.ones_like(A), kernel, mode='same')
      )

output:

array([[3. , 3.5, 4. ],
       [4.5, 5. , 5.5],
       [6. , 6.5, 7. ]])
2

This can be done relatively simply using a 3x3 kernel (filter) on your array, and making sure to also correctly check how many neighbours each element actually has (think edges and corners), before dividing to find the average.

from scipy.ndimage import convolve
import numpy as np

array = ...

kernel = np.array([[1,1,1],
                   [1,1,1],
                   [1,1,1]])

sum_neighbour = convolve(array, kernel, mode='constant', cval=0.0)

neighbour_count = convolve(np.ones_like(array), kernel, mode='constant', cval=0.0)

avg = sum_neighbour / neighbour_count

ex:

a matrix:

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

has neighbour count:

4,6,6,4
6,9,9,6
6,9,9,6
4,6,6,4

sum:

14, 24, 30, 22
33, 54, ...

avg:

3.5, 4, 5, 5.5
5.5, 6.0, ...
1

Get each submatrix, and take the average. Store results in a separate matrix (otherwise the previously calculated average would mess up the calculation for the next average):

Code:

import numpy as np

A = np.array([[1,2,3],[4,5,6],[7,8,9]])
x,y = A.shape
n = 1    
B = np.zeros((x+2*n,y+2*n),dtype=float)
B[n:x+n, n:y+n] = A

C = B.copy() # not doing it in-place because the math would get messed up
for i in range(x):
    for j in range(y):
        sub_b = B[i:i+x, j:j+y]
        average = np.sum(sub_b) / 9
        C[i + n, j + n] = average
        
print(C)

Output:

[[0.         0.         0.         0.         0.        ]
 [0.         1.33333333 2.33333333 1.77777778 0.        ]
 [0.         3.         5.         3.66666667 0.        ]
 [0.         2.66666667 4.33333333 3.11111111 0.        ]
 [0.         0.         0.         0.         0.        ]]

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.