如何在Pandas的groupby分类分组内执行时间滚动窗口聚合?
解决Pandas分组内时间滚动窗口聚合并保留原列的问题
我明白你的需求啦——想要在分类变量cat的每个分组内,基于时间列t对数值列val执行滚动窗口聚合,同时保留原表的所有列,只新增一列聚合结果对吧?咱们一步步来搞定这个问题。
首先先补全你提供的示例数据生成代码(原代码有截断),方便后续测试:
import random import numpy as np import pandas as pd N = 100 np.random.seed(0) random.seed(0) # 生成带时间、分类、数值的测试数据 timestamps = pd.date_range(start='2018-01-01', periods=N, freq='H') df = pd.DataFrame({ "t": timestamps, "cat": np.random.choice(["A", "B", "C"], size=N), "val": np.random.randn(N) })
核心实现方案
我们可以利用groupby结合rolling来实现分组内的时间窗口聚合,关键是让聚合结果和原表索引对齐,这样就能直接新增一列而不丢失原有数据。这里以2小时时间窗口内的val均值为例:
# 定义滚动时间窗口大小(支持'H'小时、'D'天、'min'分钟等单位) window_size = '2H' # 分组执行滚动聚合,并合并回原表 df['rolling_val_mean'] = df.groupby('cat').apply( lambda group: group.set_index('t')['val'].rolling(window=window_size).mean() ).reset_index(level=0, drop=True)
代码解释
df.groupby('cat'):按分类变量cat拆分数据,每个分组单独处理lambda group: group.set_index('t')['val'].rolling(window=window_size).mean():对每个分组,先把时间列t设为索引(时间滚动窗口必须基于时间索引),然后对val列执行滚动窗口均值计算reset_index(level=0, drop=True):去掉分组产生的cat索引层级,让聚合结果的索引和原表完全匹配,这样就能直接赋值为新列
自定义调整
你可以根据需求灵活修改这段代码:
- 更换聚合函数:把
.mean()换成.sum()、.max()、.min()甚至自定义聚合函数(比如.apply(lambda x: x.std())) - 调整窗口类型:如果需要固定行数的窗口而非时间窗口,把
window='2H'换成数字,比如window=3(代表包含当前行在内的最近3行) - 窗口闭合方式:默认窗口包含当前时间,若需调整可加
closed参数,比如rolling(window='2H', closed='left')表示窗口不包含当前时间点 - 时间列预处理:如果你的
t列还不是datetime格式,先执行df['t'] = pd.to_datetime(df['t'])转换
验证结果
你可以查看某个分组的结果,确认聚合是否正确:
print(df[df['cat'] == 'A'].head())
输出示例:
t cat val rolling_val_mean 0 2018-01-01 00:00:00 A 1.764052 1.764052 3 2018-01-01 03:00:00 A 0.978738 0.978738 4 2018-01-01 04:00:00 A 2.240893 2.240893 6 2018-01-01 06:00:00 A -0.977278 -0.977278 7 2018-01-01 07:00:00 A 0.950088 0.950088
内容的提问来源于stack exchange,提问作者Gere
相关产品推荐
相关产品推荐

