У меня есть DataFrame pandas, и я хочу вычислить на скользящей основе среднее значение всех значений: для всех столбцов, для всех наблюдений в скользящем окне.
У меня есть решение с петлями, но я чувствую себя очень неэффективным. Обратите внимание, что у меня может быть NaNs в моих данных, поэтому вычисление суммы и деление на форму окна было бы небезопасным (поскольку мне нужен nanmean).
Есть лучший подход?
Настраивать
import numpy as np
import pandas as pd
np.random.seed(1)
df = pd.DataFrame(np.random.randint(0, 10, size=(10, 2)), columns=['A', 'B'])
df[df>5] = np.nan # EDIT: add nans
Моя попытка
n_roll = 2
df_stacked = df.values
roll_avg = {}
for idx in range(n_roll, len(df_stacked)+1):
roll_avg[idx-1] = np.nanmean(df_stacked[idx - n_roll:idx, :].flatten())
roll_avg = pd.Series(roll_avg)
roll_avg.index = df.index[n_roll-1:]
roll_avg = roll_avg.reindex(df.index)
Желаемый результат
roll_avg
Out[33]:
0 NaN
1 5.000000
2 1.666667
3 0.333333
4 1.000000
5 3.000000
6 3.250000
7 3.250000
8 3.333333
9 4.000000
Спасибо!






Чтобы получить такой же результат в случае nan, вы можете использовать column_stack на всех df.shift(i).values for i in range(n_roll), использовать nanmean на оси = 1, а затем вам нужно заменить первое значение n_roll-1 на nan после:
roll_avg = pd.Series(np.nanmean(np.column_stack([df.shift(i).values for i in range(n_roll)]),1))
roll_avg[:n_roll-1] = np.nan
и со вторым входом с nan вы получите, как и ожидалось
0 NaN
1 5.000000
2 1.666667
3 0.333333
4 1.000000
5 3.000000
6 3.250000
7 3.250000
8 3.333333
9 4.000000
dtype: float64
Вот одно решение NumPy с раздвижными окнами на view_as_windows -
from skimage.util.shape import view_as_windows
# Setup o/p array
out = np.full(len(df),np.nan)
# Get sliding windows of length n_roll along axis=0
w = view_as_windows(df.values,(n_roll,1))[...,0]
# Assign nan-ignored mean values computed along last 2 axes into o/p
out[n_roll-1:] = np.nanmean(w, (1,2))
Эффективность памяти с views -
In [62]: np.shares_memory(df,w)
Out[62]: True
Большое спасибо за ответ. Как я могу избежать использования скимейджа? похоже, не включен в стандартный дистрибутив Anaconda / моя текущая среда
@FLab Или используйте strided_axis0: np.nanmean(strided_axis0(df.values, n_roll),(1,2)).
спасибо, он работает с strided_axis0. Я только что заметил, что если все значения в окне являются nan, у меня есть RuntimeWarning: среднее значение пустого фрагмента из импорта кода InteractiveConsole, и это, похоже, влияет на производительность времени, поэтому оно не так быстро, как решение `` стек '', которое я опубликовал
@FLab Не уверен, как предупреждения могут повлиять на производительность. Как насчет отключения предупреждений вверху?
Используя отвечать, упомянутый в комментарии, можно сделать:
wsize = n_roll
cols = df.shape[1]
out = group.stack(dropna=False).rolling(window=wsize * cols, min_periods=1).mean().reset_index(-1, drop=True).sort_index()
out.groupby(out.index).last()
out.iloc[:nroll-1] = np.nan
В моем случае было важно указать dropna=False в stack, иначе длина скользящего окна была бы неправильной.
Но я с нетерпением жду других подходов, поскольку это не очень элегантно / эффективно.
.shiftили сложить, а затем перевернуть окно большего размера.