Векторизация движущегося окна на двумерном массиве - PullRequest
10 голосов
/ 18 ноября 2011

Я применяю операцию к движущемуся окну постоянного размера в массиве 2D. Есть ли эффективная векторизованная операция, которую я могу реализовать, чтобы сделать это без циклов в Python? Моя текущая структура выглядит примерно так

 for i in range(1,xmax-1):
     for j in range(1,ymax-1):
        out[i][j] = f(in[i][j],in[i+1][j],in[i-1][j],in[i][j+1],in[i][j-1],...)

Комментарии, которые eat оставили в этом вопросе, ссылаются на возможность векторизации этой операции, но без дополнительных подробностей векторизованное индексирование / нарезка в numpy / scipy?

Ответы [ 2 ]

7 голосов
/ 18 ноября 2011

Если вы можете выразить функцию

f(in[i][j],in[i+1][j],in[i-1][j],in[i][j+1],in[i][j-1],…)

как линейный оператор, вы можете использовать функцию scipy signal.convolve2d , чтобы сделать именно это.Например, скажем, у вас есть массив 50x50, A, и вы хотите вычислить второй массив B, где каждый его элемент b[ij] является средним по a[i,j], a[(i-1),j], a[i,(j-1)], a[(i-1),(j-1)] из массива A. Вы можете сделать это, просто выполнив:

A = # your first array
B = numpy.ones((2,2))/4
C = scipy.signal.convolve2d(A,B, 'valid')

Когда выполняется свертка, массив B «скользит» по A, умножая соответствующие элементы и суммируя результат.Из-за эффектов границы вы должны быть осторожны при использовании результирующего массива C. Здесь C имеет форму 49x49 из-за аргумента 'valid' в convolve2d, чтобы отбросить первую строку и столбец, поскольку они содержат эффекты границы.Если бы вы хотели иметь массив 50x50, не отбрасывая, вы бы поменяли этот аргумент на 'same'

EDIT : возможно, если бы вы могли рассказать мне больше о той функции, которая вам нужна, я мог быболее конкретно поможет вам превратить его в массив, который будет использоваться для свертки 2D.

Надеюсь, это поможет!

6 голосов
/ 15 сентября 2017

Вы можете использовать метод скользящего окна, как объяснено здесь , здесь и здесь , но для двумерного массива.Исходный код для 2D скользящего окна в NumPy:

# Rolling window for 2D arrays in NumPy
import numpy as np

def rolling_window(a, shape):  # rolling window for 2D array
    s = (a.shape[0] - shape[0] + 1,) + (a.shape[1] - shape[1] + 1,) + shape
    strides = a.strides + a.strides
    return np.lib.stride_tricks.as_strided(a, shape=s, strides=strides)

a = np.array([[0,  1,  2,  3,  4,  5],
              [6,  7,  8,  9, 10,  11],
              [12, 13, 14, 15, 7,   8],
              [18, 19, 20, 21, 13, 14],
              [24, 25, 26, 27, 19, 20],
              [30, 31, 32, 33, 34, 35]], dtype=np.int)
b = np.arange(36, dtype=np.float).reshape(6,6)
present = np.array([[7,8],[13,14],[19,20]], dtype=np.int)
absent  = np.array([[7,8],[42,14],[19,20]], dtype=np.int)

found = np.all(np.all(rolling_window(a, present.shape) == present, axis=2), axis=2)
print(np.transpose(found.nonzero()))
found = np.all(np.all(rolling_window(b, present.shape) == present, axis=2), axis=2)
print(np.transpose(found.nonzero()))
found = np.all(np.all(rolling_window(a, absent.shape) == absent, axis=2), axis=2)
print(np.transpose(found.nonzero()))

Массив present встречается в массиве a два раза на [1,1] и [2,4].

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...