Есть ли более эффективный способ определения средних значений для определенной области в данном массиве пустышек? Для простоты, скажем, у меня есть массив 5x5:
values = np.array([[0, 1, 2, 3, 4],
[1, 2, 3, 4, 5],
[2, 3, 4, 5, 6],
[3, 4, 5, 6, 7],
[4, 5, 6, 7, 8]])
Я хотел бы получить средние значения каждой координаты с указанным размером области, предполагая, что массив оборачивается вокруг. Допустим, определенная область имеет размер 2
, поэтому все, что находится вокруг определенной точки на расстоянии 2, будет рассмотрено. Например, чтобы получить среднее значение площади из координаты (2,2), нам нужно учесть
2,
2, 3, 4,
2, 3, 4, 5, 6
4, 5, 6,
6,
Таким образом, в среднем будет 4.
Для координаты (4, 4) нам нужно рассмотреть:
6,
6, 7, 3,
6, 7, 8, 4, 5
3, 4, 0,
5,
Таким образом, в среднем будет 4.92.
В настоящее время у меня есть следующий код ниже. Но так как у меня есть цикл for, я чувствую, что его можно улучшить. Есть ли способ просто использовать встроенные функции NumPy?
Есть ли способ использовать np.vectorize для сбора подмассивов (области), поместить все это в массив, затем использовать np.einsum или что-то еще.
def get_average(matrix, loc, dist):
sum = 0
num = 0
size, size = matrix.shape
for y in range(-dist, dist + 1):
for x in range(-dist + abs(y), dist - abs(y) + 1):
y_ = (y + loc.y) % size
x_ = (x + loc.x) % size
sum += matrix[y_, x_]
num += 1
return sum/num
class Coord():
def __init__(self, x, y):
self.x = x
self.y = y
values = np.array([[0, 1, 2, 3, 4],
[1, 2, 3, 4, 5],
[2, 3, 4, 5, 6],
[3, 4, 5, 6, 7],
[4, 5, 6, 7, 8]])
height, width = values.shape
averages = np.zeros((height, width), dtype=np.float16)
for r in range(height):
for c in range(width):
loc = Coord(c, r)
averages[r][c] = get_average(values, loc, 2)
print(averages)
Выход:
[[ 3.07617188 2.92382812 3.5390625 4.15234375 4. ]
[ 2.92382812 2.76953125 3.38476562 4. 3.84570312]
[ 3.5390625 3.38476562 4. 4.6171875 4.4609375 ]
[ 4.15234375 4. 4.6171875 5.23046875 5.078125 ]
[ 4. 3.84570312 4.4609375 5.078125 4.921875 ]]
Это решение менее эффективно (медленнее), чем ваше, но является лишь примером использования модуля numpy.ma
.
Обязательные библиотеки:
import numpy as np
import numpy.ma as ma
Определите методы для выполнения работы:
# build the shape of the area as a rhomboid
def rhomboid2(dim):
size = 2*dim + 1
matrix = np.ones((size,size))
for y in range(-dim, dim + 1):
for x in range(-dim + abs(y), dim - abs(y) + 1):
matrix[(y + dim) % size, (x + dim) % size] = 0
return matrix
# build a mask using the area shaped
def mask(matrix_shape, rhom_dim):
mask = np.zeros(matrix_shape)
bound = 2*rhom_dim+1
rhom = rhomboid2(rhom_dim)
mask[0:bound, 0:bound] = rhom
# roll to set the position of the rhomboid to 0,0
mask = np.roll(mask,-rhom_dim, axis = 0)
mask = np.roll(mask,-rhom_dim, axis = 1)
return mask
Затем выполните итерацию, чтобы получить результат:
mask_ = mask((5,5), 2) # call the mask sized as values array with a rhomboid area of size 2
averages = np.zeros_like(values, dtype=np.float16) # initialize the recipient
# iterate over the mask to calculate the average
for y in range(len(mask_)):
for x in range(len(mask_)):
masked = ma.array(values, mask = mask_)
averages[y,x] = np.mean(masked)
mask_ = np.roll(mask_, 1, axis = 1)
mask_ = np.roll(mask_, 1, axis = 0)
Который возвращается
# [[3.076 2.924 3.54 4.152 4. ]
# [2.924 2.77 3.385 4. 3.846]
# [3.54 3.385 4. 4.617 4.46 ]
# [4.152 4. 4.617 5.23 5.08 ]
# [4. 3.846 4.46 5.08 4.92 ]]