Python Pandas:计算组内的移动平均值

Posted

技术标签:

【中文标题】Python Pandas:计算组内的移动平均值【英文标题】:Python Pandas: Calculate moving average within group 【发布时间】:2019-04-19 17:03:35 【问题描述】:

我有一个包含 100 个对象的时间序列的数据框:

object  period  value 
1       1       24
1       2       67
...
1       1000    56
2       1       59
2       2       46
...
2       1000    64
3       1       54
...
100     1       451
100     2       153
...
100     1000    21

我想用窗口 10 计算 value 列的移动平均值。我想我必须做类似的事情

df.groupby('object').apply(lambda ~calculate MA~) 

然后按对象将此系列合并到原始数据框?无法确定确切的命令

【问题讨论】:

移动平均线的行数会更少,应该将它们分配到哪些时段? 最好这样做:对于周期 1,MA 等于周期 1 的值。从周期 2 开始,MA = (value_1 + value_2) / 2,依此类推,直到 10。 10 点之后,这是一个正常的移动平均线 我正在尝试使用 pd.rolling_mean(),但还没有弄明白 【参考方案1】:

您可以将rolling 与transform 一起使用:

df['moving'] = df.groupby('object')['value'].transform(lambda x: x.rolling(10, 1).mean())

rolling 中的 1 用于表示最少的句点数。

【讨论】:

哦,太美了!我爱熊猫! 这是推荐的方式:我打算用pd.rolling_mean 回答并收到弃用警告。所以,谢谢你今天教我一些东西@zipa 如何使用talib.BBANDS() 计算组内的Bolinger Band 值?以下代码给出错误。 (BBANDS() 返回一个元组(上、中、下)。)df['bb_up'], df['bb_mid'], df['bb_low'] = df.groupby('object')['value'].transform(lambda x: talib.BBANDS(x))【参考方案2】:

您可以在groupby 对象上直接使用rolling

df['moving'] = df.groupby('object').rolling(10)['value'].mean()

新版pandas使用直接赋值给列时会报错,所以使用:

df['moving'] = df.groupby('object').rolling(10)['value'].mean().reset_index(drop=True)

【讨论】:

嗨,我收到一个错误:TypeError: incompatible index of inserted column with frame index。不知道是什么问题... 这清除了错误,但 df['avg'] 对我来说完全是空的。我的熊猫版本是 0.24.2 @SarahMesser 那是因为您在每个组中只有一个值,请检查 object 是否只有唯一值,这意味着您计算滚动的每个组只有一个值,因此您得到NaN's 糟糕。我删除了列表理解中的“句点”循环,以简化数据框并使示例最小化。如您所说,将其添加回固定的空值。 我在 mean() 和 reset_index() 之间添加了一个 shift(1),因为我不想在计算 period-2 的平均值时包含 period-2 的值...这似乎通过将多索引中的值从一个“对象”组转移到下一个来混淆值。手动构建的小型数据框似乎也依赖于原始索引。可能有必要运行df.sort_values(by=['object', 'period']).reset_index(drop=True) 你的groupby-rolling构造,以保证索引对齐。【参考方案3】:

如果您在多列上进行分组,所提供的答案可能不会产生预期的结果。

下面应该删掉它:

df['moving'] = df.groupby(['col_1', 'col_2', 'col_3']).rolling(10)['value'].mean().droplevel(level=[0,1,2])

【讨论】:

这应该是最佳答案+1! (.droplevel 可以替换为 .reset_index,顺便说一句)。【参考方案4】:

扩展来自@Sandeep Kadapa 的答案:

df['moving'] = df.groupby('object').rolling(10)['value'].mean().reset_index(drop=True)

reset_index 的原因是因为在df.groupby 之后我们最终得到了一个多级索引并且在分配时我们会得到错误TypeError: incompatible index of inserted column with frame index

【讨论】:

【参考方案5】:

将列创建为链式方法:

(
    df
        .assign(
            column_name = lambda x: 
                x
                    .groupby(['object'])['value']
                    .transform(lambda x: x.rolling(10)
                    .mean())
        )
)

【讨论】:

【参考方案6】:

这些解决方案假定数据框以特定方式(按对象和周期)排序。例如,如果数据被组织在面板中(按期间和对象),那么分配将失败。一种与排序顺序无关的通用解决方案如下:

df.loc[:, 'value_sma_10'] = df.groupby(by='object')[['object', 'period']].rolling(window=10, min_periods=1, on='period').mean().reset_index(level='object')['value']

【讨论】:

以上是关于Python Pandas:计算组内的移动平均值的主要内容,如果未能解决你的问题,请参考以下文章

Python/Pandas - 结合 groupby 平均值和最小值

python pandas groupby分组后的数据怎么用

Pandas---11.移动窗口函数

Pandas Dataframe:获取组内每个子组的第一行的平均值

Pandas按组内的值分组和排序[重复]

组内的 Cumsum 并在 pandas 的条件下重置