如何为DataFrame添加连续工作日序列长度统计列?
问题
现有一个包含Account(账户)和Date(日期)的DataFrame,需新增一列Length,统计每个账户下连续日期序列的长度(该连续日期段的总天数)。核心规则:
- 常规连续日期(如01/02和01/03)算同一段连续序列
- 周五到周一需视为连续日期(即跳过周末,周五和周一算作连续)
输入DataFrame
| Account | Date |
|---|---|
| A | 01/01/2023 |
| A | 01/02/2023 |
| A | 01/03/2023 |
| A | 01/05/2023 |
| B | 01/02/2023 |
| B | 01/03/2023 |
| B | 01/05/2023 |
| B | 01/06/2023 |
| C | 01/01/2023 |
| C | 01/02/2023 |
| C | 01/04/2023 |
| C | 01/05/2023 |
| D | 01/01/2023 |
| D | 01/05/2023 |
| D | 01/07/2023 |
| D | 01/08/2023 |
| D | 01/09/2023 |
| D | 01/10/2023 |
期望输出DataFrame
| Account | Date | Length |
|---|---|---|
| A | 01/01/2023 | 3 |
| A | 01/02/2023 | 3 |
| A | 01/03/2023 | 3 |
| A | 01/05/2023 | 1 |
| B | 01/02/2023 | 2 |
| B | 01/03/2023 | 2 |
| B | 01/05/2023 | 2 |
| B | 01/06/2023 | 2 |
| C | 01/01/2023 | 4 |
| C | 01/02/2023 | 4 |
| C | 01/04/2023 | 4 |
| C | 01/05/2023 | 4 |
| D | 01/01/2023 | 1 |
| D | 01/05/2023 | 1 |
| D | 01/07/2023 | 4 |
| D | 01/08/2023 | 4 |
| D | 01/09/2023 | 4 |
| D | 01/10/2023 | 4 |
解决方案
使用Pandas可以高效实现需求,核心是自定义连续日期的判断逻辑,步骤如下:
import pandas as pd # 构造输入DataFrame(若已有数据可跳过此步) data = { 'Account': ['A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'C', 'C', 'C', 'C', 'D', 'D', 'D', 'D', 'D', 'D'], 'Date': ['01/01/2023', '01/02/2023', '01/03/2023', '01/05/2023', '01/02/2023', '01/03/2023', '01/05/2023', '01/06/2023', '01/01/2023', '01/02/2023', '01/04/2023', '01/05/2023', '01/01/2023', '01/05/2023', '01/07/2023', '01/08/2023', '01/09/2023', '01/10/2023'] } df = pd.DataFrame(data) # 1. 转换日期格式并排序,确保每个账户内日期顺序正确 df['Date'] = pd.to_datetime(df['Date'], format='%m/%d/%Y') df = df.sort_values(['Account', 'Date']).reset_index(drop=True) # 2. 按账户分组,生成连续序列的分组ID def mark_continuous_groups(group): # 计算当前日期与前一日的天数差 day_diff = group['Date'].diff().dt.days # 判断是否连续:要么差1天,要么差3天且前一日是周五、当日是周一 is_continuous = (day_diff == 1) | ((day_diff == 3) & (group['Date'].shift(1).dt.weekday == 4) & (group['Date'].dt.weekday == 0)) # 非连续时分组ID累加,将连续日期归为同一组 group['group_id'] = (~is_continuous).cumsum() return group df = df.groupby('Account').apply(mark_continuous_groups).reset_index(drop=True) # 3. 统计每个分组的长度,合并回原表 group_lengths = df.groupby(['Account', 'group_id']).size().reset_index(name='Length') df = df.merge(group_lengths, on=['Account', 'group_id']).drop('group_id', axis=1) # 可选:恢复日期为原字符串格式 df['Date'] = df['Date'].dt.strftime('%m/%d/%Y') print(df)
关键逻辑说明
- 日期转换与排序:先将日期转为datetime类型,确保后续差值计算准确,同时按账户和日期排序,避免因乱序导致分组错误
- 连续判断规则:除了常规的1天差值,针对周五(weekday=4)到周一(weekday=0)的3天差值也判定为连续,符合需求
- 分组与长度统计:通过
cumsum()生成分组ID,将同一连续序列的日期归为一组,最后统计每组的长度并映射回原数据
内容的提问来源于stack exchange,提问作者BrianTheMoose
相关产品推荐
相关产品推荐

