如何在Pandas中为不同Player子集创建2日滚动均值列?
解决Pandas按Player分组计算2日滚动均值的问题
问题描述
我有如下结构的Pandas DataFrame:
| PLAYER | DATE | SCORE | GAME |
|---|---|---|---|
| Albert | 2020-08-12 | 10 | X |
| Barney | 2020-08-12 | 100 | X |
| Charlie | 2020-08-12 | 1000 | X |
| Albert | 2020-08-13 | 20 | X |
| Barney | 2020-08-13 | 200 | X |
| Charlie | 2020-08-13 | 2000 | X |
| Albert | 2020-08-14 | 30 | Y |
| Barney | 2020-08-14 | 300 | Y |
| Charlie | 2020-08-14 | 3000 | Y |
| Albert | 2020-08-15 | 40 | Y |
| Barney | 2020-08-15 | 400 | Y |
| Charlie | 2020-08-15 | 4000 | Y |
| Albert | 2020-08-16 | 50 | Z |
| Barney | 2020-08-16 | 500 | Z |
| Charlie | 2020-08-16 | 5000 | Z |
| Albert | 2020-08-17 | 60 | Z |
| Barney | 2020-08-17 | 600 | Z |
| Charlie | 2020-08-17 | 6000 | Z |
我想要为每个Player子集创建一个新的2日得分均值列,预期结果如下:
| PLAYER | DATE | SCORE | GAME | 2-DAY AVG |
|---|---|---|---|---|
| Albert | 2020-08-12 | 10 | X | NaN |
| Barney | 2020-08-12 | 100 | X | NaN |
| Charlie | 2020-08-12 | 1000 | X | NaN |
| Albert | 2020-08-13 | 20 | X | 15 |
| Barney | 2020-08-13 | 200 | X | 150 |
| Charlie | 2020-08-13 | 2000 | X | 1500 |
| Albert | 2020-08-14 | 30 | Y | 25 |
| Barney | 2020-08-14 | 300 | Y | 250 |
| Charlie | 2020-08-14 | 3000 | Y | 2500 |
| Albert | 2020-08-15 | 40 | Y | 35 |
| Barney | 2020-08-15 | 400 | Y | 350 |
| Charlie | 2020-08-15 | 4000 | Y | 3500 |
| Albert | 2020-08-16 | 50 | Z | 45 |
| Barney | 2020-08-16 | 500 | Z | 450 |
| Charlie | 2020-08-16 | 5000 | Z | 4500 |
| Albert | 2020-08-17 | 60 | Z | 55 |
| Barney | 2020-08-17 | 600 | Z | 550 |
| Charlie | 2020-08-17 | 6000 | Z | 5500 |
我已尝试过groupby()结合rolling.mean(2)函数以及Python条件语句的多种组合,但均未成功。请问在Pandas中有什么巧妙的实现方法吗?
解决方案
其实核心就是按PLAYER分组后,对SCORE列应用窗口大小为2的滚动均值,只要注意几个细节就能搞定:
- 先把DATE列转为datetime类型,确保时间排序逻辑正确(哪怕你的数据已经排好序,这也是个好习惯)
- 滚动计算时设置
min_periods=2,保证只有当窗口内有至少2条数据时才返回均值,否则返回NaN,正好对应第一行的预期结果
下面是完整的可运行代码:
import pandas as pd # 构造原始数据 data = { 'PLAYER': ['Albert', 'Barney', 'Charlie']*6, 'DATE': ['2020-08-12', '2020-08-12', '2020-08-12', '2020-08-13', '2020-08-13', '2020-08-13', '2020-08-14', '2020-08-14', '2020-08-14', '2020-08-15', '2020-08-15', '2020-08-15', '2020-08-16', '2020-08-16', '2020-08-16', '2020-08-17', '2020-08-17', '2020-08-17'], 'SCORE': [10, 100, 1000, 20, 200, 2000, 30, 300, 3000, 40, 400, 4000, 50, 500, 5000, 60, 600, 6000], 'GAME': ['X','X','X','X','X','X','Y','Y','Y','Y','Y','Y','Z','Z','Z','Z','Z','Z'] } df = pd.DataFrame(data) # 1. 转换DATE列为datetime类型 df['DATE'] = pd.to_datetime(df['DATE']) # 2. 按玩家分组计算滚动2期均值 df['2-DAY AVG'] = df.groupby('PLAYER')['SCORE'].rolling(window=2, min_periods=2).mean().reset_index(level=0, drop=True) # 输出结果 print(df)
关键细节解释
groupby('PLAYER'):确保每个玩家的计算独立进行,不会和其他玩家的数据混在一起rolling(window=2, min_periods=2):窗口大小设为2,min_periods=2要求窗口内必须有2条数据才计算均值,否则返回NaNreset_index(level=0, drop=True):分组后的滚动结果会带有分组索引,这一步是去掉分组索引,让计算结果能和原DataFrame完美对齐
运行这段代码后,你就能得到和预期完全一致的结果啦!之前尝试失败大概率是没处理好分组后的索引对齐,或者没设置min_periods导致第一行没有返回NaN。
内容的提问来源于stack exchange,提问作者Zoivermey
相关产品推荐
相关产品推荐

