Прокручивающееся окно для 1D-массивов в Numpy?

Есть ли способ эффективно реализовать скользящее окно для одномерных массивов в Numpy?

Например, у меня есть этот чистый фрагмент кода Python для вычисления скользящих стандартных отклонений для одномерного списка, где observations — это одномерный список значений, а n — длина окна для стандартного отклонения:

stdev = []
for i, data in enumerate(observations[n-1:]):
    strip = observations[i:i+n]
    mean = sum(strip) / n
    stdev.append(sqrt(250*sum([(s-mean)**2 for s in strip])/(n-1)))

Есть ли способ сделать это полностью в Numpy, то есть без каких-либо циклов Python? Стандартное отклонение тривиально с numpy.std, но часть с скользящим окном меня совершенно озадачивает.

Я нашел это сообщение в блоге о скользящем окне в Numpy. , но, похоже, это не для 1D-массивов.


person c00kiemonster    schedule 25.07.2011    source источник
comment
Вы также можете ознакомиться с проектом узкого места, в нем встроены скользящие средние, стандартные значения и т. д.   -  person derchambers    schedule 30.05.2017


Ответы (5)


Просто используйте код блога, но примените свою функцию к результату.

i.e.

numpy.std(rolling_window(observations, n), 1)

где у вас есть (из блога):

def rolling_window(a, window):
    shape = a.shape[:-1] + (a.shape[-1] - window + 1, window)
    strides = a.strides + (a.strides[-1],)
    return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)
person so12311    schedule 25.07.2011
comment
Можно ли распространить это на ось массива n-d? - person Gulzar; 27.06.2021
comment
Кроме того, как использовать это для создания перекрытия в шагах? - person Gulzar; 27.06.2021
comment
@Gulzar, если вы еще этого не сделали, посмотрите мой ответ ниже. Функция so12311 фактически работает с массивом n-d с движущимся окном вдоль последней оси. Моя функция работает с массивом n-d с движущимся окном по первой оси. Если вам нужно катиться по промежуточной оси, вам нужно будет разделить шаги и форму и добавить дополнительный элемент в соответствующем месте. Я не знаю, что вы имеете в виду под перекрытием, но вы, вероятно, можете добиться этого с другим шагом и формой. Попробуйте задать новый вопрос с подробным описанием того, что вам конкретно нужно. - person Leland Hepworth; 06.07.2021
comment
@LelandHepworth Спасибо. Под перекрытием я имею в виду, например, для массива [1, 2, 3, 4, 5]. Я хочу каким-то образом получить, например, [1, 2, 3], [2, 3, 4], [3, 4, 5]. - person Gulzar; 06.07.2021
comment
@Gulzar, используя любую версию функции, следующее должно дать вам то, что вы хотите: rolling_window(np.array([1, 2, 3, 4, 5]), 3) - person Leland Hepworth; 06.07.2021

Я попытался использовать so12311 ответ, указанный выше, для 2D-массива с формой [samples, features], чтобы получить выходной массив с формой [samples, timesteps, features] для использования с нейронной сетью свертки или lstm, но он работал не совсем правильно. Изучив, как работают шаги, я понял, что окно перемещается по последней оси, поэтому я внес некоторые коррективы, чтобы вместо этого окно перемещалось по первой оси:

def rolling_window(a, window_size):
    shape = (a.shape[0] - window_size + 1, window_size) + a.shape[1:]
    strides = (a.strides[0],) + a.strides
    return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)

ПРИМЕЧАНИЕ: нет никакой разницы в выводе, если вы используете только одномерный входной массив. В моем поиске это был первый результат, который приблизился к тому, что я хотел сделать, поэтому я добавляю это, чтобы помочь другим, ищущим аналогичный ответ.

person Leland Hepworth    schedule 29.01.2020

Только с одной строкой кода...

import pandas as pd

pd.Series(observations).rolling(n).std()
person Marco Cerliani    schedule 08.10.2019

Начиная с версии Numpy 1.20, вы можете напрямую получить скользящее окно с помощью sliding_window_view:

from numpy.lib.stride_tricks import sliding_window_view

sliding_window_view(np.array([1, 2, 3, 4, 5, 6]), window_shape = 3)
# array([[1, 2, 3],
#        [2, 3, 4],
#        [3, 4, 5],
#        [4, 5, 6]])
person Xavier Guihot    schedule 25.12.2020

Основываясь на последних ответах, здесь я добавляю код для прокатки одномерных массивов numpy, выбирая размер окна и частоту шагов окна.

a = np.arange(50)

def rolling_window(array, window_size,freq):
    shape = (array.shape[0] - window_size + 1, window_size)
    strides = (array.strides[0],) + array.strides
    rolled = np.lib.stride_tricks.as_strided(array, shape=shape, strides=strides)
    return rolled[np.arange(0,shape[0],freq)]

rolling_window(a,10,5)

Вывод:

array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9],
       [ 5,  6,  7,  8,  9, 10, 11, 12, 13, 14],
       [10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
       [15, 16, 17, 18, 19, 20, 21, 22, 23, 24],
       [20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
       [25, 26, 27, 28, 29, 30, 31, 32, 33, 34],
       [30, 31, 32, 33, 34, 35, 36, 37, 38, 39],
       [35, 36, 37, 38, 39, 40, 41, 42, 43, 44],
       [40, 41, 42, 43, 44, 45, 46, 47, 48, 49]])

person Miguel Gonzalez    schedule 28.04.2021