按ID分组、以周日至周四为周期的周度金额求和及多周累计实现
问题:按自定义周(周日-周四)分组计算金额衍生列
需求说明
需对每个ID分组,以周日至周四为完整周进行金额的周度求和,并生成以下衍生列:
- OneWeekAmount:该日期所属周的金额总和(注:2021-08-03、04为周二、周三,属于同一周;2021-08-06、07为周五、周六,不计入该周求和)
- TwoWeekAmount = 当前周金额总和 + 上一周金额总和
- ThreeWeekAmount = 当前周金额总和 + 前两周金额总和
输入DataFrame
| ID | Date | Amount |
|---|---|---|
| A | 2021-08-03 | 100 |
| A | 2021-08-04 | 100 |
| A | 2021-08-06 | 20 |
| A | 2021-08-07 | 100 |
| A | 2021-08-09 | 300 |
| A | 2021-08-11 | 100 |
| A | 2021-08-12 | 100 |
| A | 2021-08-13 | 10 |
| A | 2021-08-23 | 10 |
| A | 2021-08-24 | 10 |
| A | 2021-08-26 | 10 |
| A | 2021-08-28 | 10 |
期望输出DataFrame
| ID | Date | Amount | OneWeekAmount | TwoWeekAmount | ThreeWeekAmount |
|---|---|---|---|---|---|
| A | 2021-08-03 | 100 | 200 | 200 | 200 |
| A | 2021-08-04 | 100 | 200 | 200 | 200 |
| A | 2021-08-06 | 20 | 200 | 200 | 200 |
| A | 2021-08-07 | 100 | 200 | 200 | 200 |
| A | 2021-08-09 | 300 | 500 | 700 | 700 |
| A | 2021-08-11 | 100 | 500 | 700 | 700 |
| A | 2021-08-12 | 100 | 500 | 700 | 700 |
| A | 2021-08-13 | 10 | 500 | 700 | 700 |
| A | 2021-08-23 | 10 | 30 | 30 | 530 |
| A | 2021-08-24 | 10 | 30 | 30 | 530 |
| A | 2021-08-26 | 10 | 30 | 30 | 530 |
| A | 2021-08-28 | 10 | 30 | 30 | 530 |
解决方案
以下是基于Pandas的实现代码,核心逻辑是先自定义周分组规则,再计算周度金额,最后关联回原表生成衍生列:
import pandas as pd # 构造输入数据 df = pd.DataFrame({ 'ID': ['A']*12, 'Date': ['2021-08-03', '2021-08-04', '2021-08-06', '2021-08-07', '2021-08-09', '2021-08-11', '2021-08-12', '2021-08-13', '2021-08-23', '2021-08-24', '2021-08-26', '2021-08-28'], 'Amount': [100, 100, 20, 100, 300, 100, 100, 10, 10, 10, 10, 10] }) # 转换日期格式 df['Date'] = pd.to_datetime(df['Date']) # 自定义周分组:周日至周四为一周,周五/周六归属前一周 # 计算每个日期对应的周起始日(周日) df['week_start'] = df['Date'] - pd.to_timedelta(df['Date'].dt.weekday, unit='D') + pd.Timedelta(days=6) # 标记周五(4)、周六(5),将其周起始日调整为上一周周日 mask = df['Date'].dt.weekday.isin([4,5]) df.loc[mask, 'week_start'] = df.loc[mask, 'week_start'] - pd.Timedelta(weeks=1) # 按ID和周起始日分组计算周度金额总和 weekly_sum = df.groupby(['ID', 'week_start'])['Amount'].sum().reset_index(name='OneWeekAmount') # 计算上一周、前两周的金额,无数据则填充0 weekly_sum['prev_week'] = weekly_sum.groupby('ID')['OneWeekAmount'].shift(1).fillna(0) weekly_sum['prev_two_week'] = weekly_sum.groupby('ID')['OneWeekAmount'].shift(2).fillna(0) # 生成衍生列 weekly_sum['TwoWeekAmount'] = weekly_sum['OneWeekAmount'] + weekly_sum['prev_week'] weekly_sum['ThreeWeekAmount'] = weekly_sum['OneWeekAmount'] + weekly_sum['prev_two_week'] # 关联周度数据回原表,整理输出格式 result = df.merge(weekly_sum, on=['ID', 'week_start'], how='left') result = result[['ID', 'Date', 'Amount', 'OneWeekAmount', 'TwoWeekAmount', 'ThreeWeekAmount']].sort_values(['ID', 'Date']) print(result)
代码逻辑说明:
- 日期格式转换:确保
Date列是datetime类型,方便后续日期运算; - 自定义周规则:以周日作为周起始日,周五、周六的日期归属到上一周;
- 周度求和:按ID和周起始日分组,计算每个周的金额总和;
- 衍生列计算:用
shift函数获取历史周的金额,叠加得到TwoWeekAmount和ThreeWeekAmount; - 结果合并:将周度统计数据关联回原表,保留指定列并排序。
内容的提问来源于stack exchange,提问作者Rahi007
相关产品推荐
相关产品推荐

