2013-05-23 2 views
11

Я реализую алгоритм, который требует, чтобы я смотрел на неперекрывающиеся последовательные подматрицы внутри (строго двумерного) массива numpy. например, для 12 по 12Индексы фиксированных размерных матриц матрицы numpy

>>> a = np.random.randint(20, size=(12, 12)); a 
array([[ 4, 0, 12, 14, 3, 8, 14, 12, 11, 18, 6, 6], 
     [15, 13, 2, 18, 15, 15, 16, 2, 9, 16, 6, 4], 
     [18, 18, 3, 8, 1, 15, 14, 13, 13, 13, 7, 0], 
     [ 1, 9, 3, 6, 0, 4, 3, 15, 0, 9, 11, 12], 
     [ 5, 15, 5, 6, 4, 4, 18, 13, 10, 17, 11, 8], 
     [13, 17, 8, 15, 17, 12, 7, 1, 13, 15, 0, 18], 
     [ 2, 1, 11, 12, 3, 16, 11, 9, 10, 15, 4, 16], 
     [19, 11, 10, 7, 10, 19, 7, 13, 11, 9, 17, 8], 
     [14, 14, 17, 0, 0, 0, 11, 1, 10, 14, 2, 7], 
     [ 6, 15, 6, 7, 15, 19, 2, 4, 6, 16, 0, 3], 
     [ 5, 10, 7, 5, 0, 8, 5, 8, 9, 14, 4, 3], 
     [17, 2, 0, 3, 15, 10, 14, 1, 0, 7, 16, 2]]) 

и глядя на 3х3 подматрицы, я хотел бы, чтобы первый 3х3 подматрицы быть из верхнего левого угла:

>>> a[0:3, 0:3] 
array([[ 4, 0, 12], 
     [15, 13, 2], 
     [18, 18, 3]]) 

Следующая вдоль быть дано a[0:3, 3:6] и так далее. Не имеет значения, имеет ли последний такой набор индексов в каждой строке или столбце конец конца массива - поведение numpy просто дает часть внутри существующего среза.

Я хочу, чтобы сгенерировать эти индексы среза программно для произвольно размерных матриц и подматриц. Сейчас у меня это:

size = 3 
x_max = a.shape[0] 
xcoords = range(0, x_max, size) 
xcoords = zip(xcoords, xcoords[1:]) 

и аналогично для создания y_coords, так что ряд индексов задается itertools.product(xcoords, ycoords).

Мой вопрос: есть ли более прямой способ сделать это, возможно, используя numpy.mgrid или какую-нибудь другую технику numpy?

ответ

6

Попадая индексы

Вот быстрый способ получить конкретный size x size блок:

base = np.arange(size) # Just the base set of indexes 
row = 1    # Which block you want 
col = 0     
block = a[base[:, np.newaxis] + row * size, base + col * size] 

Если вы хотите, вы можете создать матрицы, похожие на ваш xcoords как:

y, x = np.mgrid[0:a.shape[0]/size, 0:a.shape[1]/size] 
y_coords = y[..., np.newaxis] * size + base 
x_coords = x[..., np.newaxis] * size + base 

Затем вы можете получить доступ к блоку следующим образом:

block = a[y_coords[row, col][:, np.newaxis], x_coords[row, col]] 

Попадая блоки непосредственно

Если вы просто хотите, чтобы блоки (а не индексы записей блока), я хотел бы использовать np.split (дважды):

blocks = map(lambda x : np.split(x, a.shape[1]/size, 1), # Split the columns 
         np.split(a, a.shape[0]/size, 0)) # Split the rows 

то у вас есть 2D список size x size блоков:

>>> blocks[0][0] 
array([[ 4, 0, 12], 
     [15, 13, 2], 
     [18, 18, 3]]) 

>>> blocks[1][0] 
array([[ 1, 9, 3], 
     [ 5, 15, 5], 
     [13, 17, 8]]) 

вы могли бы сделать это NumPy массив и использовать тот же стиль индексации, как описано выше:

>>> blocks = np.array(blocks) 
>>> blocks.shape 
(4, 4, 3, 3) 
+1

FYI, я только что проверил, и [ответ Саулио] (http://stackoverflow.com/a/16715845/310165) примерно в 3-4 раза быстрее, чем мой метод «map», если все, что вам нужно, это блоки , – Geoff

5

Вы можете использовать один вкладыш:

r = 3 
c = 3 
lenr = a.shape[0]/r 
lenc = a.shape[1]/c 
np.array([a[i*r:(i+1)*r,j*c:(j+1)*c] for (i,j) in np.ndindex(lenr,lenc)]).reshape(lenr,lenc,r,c) 
+2

+1 - Я не знал о 'ndindex'. Выглядит весьма полезно. – Geoff

2

Я добавляю этот ответ на старый вопрос так как правка врезались это вопрос выше. Вот альтернативный способ расчета блоков:

size = 3 
lenr, lenc = int(a.shape[0]/size), int(a.shape[1]/size) 

t = a.reshape(lenr,size,lenc,size).transpose(0, 2, 1, 3) 

Профилирование показывает, что это самый быстрый. Профилирование выполнено с помощью python 3.5, а результаты от карты переданы в array() для совместимости, так как в 3.5 карте возвращается итератор.

reshape/transpose: 643 ns per loop 
reshape/index:  45.8 µs per loop 
Map/split:   10.3 µs per loop 

Интересно, что версия итератора карты быстрее. В любом случае использование перестановки и транспонирования выполняется быстрее всего.

+0

Это, без сомнения, способ решить эту проблему; не вопрос об этом –

Смежные вопросы