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

Pandas resample异常:Datetime Index分组求和结果不符合预期

Pandas resample半月分组分箱错误的解决方法

原始DataFrame:

Column1
2022-08-03 08:48:34    9217.02
2022-08-17 17:14:39    6229.27
2022-08-31 17:17:00    6229.27
2022-09-14 18:12:14    5939.54
2022-09-30 17:51:48    6229.27
2022-10-14 15:26:14    5939.54
2022-10-31 16:29:14    5939.54
2022-11-15 18:10:27    5939.54
2022-11-30 18:10:23    5939.54
2022-12-19 10:53:21    5939.54
2022-12-20 16:26:08    2440.98
2022-12-30 18:30:25    6302.54
2023-01-13 19:24:22    6262.74
2023-01-31 16:51:44    6262.74

期望按每月1日至15日、16日至月末分组求和,输出如下:

Column1
          2022-08-15     9217.02
          2022-08-31    12458.54
          2022-09-15     5939.54
          2022-09-30     6229.27
          2022-10-15     5939.54
          2022-10-31     5939.54
          2022-11-15     5939.54
          2022-11-30     5939.54
          2022-12-15        0.0   
          2022-12-31    14683.06 
          2023-01-15     6262.74
          2023-01-31     6262.74

问题原因

直接调用df.resample('SM').sum()出现分箱错误,核心原因是pandas默认的SM(半月频率)分组逻辑:

  • 默认以每月15日和月末为锚点,标签取区间左边界
  • 分组区间为「上月末至本月15日」「本月15日至本月末」,和需求的「1-15日」「16-月末」不匹配

使用label='right'虽能修正标签,但会生成超出数据范围的分组(如2023-02-15),不符合预期。

解决方案

方法一:自定义分组键(直观易控)

通过判断日期的日数,手动生成对应分组标签,再按标签求和:

import pandas as pd

# 遍历索引日期,生成分组键
group_keys = []
for date in df.index.date:
    if date.day <= 15:
        # 1-15日的分组标签为当月15日
        group_key = date.replace(day=15)
    else:
        # 16-月末的分组标签为当月最后一天
        # 计算当月最后一天的通用方法
        next_month = date.replace(day=28) + pd.Timedelta(days=4)
        group_key = next_month - pd.Timedelta(days=next_month.day)
    group_keys.append(pd.to_datetime(group_key))

# 按分组键求和
result = df.groupby(group_keys).sum()

# 生成所有需要的日期区间,补全缺失分组并填充0
min_month = df.index.min().to_period('M')
max_month = df.index.max().to_period('M')
all_dates = []
for period in pd.period_range(min_month, max_month):
    all_dates.append(period.start_time.replace(day=15))
    all_dates.append(period.end_time)

result = result.reindex(all_dates, fill_value=0)

方法二:调整resample参数

通过修改resample的label、closed、loffset参数,匹配需求区间:

# 调整resample参数,让区间和标签匹配需求
result = df.resample('SM', label='right', closed='right', loffset='1D').sum()

# 过滤超出数据范围的分组
max_end_date = df.index.max().to_period('M').end_time
result = result.loc[:max_end_date]

# 补全缺失日期并填充0
min_start_date = df.index.min().replace(day=15)
all_dates = pd.date_range(start=min_start_date, end=max_end_date, freq='SM')
result = result.reindex(all_dates, fill_value=0)

参数说明:

  • label='right':标签取区间右边界(即15日或月末)
  • closed='right':区间为左开右闭,确保15日当天数据归入1-15日分组
  • loffset='1D':修正默认锚点,避免将上月末至本月15日作为一个区间

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 17:35:00