Как вычислить движущийся (или скользящий, если хотите) процентиль/квантиль для массива 1d в numpy?

В пандах у нас есть pd.rolling_quantile(). И в numpy у нас есть np.percentile(), но я не уверен, как сделать его скользящую/перемещающуюся версию.

Чтобы объяснить, что я имел в виду под движущимся/скользящим процентилем/квантилем:

Для заданного массива [1, 5, 7, 2, 4, 6, 9, 3, 8, 10] скользящий квантиль 0.5 (т.е. скользящий процентиль 50%) с размером окна 3 равен:

1
5 - 1 5 7 -> 0.5 quantile = 5
7 - 5 7 2 ->                5
2 - 7 2 4 ->                4
4 - 2 4 6 ->                4
6 - 4 6 9 ->                6
9 - 6 9 3 ->                6
3 - 9 3 8 ->                8
8 - 3 8 10 ->               8
10

Так что [5, 5, 4, 4, 6, 6, 8, 8] это ответ. Чтобы результирующий ряд имел ту же длину, что и входная, некоторые реализации вставляют NaN или None, а pandas.rolling_quantile() позволяет вычислить первые два значения квантиля в меньшем окне.


person Roy    schedule 01.12.2017    source источник
comment
Можете ли вы показать образцы данных и ожидаемый результат?   -  person BENY    schedule 01.12.2017
comment
Только что сделал. Надеюсь, это проясняет мою цель. @Вен   -  person Roy    schedule 01.12.2017
comment
проверьте ответ :-)   -  person BENY    schedule 01.12.2017
comment
Это то, что вам нужно?   -  person BENY    schedule 01.12.2017


Ответы (2)


Мы могли бы создать скользящие окна с помощью np.lib.stride_tricks.as_strided, реализованного как функция strided_app -

In [14]: a = np.array([1, 5, 7, 2, 4, 6, 9, 3, 8, 10]) # input array

In [15]: W = 3 # window length

In [16]: np.percentile(strided_app(a, W,1), 50, axis=-1)
Out[16]: array([ 5.,  5.,  4.,  4.,  6.,  6.,  8.,  8.])

Чтобы сделать его той же длины, что и ввод, мы могли бы дополнить NaNs np.concatenate или, проще, np.pad. Следовательно, для W=3 это будет -

In [39]: np.pad(_, 1, 'constant', constant_values=(np.nan)) #_ is previous one
Out[39]: array([ nan,   5.,   5.,   4.,   4.,   6.,   6.,   8.,   8.,  nan])
person Divakar    schedule 01.12.2017
comment
Помечен как ответ, так как он дает решение моего вопроса. Просто любопытно, может ли ваш метод расшириться, чтобы сделать min_periods бит pandas.rolling_quantile() (т.е. создать два дополнительных шага в начале, каждый с меньшим количеством членов)? @Дивакар - person Roy; 02.12.2017
comment
@ Рой Ага. Заполните входной массив NaN и используйте np.nanpercentile. - person Divakar; 02.12.2017
comment
Идеальный. Спасибо @Дивакар. - person Roy; 02.12.2017
comment
Такой подход может привести к переполнению памяти для больших входных массивов. - person Prokhozhii; 04.01.2021

series = pd.Series([1, 5, 7, 2, 4, 6, 9, 3, 8, 10])

In [194]: series.rolling(window = 3, center = True).quantile(.5)

Out[194]: 
0      nan
1   5.0000
2   5.0000
3   4.0000
4   4.0000
5   6.0000
6   6.0000
7   8.0000
8   8.0000
9      nan
dtype: float64

Центр False по умолчанию. Поэтому вам нужно вручную установить его на True, чтобы окно расчета квантиля симметрично охватывало текущий индекс.

person Saeed    schedule 16.02.2018