Есть ли способ иметь скользящее окно, которое варьируется в зависимости от произвольной серии целых чисел одного и того же временного ряда?

Необходимость возникла потому, что я хочу вычислить что-то вроде:

df['result'] = np.where(df['data1'] == True, df["data2"].rolling(window).max(), 0)

Однако: window практически df['window']; Ряд данных в одном временном ряду; он содержит целые числа, и они могут выглядеть примерно как [2,2,2,3,3,2,2,4,2,2].

Какой самый векторизованный или другой эффективный способ сделать это?

Пожалуйста, представьте более полный пример с данными, с которыми мы можем поиграть, и какой желаемый результат должен быть получен в этом примере.

piRSquared 08.04.2022 20:41

@piRSquared да, я могу сделать это позже, так как знаю, что это помогает при разработке ответов. А пока: я думаю, что этот вопрос почти точно такая же тема stackoverflow.com/questions/57064501, однако: у них нет там векторизованной версии ответа (хотя я не знаю, существует ли он).

j riv 08.04.2022 20:52

Не волнуйтесь, у меня есть векторное решение для вас.

piRSquared 08.04.2022 23:48

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

j riv 09.04.2022 06:58

Поскольку проблема сместилась исключительно на производительность, я специально задал новый вопрос, stackoverflow.com/questions/71805439

j riv 09.04.2022 07:15
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
5
65
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Настраивать

import pandas as pd
import numpy as np

np.random.seed([3,14])
a = np.random.randn(20).cumsum()
w = np.minimum(
    np.random.randint(1, 4, size=a.shape),
    np.arange(len(a))+1
)

df = pd.DataFrame({'Data': a, 'Window': w})
df

        Data  Window
0  -0.602923       1
1  -1.005579       2
2  -0.703250       3
3  -1.227599       1
4  -0.683756       1
5  -0.670621       2
6  -0.997120       1
7   0.387956       3
8   0.255502       1
9  -0.152361       2
10  1.150534       3
11  0.546298       3
12  0.302936       3
13  0.091674       1
14 -1.964947       1
15 -1.447079       2
16 -1.487828       1
17 -2.539703       1
18 -1.932612       3
19 -4.163049       2

Максимум скользящего векторизованного переменного окна

idx_base = np.arange(len(df))
windows = df.Window.to_numpy()
data = df.Data.to_numpy()

idx_max = np.concatenate([
    np.arange(position-(window_size-1), position+1)
    for window_size, position in zip(windows, idx_base)
])

idx_pos = np.repeat(idx_base, windows)
data_windowed = data[idx_max]

out = np.full(data.shape, data.min())
np.maximum.at(out, idx_pos, data_windowed)

Ответ теперь находится в переменной out. Давайте посмотрим

df.Data.iloc[idx_max].groupby(idx_pos).max().to_frame('Pandas').assign(Numpy=out)

      Pandas     Numpy
0  -0.602923 -0.602923
1  -0.602923 -0.602923
2  -0.602923 -0.602923
3  -1.227599 -1.227599
4  -0.683756 -0.683756
5  -0.670621 -0.670621
6  -0.997120 -0.997120
7   0.387956  0.387956
8   0.255502  0.255502
9   0.255502  0.255502
10  1.150534  1.150534
11  1.150534  1.150534
12  1.150534  1.150534
13  0.091674  0.091674
14 -1.964947 -1.964947
15 -1.447079 -1.447079
16 -1.487828 -1.487828
17 -2.539703 -2.539703
18 -1.487828 -1.487828
19 -1.932612 -1.932612

Приложение

Посмотрите на idx_max. Вы увидите, как мы закончим векторизацию этого.

print(idx_max)

[           #  Position   Window
  0         #         0        1
  0  1      #         1        2
  0  1  2   #         2        3
  3         #         3        1
  4         #         4        1
  4  5      #         5        2
  6         #         6        1
  5  6  7   #         7        3
  8         #         8        1
  8  9      #         9        2
  8  9 10   #        10        3
  9 10 11   #        11        3
 10 11 12   #        12        3
 13         #        13        1
 14         #        14        1
 14 15      #        15        2
 16         #        16        1
 17         #        17        1
 16 17 18   #        18        3
 18 19      #        19        2
]

Спасибо, так как это, кажется, дает те же результаты с методом apply (). Однако: он по-прежнему чрезвычайно медленный до такой степени, что становится непригодным для использования по сравнению с производительностью roll().max с учетом постоянного целочисленного окна. Но я подозреваю, что невозможно быть быстрым, потому что аппаратное обеспечение SIMD может предпочесть этот постоянный характер окон.

j riv 09.04.2022 06:51

Поскольку вопрос касался исключительно производительности, я принял этот ответ и задал новый вопрос специально для производительности, stackoverflow.com/questions/71805439

j riv 09.04.2022 07:16

Вы вообще изучали использование Numba?

piRSquared 09.04.2022 10:12

Нет, но я считаю, что в первом ответе прямо используется numba и сравнивается с cython, хотя это вызвало проблему с правильностью результатов.

j riv 09.04.2022 12:45

Я заметил что-то странное с этим методом: хотя он все еще заметно медленнее, чем метод stackoverflow.com/a/71806274/277716, найденный в новом вопросе, у меня смутное впечатление, что теперь он быстрее, чем был, когда я впервые тестировал, и единственное отличие, о котором я могу думать, это установка mumba /llvmlite, но он остается прежним после их удаления, так что это может быть не связано. Это не имеет решающего значения, поскольку этот другой метод остается более производительным (хотя они, похоже, дают те же результаты).

j riv 09.04.2022 14:46

Другие вопросы по теме