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

1

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

1 ответ

0

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню