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

如何对DataFrame按[D-2,D]日期范围聚合N列求和?

问题描述

现有包含D(日期)、N列的DataFrame如下:

DN
01/06/20212
01/06/20214
01/06/20210
02/06/20211
02/06/20210
03/06/20211
03/06/20215
03/06/20211
04/06/20212
05/06/20210
05/06/20212
05/06/20214
08/06/20217
09/06/20213
09/06/20219

需要计算每个日期对应的**过去3天(即[D-2, D]日期范围)**内N列的总和,预期结果如下:

DN
01/06/20216
02/06/20217
03/06/202114
04/06/202110
05/06/202115
08/06/20217
09/06/202119
解决方案

以下是两种高效实现需求的方法:

方法一:基于滚动窗口(填充缺失日期)

步骤1:转换日期格式并聚合每日总和

import pandas as pd

# 构造原始DataFrame(实际场景可替换为读取数据)
df = pd.DataFrame({
    'D': ['01/06/2021', '01/06/2021', '01/06/2021', '02/06/2021', '02/06/2021',
          '03/06/2021', '03/06/2021', '03/06/2021', '04/06/2021', '05/06/2021',
          '05/06/2021', '05/06/2021', '08/06/2021', '09/06/2021', '09/06/2021'],
    'N': [2,4,0,1,0,1,5,1,2,0,2,4,7,3,9]
})

# 转换日期列(格式为DD/MM/YYYY)
df['D'] = pd.to_datetime(df['D'], format='%d/%m/%Y')

# 聚合每日N的总和
daily_total = df.groupby('D')['N'].sum().reset_index()

步骤2:生成连续日期并计算滚动总和

# 生成覆盖数据范围的连续日期索引
date_range = pd.date_range(start=daily_total['D'].min(), end=daily_total['D'].max(), freq='D')
# 填充缺失日期的N值为0
daily_full = daily_total.set_index('D').reindex(date_range, fill_value=0).reset_index().rename(columns={'index':'D'})

# 计算3天滚动总和(窗口包含当前日期及前2天)
daily_full['rolling_sum'] = daily_full['N'].rolling(window=3, closed='both').sum()

# 筛选原始存在的日期,得到最终结果
result = daily_full[daily_full['D'].isin(df['D'].unique())][['D', 'rolling_sum']].rename(columns={'rolling_sum':'N'})
# 还原日期格式
result['D'] = result['D'].dt.strftime('%d/%m/%Y')

方法二:基于时间范围匹配(无需填充缺失日期)

直接通过merge_asof匹配每个日期的前2天范围,计算总和:

import pandas as pd

# 构造并预处理数据(同方法一)
df = pd.DataFrame({
    'D': ['01/06/2021', '01/06/2021', '01/06/2021', '02/06/2021', '02/06/2021',
          '03/06/2021', '03/06/2021', '03/06/2021', '04/06/2021', '05/06/2021',
          '05/06/2021', '05/06/2021', '08/06/2021', '09/06/2021', '09/06/2021'],
    'N': [2,4,0,1,0,1,5,1,2,0,2,4,7,3,9]
})
df['D'] = pd.to_datetime(df['D'], format='%d/%m/%Y')
daily_total = df.groupby('D')['N'].sum().reset_index()

# 计算每个日期的起始范围(D-2)
daily_total['D_start'] = daily_total['D'] - pd.Timedelta(days=2)
daily_total_sorted = daily_total.sort_values('D')

# 按时间范围匹配并求和
result = pd.merge_asof(
    daily_total_sorted,
    daily_total_sorted[['D', 'N']].rename(columns={'D':'match_D', 'N':'match_N'}),
    left_on='D',
    right_on='match_D',
    direction='backward',
    tolerance=pd.Timedelta(days=2)
).groupby('D')['match_N'].sum().reset_index().rename(columns={'match_N':'N'})

# 还原日期格式
result['D'] = result['D'].dt.strftime('%d/%m/%Y')

两种方法最终输出均与预期结果一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 19:10:52