скользящее среднее с движущимся окном - PullRequest
1 голос
/ 01 апреля 2020

В моем информационном кадре есть столбец дневной цены и столбец размера окна:

df = pd.DataFrame(columns = ['price', 'window'],
             data = [[100, 1],[120, 2], [115, 2], [116, 2], [100, 4]])

df

        price   window
0        100    1
1        120    2
2        115    2
3        116    2
4        100    4

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

Результат будет таким:

df
    price   window  rolling_mean_price
0   100        1    100.00
1   120        2    110.00
2   115        2    117.50
3   116        2    115.50
4   100        4    112.75

Я не нахожу элегантного способа сделать это с применением и я отказываюсь l oop в каждой строке моего DataFrame ...

Ответы [ 2 ]

2 голосов
/ 01 апреля 2020

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

Numpy + Линейная сложность

size = len(df['price'])
price = np.zeros(size + 1)
price[1:] = df['price'].values.cumsum()

window = np.clip(np.arange(size) - (df['window'].values - 1), 0, None)
df['rolling_mean_price'] = (price[1:] - price[window]) / df['window'].values

print(df)

Выход

   price  window  rolling_mean_price
0    100       1              100.00
1    120       2              110.00
2    115       2              117.50
3    116       2              115.50
4    100       4              112.75

Loopy + линейная сложность

price = df['price'].values.cumsum()
df['rolling_mean_price'] = [(price[i] - float((i - w) > -1) * price[i-w]) / w for i, w in enumerate(df['window'])]

Loopy + Quadrati c сложность

price = df['price'].values
df['rolling_mean_price'] = [price[i - (w - 1):i + 1].mean() for i, w in enumerate(df['window'])]
1 голос
/ 01 апреля 2020

Я бы не рекомендовал этот подход, используя pandas.DataFrame.apply() (причины описаны здесь ), но если вы настаиваете на этом, вот одно решение:

df['rolling_mean_price'] = df.apply(
    lambda row: df.rolling(row.window).price.mean().iloc[row.name], axis=1)

Вывод выглядит так:

>>> print(df)
   price  window  rolling_mean_price
0    100       1              100.00
1    120       2              110.00
2    115       2              117.50
3    116       2              115.50
4    100       4              112.75
...