You need to enable JavaScript to run this app. pandas.resample/groupby实现每月10/20/月末为节点的自定义时间间隔聚合
优惠活动
大模型
产品
解决方案
定价
更多

pandas.resample/groupby实现每月10/20/月末为节点的自定义时间间隔聚合

实现方案

核心思路

通过自定义规则把每条数据映射到所属区间的结束日期,再按结束日期分组聚合即可,完美适配每月10/20/月末三个节点的区间规则,不会出现月初日期漏算的问题。

完整代码实现

import pandas as pd
import numpy as np
from pandas.tseries.offsets import MonthEnd

# 定义区间结束日期映射函数
def get_period_end(date):
    day = date.day
    year, month = date.year, date.month
    if day <= 10:
        return pd.Timestamp(year=year, month=month, day=10)
    elif 11 <= day <= 20:
        return pd.Timestamp(year=year, month=month, day=20)
    else:
        # 大于20号则取当月最后一天
        return pd.Timestamp(year=year, month=month, day=1) + MonthEnd(1)

# ========== 测试用例1:初始样例数据 ==========
d = {'price': [10, 12, 8, 12, 14, 18, 10, 20],
     'volume': [50, 60, 40, 100, 50, 100, 40, 50]}
df = pd.DataFrame(d)
df['a_date'] = pd.date_range('01/01/2018', periods=8, freq='W')

# 映射区间结束日期、分组求和、修改索引名匹配预期输出
df['period_end'] = df['a_date'].apply(get_period_end)
result = df.groupby('period_end')[['price', 'volume']].sum().rename_axis('a_date')
print("样例1输出:")
print(result)

# ========== 测试用例2:包含月初第一天的20天数据 ==========
d2 = {'price': np.arange(20)+1,
      'volume': np.arange(20)+5}
df2 = pd.DataFrame(d2)
df2['a_date'] = pd.date_range('01/01/2018', periods=20, freq='D')
df2['period_end'] = df2['a_date'].apply(get_period_end)
result2 = df2.groupby('period_end')[['price', 'volume']].sum().rename_axis('a_date')
print("\n样例2输出:")
print(result2)

输出验证

样例1输出完全匹配预期:

price  volume
a_date                   
2018-01-10     10      50
2018-01-20     12      60
2018-01-31     20     140
2018-02-10     14      50
2018-02-20     28     140
2018-02-28     20      50

样例2输出符合正确计算结果,无月初日期漏算:

price  volume
a_date                   
2018-01-10     55      95
2018-01-20    155     195

可选扩展:补全空区间

如果需要展示所有区间(包括无数据的区间),可以先生成全量的区间结束日期,再对结果重索引:

# 生成时间范围内所有不重复的区间结束日期
start = df['a_date'].min().replace(day=1)
end = df['a_date'].max() + MonthEnd(1)
all_dates = pd.date_range(start=start, end=end, freq='D')
all_periods = sorted(list(set([get_period_end(d) for d in all_dates])))
# 重索引补全空值,无数据的区间填充0
result = result.reindex(all_periods, fill_value=0).rename_axis('a_date')

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.11 07:18:03