滚动平均所有 Pandas DataFrame 的值

4
我有一个pandas DataFrame,想要在滚动窗口中对所有值进行平均值的计算:对于所有列,在滚动窗口内的所有观察值。
我有一个循环解决方案,但感觉非常低效。请注意,我的数据中可能有NaN,因此计算总和并除以窗口的形状不安全(因为我想要一个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

谢谢!


使用滚动在多列上可能会有用。您可以使用.shift,或者堆叠然后在更大的窗口上滚动。 - ALollz
3个回答

3

这里提供了一个使用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))

视图提高内存效率 -

In [62]: np.shares_memory(df,w)
Out[62]: True

非常感谢您的回答。有没有办法避免使用skimage?它似乎没有包含在标准anaconda发行版/我的当前环境中。 - FLab
@FLab 你可以使用源代码 - Divakar
1
@FLab 或者使用 strided_axis0np.nanmean(strided_axis0(df.values, n_roll),(1,2)) - Divakar
谢谢,使用strided_axis0后它可以工作了。我刚刚注意到,如果窗口中的所有值都是nan,我会收到一个RuntimeWarning: Mean of empty slice的警告。从代码导入InteractiveConsole似乎影响了时间性能,所以它不像我发布的“stack”解决方案那样快。 - FLab
@FLab 不确定警告如何影响性能。在顶部关闭警告怎么样? - Divakar

0
为了在出现nan的情况下获得相同的结果,您可以对所有df.shift(i).values for i in range(n_roll)使用column_stack,在axis=1上使用nanmean,然后需要将前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

0

使用评论中提到的答案,可以做到:

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=Falsestack中非常重要,否则滚动窗口的长度将不正确。
但是我期待其他方法,因为这种方法并不感觉很优雅/高效。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接