Pandas Grouper日期值异常:分组后为何返回原数据不存在的日期?
解决Pandas时间序列分组:获取每月实际存在的最晚日期及对应值
这是个很常见的Pandas时间序列分组误区,我来帮你拆解清楚问题所在和对应的解决办法~
为什么groupby(pd.Grouper(freq='M')).last()会返回月末日期?
你观察到的现象其实是pd.Grouper(freq='M')的设计逻辑导致的:
- 当你用
freq='M'作为分组依据时,Pandas会自动将所有时间戳归组到当月的最后一个日历日(比如4月的所有数据都会被分到2017-04-30这个组标签下),不管你的原始数据里有没有这个日期。 last()方法确实会取每组内原始数据的最后一条记录的值,但分组后的结果索引会被替换成预设的组标签(也就是月末日期),并不是Pandas把4月28日的值“映射”到了4月30日,只是索引被替换成了分组的标准标签而已。
为什么groupby(pd.Grouper(freq='M')).max()不符合需求?
max()方法是对每一列分别取最大值:
- 对日期列(或索引),它会取组内的最大日期;但对
CumReturn列,它会取组内的最大值。 - 这就导致结果可能是组内
CumReturn最大的那行,而不是日期最晚的那行(比如你4月的数据里,4/4的CumReturn是100,是最大值,所以max()会返回这行,和你要的“最晚日期”需求不匹配)。
正确的解决方法:保留原始的最晚日期
要获取每月实际存在数据的最晚日期及对应值,我们可以换一种分组方式,直接按月份周期分组,而不是按月末日历日分组:
import pandas as pd # 读取并预处理数据(注意要正确设置索引) df = pd.read_clipboard(parse_dates=['Date']) df = df.set_index('Date') # 这里必须赋值,否则索引不会修改 # 按月份周期分组,取每组的最后一行(保留原始日期) result = df.groupby(df.index.to_period('M')).apply(lambda x: x.iloc[-1])
运行后你会得到符合预期的结果:
| Date | CumReturn |
|---|---|
| 2017-03-31 | 1.000 |
| 2017-04-28 | 1.012 |
| 2017-05-31 | 1.022 |
| 2017-06-30 | 1.033 |
方法原理:
df.index.to_period('M')会把每个时间戳转换成对应的月份周期(比如2017-04),这样分组的依据是“月份”而非“月末日期”。apply(lambda x: x.iloc[-1])直接取每组内的最后一条记录,保留了原始数据的日期索引和对应的值,完全符合你的需求。
内容的提问来源于stack exchange,提问作者Evan
相关产品推荐
相关产品推荐

