Использование Numpy stride_tricks для получения неперекрывающихся блоков массива - PullRequest
12 голосов
/ 09 ноября 2011

Я пытаюсь использовать numpy.lib.stride_tricks.as_strided для итерации по неперекрывающимся блокам массива, но у меня возникают проблемы с поиском документации параметров, поэтому я смог получить только перекрывающиеся блоки .

Например, у меня есть массив 4x5, из которого я хотел бы получить 4 блока 2x2. Я в порядке, если исключить лишние ячейки справа и снизу.

Пока мой код:

import sys
import numpy as np

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

sz = a.itemsize
h,w = a.shape
bh,bw = 2,2

shape = (h/bh, w/bw, bh, bw)
strides = (w*sz, sz, w*sz, sz)
blocks = np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)

print blocks[0][0]
assert blocks[0][0].tolist() == [[1, 2], [6,7]]
print blocks[0][1]
assert blocks[0][1].tolist() == [[3,4], [8,9]]
print blocks[1][0]
assert blocks[1][0].tolist() == [[11, 12], [16, 17]]

Форма полученного массива блоков, кажется, правильная, но последние два утверждения терпят неудачу, вероятно, потому что мои параметры формы или шагов неверны. Какие значения для них я должен установить, чтобы получить неперекрывающиеся блоки?

Ответы [ 3 ]

13 голосов
/ 09 ноября 2011
import numpy as np
n=4
m=5
a = np.arange(1,n*m+1).reshape(n,m)
print(a)
# [[ 1  2  3  4  5]
#  [ 6  7  8  9 10]
#  [11 12 13 14 15]
#  [16 17 18 19 20]]
sz = a.itemsize
h,w = a.shape
bh,bw = 2,2
shape = (h/bh, w/bw, bh, bw)
print(shape)
# (2, 2, 2, 2)

strides = sz*np.array([w*bh,bw,w,1])
print(strides)
# [40  8 20  4]

blocks=np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)
print(blocks)
# [[[[ 1  2]
#    [ 6  7]]
#   [[ 3  4]
#    [ 8  9]]]
#  [[[11 12]
#    [16 17]]
#   [[13 14]
#    [18 19]]]]

Начиная с 1 в a (т. Е. blocks[0,0,0,0]), чтобы добраться до 2 (т. Е. blocks[0,0,0,1]), остается один пункт. Поскольку (на моей машине) a.itemsize составляет 4 байта, шаг равен 1 * 4 = 4. Это дает нам последнее значение в strides = (10,2,5,1)*a.itemsize = (40,8,20,4).

Начиная с 1 снова, чтобы добраться до 6 (т. Е. blocks[0,0,1,0]), на расстоянии 5 (т. Е. w) предметов, так что шаг 5 * 4 = 20. Это объясняет значение от второго до последнего в strides.

Начиная с 1 еще раз, чтобы добраться до 3 (т. Е. blocks[0,1,0,0]), на расстоянии 2 (т. Е. bw) пунктов, поэтому шаг равен 2 * 4 = 8. Это объясняет второе значение в strides.

Наконец, начиная с 1, чтобы добраться до 11 (т. Е. blocks[1,0,0,0]), нужно 10 (т. Е. w*bh) предметов, поэтому шаг составляет 10 * 4 = 40. Итак, strides = (40,8,20,4) .

5 голосов
/ 29 января 2015

Используя ответ @ unutbu в качестве примера, я написал функцию, которая реализует этот трюк листов для любого массива ND. Ниже приведена ссылка на источник.

>>> a = numpy.arange(1,21).reshape(4,5)

>>> print a
[[ 1  2  3  4  5]
 [ 6  7  8  9 10]
 [11 12 13 14 15]
 [16 17 18 19 20]]

>>> blocks = blockwise_view(a, blockshape=(2,2), require_aligned_blocks=False)

>>> print blocks
[[[[ 1 2]
   [ 6 7]]

  [[ 3 4]
   [ 8 9]]]


 [[[11 12]
   [16 17]]

  [[13 14]
   [18 19]]]]

[blockwise_view.py] [test_blockwise_view.py]

1 голос
/ 05 февраля 2015

scikit-image имеет функцию с именем view_as_blocks(), которая делает почти то, что вам нужно.Единственная проблема состоит в том, что у него есть дополнительный assert, который запрещает ваш вариант использования, так как ваши блоки не делятся равномерно в форме массива.Но в вашем случае assert не является необходимым, поэтому вы можете скопировать исходный код функции и безопасно удалить надоедливое утверждение.

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