Pandas按日分组(非连续日期)出现分组错误问题排查
解决Pandas按DatetimeIndex分组时生成空分组的问题
问题背景
你有一个以DatetimeIndex为索引的DataFrame,尝试按日(freq="D")分组时,Pandas会自动填充首尾日期之间的所有日期,生成大量空分组,导致自定义聚合函数因访问空分组的索引而抛出IndexError。而按月/年分组看似正常,只是因为你的数据刚好覆盖了连续的月份/年份,没有空区间。
解决方案
要实现仅基于实际存在数据的频率区间分组,可以直接将索引按目标频率格式化后作为分组键,避免Pandas自动填充空区间。
1. 按任意频率分组(通用方法)
使用index.floor()方法将DatetimeIndex按目标频率向下取整,以此作为分组依据:
按日分组
import pandas as pd df = pd.DataFrame( data={"values": [10.0, 20.0, 10.0, 20.0]}, index=[pd.Timestamp("2023-01-02T01:00", tz="utc"), pd.Timestamp("2023-01-02T02:00", tz="utc"), pd.Timestamp("2023-02-03T01:00", tz="utc"), pd.Timestamp("2023-02-03T02:00", tz="utc"),], ) # 仅对存在数据的日期分组 groups = df.groupby(df.index.floor('D'))
按其他频率分组
- 按5日分组:
df.groupby(df.index.floor('5D')) - 按月(每月第一天)分组:
df.groupby(df.index.floor('MS')) - 按季度分组:
df.groupby(df.index.floor('QS'))
2. 运行自定义聚合函数
现在你的聚合函数可以正常执行,不会遇到空分组:
def f(group): d = {} d['new_col'] = str(group.index[0]) + "/" + str(group.index[-1]) return pd.Series(d) new_df = groups.apply(f)
最终结果
new_col 2023-01-02 00:00:00+00:00 2023-01-02 01:00:00+00:00/2023-01-02 02:00:00+00:00 2023-02-03 00:00:00+00:00 2023-02-03 01:00:00+00:00/2023-02-03 02:00:00+00:00
原理说明
使用pd.Grouper(freq="D")时,Pandas会生成从数据最早日期到最晚日期的所有连续日区间,即使区间内没有数据也会保留,这就是你得到33个分组的原因。而通过index.floor()生成分组键时,只会将属于同一频率区间的现有数据归为一组,完全不会创建空分组,从根源避免了索引越界问题。
内容的提问来源于stack exchange,提问作者Mo Kanj
相关产品推荐
相关产品推荐

