如何用Pandas按课程与连续日期范围分组DataFrame?
Pandas按课程分组合并连续日期范围的解决方案
原始数据
start end value course 0 2022-01-01 2022-01-01 10 first 1 2022-01-02 2022-01-02 20 first 2 2022-01-05 2022-01-05 30 second 3 2022-01-04 2022-01-04 40 second 4 2022-01-08 2022-01-08 21 first 5 2022-01-09 2022-01-09 92 first 6 2022-01-10 2022-01-10 55 first
期望输出
start end value course 0 2022-01-01 2022-01-02 10 first 1 2022-01-04 2022-01-05 30 second 2 2022-01-08 2022-01-10 21 first
核心需求
- 先按
course字段分组 - 合并每组内的连续日期区间
- 无法使用
pd.Grouper(无固定日期频率),需保留每组连续区间第一条的start和value值
实现代码
import pandas as pd # 构造原始DataFrame(已有数据可跳过此步) df = pd.DataFrame({ 'start': ['2022-01-01', '2022-01-02', '2022-01-05', '2022-01-04', '2022-01-08', '2022-01-09', '2022-01-10'], 'end': ['2022-01-01', '2022-01-02', '2022-01-05', '2022-01-04', '2022-01-08', '2022-01-09', '2022-01-10'], 'value': [10, 20, 30, 40, 21, 92, 55], 'course': ['first', 'first', 'second', 'second', 'first', 'first', 'first'] }) # 转换日期列为datetime类型,这是后续计算的基础 df['start'] = pd.to_datetime(df['start']) df['end'] = pd.to_datetime(df['end']) # 按课程分组后对日期排序,确保同一课程下的日期是有序的 df_sorted = df.sort_values(['course', 'start']) # 给每组内的连续日期段标记唯一ID # 逻辑:如果当前行日期与前一行间隔超过1天,就标记为新的分组 df_sorted['group_id'] = ( df_sorted.groupby('course')['start'] .diff().dt.days.fillna(0) .gt(1) .cumsum() ) # 聚合得到最终结果 result = df_sorted.groupby(['course', 'group_id']).agg( start=('start', 'first'), # 取连续段的第一个start end=('end', 'last'), # 取连续段的最后一个end value=('value', 'first') # 取连续段的第一个value ).reset_index(drop=True).reindex(columns=['start', 'end', 'value', 'course']) print(result)
代码说明
- 日期类型转换:将字符串格式的日期转为
datetime类型,才能进行日期差值的计算 - 排序处理:按
course和start排序,保证同一课程下的日期按时间顺序排列,确保后续连续日期的判断逻辑有效 - 标记连续组:通过
groupby+diff计算每行与前一行的日期差,若间隔超过1天则标记为新组,再用cumsum生成连续段的唯一ID - 聚合合并:按
course和group_id分组,提取连续段的首尾日期和第一个value,最后调整列顺序得到目标格式
内容的提问来源于stack exchange,提问作者CantusLupus
相关产品推荐
相关产品推荐

