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

为何Pandas Grouper分组边界与预期不符?用法解析

按4个月分箱分组DateTime索引Series的问题解析与解决

问题背景

给定带DateTime索引的Series,尝试按4个月分箱分组并获取每组最大值的索引,代码如下:

import pandas as pd
import numpy as np

# 创建带日期时间索引的示例Series
index = pd.date_range('2015-01-01', '2015-12-31', freq='B')
random_numbers = np.random.randint(1, 10, size=len(index))
s = pd.Series(random_numbers, index=index)

# 按4个月频率分组并查找最大值的索引
result = s.groupby(pd.Grouper(freq='4M')).idxmax()

print("Grouped Indexes:")
print(result)

实际输出的分组索引为:

Grouped Indexes:
2015-01-31   2015-01-07
2015-05-31   2015-02-11
2015-09-30   2015-06-04
2016-01-31   2015-10-13
Freq: 4M, dtype: datetime64[ns]

预期的分组索引应为起始日:2015-01-01、2015-05-01、2015-09-01,共3个分组,需解析输出差异并修正。

原因解析

  • 4M频率的默认行为:Pandas中M代表月末频率,4M会将每个4个月周期的最后一天作为分组标签。同时,为了覆盖所有数据,分组范围会自动延伸至下一个周期月末——原数据截止到2015-12-31,因此最后一个分组会延伸到2016-01-31,导致出现第4个分组。
  • 分组范围偏差:4M的分组逻辑是从当前月末倒推4个月,而非从起始日顺推,因此分组范围和预期的「月初起始、每4个月一组」不符。

解决方法

方案1:使用月初起始的4个月频率(推荐)

改用4MS频率(MS代表月初频率),直接生成以月初为标签的分组,完全匹配预期逻辑:

result = s.groupby(pd.Grouper(freq='4MS')).idxmax()

输出结果:

2015-01-01   2015-01-07
2015-05-01   2015-06-04
2015-09-01   2015-10-13
Freq: 4MS, dtype: datetime64[ns]

对应的分组范围为:

  • 2015-01-01 至 2015-04-30
  • 2015-05-01 至 2015-08-31
  • 2015-09-01 至 2015-12-31

方案2:手动调整分组标签

如果需要保留4M分组逻辑,可将月末标签转换为对应周期的起始月初,并过滤超出原数据范围的分组:

result = s.groupby(pd.Grouper(freq='4M')).idxmax()
# 将月末索引转为当月第一天
result.index = result.index - pd.offsets.MonthBegin(1)
# 过滤掉超出原数据时间范围的分组
result = result[result.index <= s.index.max()]

执行后同样会得到以2015-01-01、2015-05-01、2015-09-01为索引的结果。

内容的提问来源于stack exchange,提问作者shadowbiscuit

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 15:07:27