如何对DataFrame按[D-2,D]日期范围聚合N列求和?
问题描述
现有包含D(日期)、N列的DataFrame如下:
| D | N |
|---|---|
| 01/06/2021 | 2 |
| 01/06/2021 | 4 |
| 01/06/2021 | 0 |
| 02/06/2021 | 1 |
| 02/06/2021 | 0 |
| 03/06/2021 | 1 |
| 03/06/2021 | 5 |
| 03/06/2021 | 1 |
| 04/06/2021 | 2 |
| 05/06/2021 | 0 |
| 05/06/2021 | 2 |
| 05/06/2021 | 4 |
| 08/06/2021 | 7 |
| 09/06/2021 | 3 |
| 09/06/2021 | 9 |
需要计算每个日期对应的**过去3天(即[D-2, D]日期范围)**内N列的总和,预期结果如下:
| D | N |
|---|---|
| 01/06/2021 | 6 |
| 02/06/2021 | 7 |
| 03/06/2021 | 14 |
| 04/06/2021 | 10 |
| 05/06/2021 | 15 |
| 08/06/2021 | 7 |
| 09/06/2021 | 19 |
解决方案
以下是两种高效实现需求的方法:
方法一:基于滚动窗口(填充缺失日期)
步骤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
相关产品推荐
相关产品推荐

