You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在多索引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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 00:54:31