Эффективный способ получить среднюю площадь в numpy

Есть ли более эффективный способ определения средних значений определенной области в заданном массиве 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  ]]
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
166
1

Ответы 1

Это решение менее эффективно (медленнее), чем ваше, но является всего лишь примером использования модуля 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 ]]

Я понимаю. Спасибо, что показали мне альтернативу.

user1179317 10.01.2019 17:59

Другие вопросы по теме