Есть ли более эффективный способ определения средних значений определенной области в заданном массиве numpy? Для простоты предположим, что у меня есть массив 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 ]]
Я понимаю. Спасибо, что показали мне альтернативу.