Reputation: 187
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?
Upvotes: 2
Views: 209
Reputation: 262224
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. ]])
Upvotes: 2
Reputation: 126
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, ...
Upvotes: 2
Reputation: 1223
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. ]]
Upvotes: 1