如何在多索引Pandas DataFrame中按指定日频率计算滚动平均值?
问题描述
我有如下结构的Pandas DataFrame,需要按company和dt(日期)分组后,计算指定日数(如2天、3天)的滚动平均值:
import pandas as pd df = pd.DataFrame({ 'company': ['abc', 'abc', 'abc', 'xyz', 'xyz', 'xyz'], 'dt': pd.to_datetime([ '2022-01-01', '2022-01-02', '2022-01-03', '2022-01-31', '2022-02-01', '2022-02-02' ]), 'volume': [1, 2, 3, 4, 5, 6] })
我尝试了这段代码:
df.groupby(['company', 'dt'])['volume'].mean().rolling(2).mean()
结果却跨公司计算了滚动平均(比如xyz的结果混入了abc的数据),不符合需求。另外,如果把窗口设为'2D'或'3D',还会报错:ValueError: window must be an integer 0 or greater。
难道只能像下面这样逐个公司单独写代码吗?
df[df['company']=='abc'].groupby(['dt'])['volume'].mean().rolling('2D').mean() df[df['company']=='xyz'].groupby(['dt'])['volume'].mean().rolling('2D').mean()
解决方案
完全不需要逐个公司拆分代码,只要调整分组和滚动计算的顺序,就能实现按公司隔离的滚动平均,同时支持两种常见的滚动场景:
1. 基于行数的滚动平均(如最近2条数据)
先按company分组,确保每组内的日期有序(如果原始数据日期乱序,先排序),再对每组内的volume执行滚动计算:
# 先按公司和日期排序(如果数据已有序可省略) df_sorted = df.sort_values(['company', 'dt']) # 按公司分组后,计算滚动2行的平均值 result_int = df_sorted.groupby('company')['volume'].rolling(2).mean().reset_index()
这样每个公司的滚动计算完全独立,不会出现跨公司的情况,结果会保留company、dt和计算出的滚动平均值。
2. 基于日期范围的滚动平均(如最近2天)
如果要按日期跨度(比如过去2天内的数据)计算,需要让Pandas识别日期列。有两种简单的实现方式:
方法一:将日期设为索引后计算
df_sorted = df.sort_values(['company', 'dt']) result_date = df_sorted.groupby('company').apply( lambda group: group.set_index('dt')['volume'].rolling('2D').mean() ).reset_index()
方法二:使用on参数指定日期列(Pandas 1.3+版本支持)
df_sorted = df.sort_values(['company', 'dt']) result_date = df_sorted.groupby('company').rolling('2D', on='dt')['volume'].mean().reset_index()
这两种方式都能保证每个公司只使用自身的日期数据计算,同时支持'2D'、'3D'这类日期偏移窗口。
为什么你的原始代码出问题?
- 你最初的代码把
company和dt一起设为多级索引,后续的rolling(2)是在整个结果集上滚动,自然会跨公司计算。 - 使用日期偏移窗口时,必须让Pandas知道要基于哪个日期列计算,要么把日期设为索引,要么用
on参数指定日期列,否则Pandas会把日期偏移量当成无效的整数窗口,抛出错误。
内容的提问来源于stack exchange,提问作者Jane Wayne
相关产品推荐
相关产品推荐

