Эффективный способ получить среднюю площадь в NumPy - PullRequest
0 голосов
/ 10 января 2019

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

1 Ответ

0 голосов
/ 10 января 2019

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