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

求助:基于每日数据计算连续滚动季度累积值的实现方案

问题:基于每日DataFrame计算连续滚动季度(3个月)累积PP值

原始DataFrame

DATE   PP
0     1964-01-01  1.0
1     1964-01-02  0.0
2     1964-01-03  0.0
3     1964-01-04  0.0
4     1964-01-05  0.0
         ...  ...
21788 2023-03-18  NaN
21789 2023-03-19  NaN
21790 2023-03-20  NaN
21791 2023-03-21  NaN
21792 2023-03-22  NaN

预期结果

cum_start   cum_end          PP
1964-12     1965-02          25
1965-01     1965-03          30
1965-02     1965-04          12
1965-03     1965-05          11
1965-04     1965-06          25
         ...  ...
2022-9      2022-11          14
2022-10     2022-12          22
2022-11     2023-01          15
2022-12     2023-02          21
2023-01     2023-03          40

尝试的问题代码

trimestres = df.set_index('DATE').rolling('90D')['PP'].sum()
trimestres = trimestres.groupby([trimestres.index.year, trimestres.index.quarter]).tail(3)
trimestres = trimestres.reset_index().rename(columns={'DATE': 'cum_start'})
trimestres['cum_end'] = trimestres['cum_start'] + pd.DateOffset(months=3)

问题分析

原代码存在三个核心问题:

  1. 窗口范围不准确:rolling('90D')按固定90天计算,无法匹配自然月的3个月周期(不同月份天数不同,3个月可能是90-93天),导致累积区间不符合预期的连续3个日历月。
  2. 分组逻辑错误:groupby([year, quarter]).tail(3)是提取每个季度的最后3天数据,和预期的「每个月作为起始的滚动3个月累积」完全不符。
  3. 结束日期计算错误:直接给cum_start加3个月会得到起始日期+3个月的当天(如1964-12-01加3个月是1965-03-01),但预期的cum_end是3个月周期的最后一个月(1965-02)。

解决方案

以下代码严格按照「每个月起始,计算连续3个日历月的PP总和」逻辑实现,完全匹配预期格式:

步骤1:数据预处理

import pandas as pd

# 转换DATE列为datetime类型并设为索引
df['DATE'] = pd.to_datetime(df['DATE'])
df = df.set_index('DATE')

# 处理缺失值:将NaN填充为0(根据业务需求调整,若缺失值无需计入则可跳过此步)
df['PP'] = df['PP'].fillna(0)

步骤2:生成滚动窗口并计算累积值

# 生成所有有效起始月份(月初):从数据最早月份到最晚月份往前推2个月
start_months = pd.date_range(
    start=df.index.min().floor('M'),  # 取最早日期所在月的第一天
    end=df.index.max().floor('M') - pd.DateOffset(months=2),  # 最晚可起始月份(保证有3个月数据)
    freq='MS'  # 按月初频率生成
)

# 遍历每个起始月份,计算对应3个月周期的PP总和
result_list = []
for start in start_months:
    # 计算周期结束日期:起始月份+3个月的前一天(即第三个月的最后一天)
    end_date = start + pd.DateOffset(months=3) - pd.Timedelta(days=1)
    # 计算该周期内的PP总和
    pp_total = df.loc[start:end_date, 'PP'].sum()
    # 格式化为年月字符串(如1964-12)
    cum_start = start.strftime('%Y-%m')
    cum_end = end_date.strftime('%Y-%m')
    # 添加到结果列表
    result_list.append({'cum_start': cum_start, 'cum_end': cum_end, 'PP': pp_total})

# 转换为DataFrame
result_df = pd.DataFrame(result_list)

说明

  • 此方法严格基于自然日历月生成滚动窗口,确保每个窗口是连续3个完整月份(如1964-12至1965-02包含12月、1月、2月所有日期)。
  • 自动过滤无法形成完整3个月窗口的起始月份(如数据最后一个月无法作为起始,因为没有后续2个月的数据)。
  • 结果格式完全匹配预期的cum_start(起始年月)、cum_end(结束年月)、PP(累积值)结构。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 14:30:00