Скользящие окна вдоль последней оси 2D-массива для получения 3D-массива с использованием шагов NumPy

Я пытаюсь использовать функцию as_strided из numpy.lib.stride_tricks для извлечения подсерий из большего 2D-массива, но я изо всех сил пытался найти правильную запись для аргумента strides.

Допустим, у меня есть матрица m, которая содержит 5 одномерных массивов длиной (a=)10. Я хочу извлечь вспомогательные 1D-массивы длиной (b=)4 для каждого 1D-массива в m.

import numpy
from numpy.lib.stride_tricks import as_strided

a, b = 10, 4
m = numpy.array([range(i,i+a) for i in range(5)])

# first try
sub_m = as_strided(m, shape=(m.shape[0], m.shape[1]-b+1, b))
print sub_m.shape # (5,7,4) which is what i expected
print sub_m[-1,-1,-1] # Some unexpected strange number: 8227625857902995061

# second try with strides argument
sub_m = as_strided(m, shape=(m.shape[0], m.shape[1]-b+1, b), strides=(m.itemize,m.itemize,m.itemize))
# gives error, see below

AttributeError: объект «numpy.ndarray» не имеет атрибута «itemize»

Как видите, мне удалось получить правильную форму для sub_m с первой попытки. Однако я не могу найти, что написать в strides=()

Для информации:

m = [[ 0  1  2  3  4  5  6  7  8  9]
 [ 1  2  3  4  5  6  7  8  9 10]
 [ 2  3  4  5  6  7  8  9 10 11]
 [ 3  4  5  6  7  8  9 10 11 12]
 [ 4  5  6  7  8  9 10 11 12 13]]

Ожидаемый результат:

sub_n = [
         [[0 1 2 3] [1 2 3 4] ... [5 6 7 8] [6 7 8 9]]
         [[1 2 3 4] [2 3 4 5] ... [6 7 8 9] [7 8 9 10]]
         [[2 3 4 5] [3 4 5 6] ... [7 8 9 10] [8 9 10 11]]
         [[3 4 5 6] [4 5 6 7] ... [8 9 10 11] [9 10 11 12]]
         [[4 5 6 7] [5 6 7 8] ... [9 10 11 12] [10 11 12 13]]
        ]

изменить: у меня гораздо больше данных, поэтому я хочу использовать as_strided (эффективность)


person Nuageux    schedule 01.06.2017    source источник
comment
Какова форма ожидаемого результата? Предположим, что вход имеет форму (m, n), и у вас есть длина шага, скажем, L.   -  person Divakar    schedule 01.06.2017
comment
Ожидаемая выходная форма: (5,7,4) (m,n,L), где L = m-4+1   -  person Nuageux    schedule 01.06.2017
comment
Может быть, вы имели в виду (m,n-L+1,L)?   -  person Divakar    schedule 01.06.2017
comment
Да, в самом деле. Вы правы (так же, как в коде)   -  person Nuageux    schedule 01.06.2017


Ответы (1)


Вот один из подходов с np.lib.stride_tricks.as_strided:

def strided_lastaxis(a, L):
    s0,s1 = a.strides
    m,n = a.shape
    return np.lib.stride_tricks.as_strided(a, shape=(m,n-L+1,L), strides=(s0,s1,s1))

Небольшое объяснение шагов для as_strided :

У нас есть 3D-шаги, которые увеличиваются на один элемент вдоль последней/третьей оси, поэтому s1 там для шага по последней оси. Вторая ось шагает на одно и то же "расстояние" одного элемента, так что s1 и за это тоже. Для первой оси шаг такой же, как и длина шага первой оси массива, когда мы движемся к следующей строке, поэтому там s0.

Пробный запуск -

In [46]: a
Out[46]: 
array([[0, 5, 6, 2, 3, 6, 7, 1, 4, 8],
       [2, 1, 3, 7, 0, 3, 5, 4, 0, 1]])

In [47]: strided_lastaxis(a, L=4)
Out[47]: 
array([[[0, 5, 6, 2],
        [5, 6, 2, 3],
        [6, 2, 3, 6],
        [2, 3, 6, 7],
        [3, 6, 7, 1],
        [6, 7, 1, 4],
        [7, 1, 4, 8]],

       [[2, 1, 3, 7],
        [1, 3, 7, 0],
        [3, 7, 0, 3],
        [7, 0, 3, 5],
        [0, 3, 5, 4],
        [3, 5, 4, 0],
        [5, 4, 0, 1]]])
person Divakar    schedule 01.06.2017
comment
Спасибо! Оно работает. Однако я до сих пор не понимаю, что я должен вставить в последний аргумент. Откуда (s0,s1,s1)? Я был бы очень признателен, если бы вы могли добавить больше деталей, чтобы в следующий раз мне не пришлось спрашивать :) - person Nuageux; 01.06.2017
comment
@Nuageux Сердечно извиняюсь, сэр! Добавлены комментарии. - person Divakar; 01.06.2017
comment
Большое спасибо за объяснение, не первый раз бьюсь с этой функцией, в следующий раз думаю не буду! (PS: Почему сэр?) - person Nuageux; 01.06.2017