Pandas相同id分组下合并带NaT的连续日期且特征值一致的行
解决方案
核心思路:通过给同ID、同特征的连续日期打分组标签,再聚合得到合并结果,兼容End列NaT场景。
首先给出完整可运行代码:
import pandas as pd import numpy as np # 构造测试数据,你可以替换成自己的数据集读取逻辑 df = pd.DataFrame({ 'Id': ['A', 'A', 'A', 'A', 'B', 'B'], 'Start': pd.to_datetime(['2020-01-01', '2020-01-16', '2020-01-31', '2020-07-01', '2020-01-31', '2020-02-16']), 'End': pd.to_datetime(['2020-01-15', '2020-01-30', '2020-02-15', '2020-07-15', '2020-02-15', pd.NaT]), 'Feature1': [1, 1, 0, 0, 0, 0], 'Feature2': [1, 1, 1, 1, 0, 0] }) # 1. 先按Id、特征列、Start排序,保证日期顺序正确 df_sorted = df.sort_values(by=['Id', 'Feature1', 'Feature2', 'Start']).reset_index(drop=True) # 2. 标记新分组:同ID同特征下,当前行和上一行日期不连续就算新分组 # 连续判断规则:上一行的End +1天 == 当前行的Start df_sorted['is_new_group'] = df_sorted.groupby(['Id', 'Feature1', 'Feature2']).apply( lambda x: ~(x['End'].shift(1) + pd.Timedelta(days=1) == x['Start']) ).reset_index(drop=True) # 3. 生成连续块的唯一分组标记 df_sorted['block_id'] = df_sorted['is_new_group'].cumsum() # 4. 聚合合并,End列特殊处理:组内存在NaT则返回NaT,否则返回组内最大日期 def agg_end(s): if s.isna().any(): return pd.NaT return s.max() result = df_sorted.groupby(['Id', 'Feature1', 'Feature2', 'block_id'], as_index=False).agg( Start=('Start', 'min'), End=('End', agg_end) )[['Id', 'Start', 'End', 'Feature1', 'Feature2']] print(result)
运行后输出结果和预期完全匹配:
Id Start End Feature1 Feature2 0 A 2020-01-01 2020-01-30 1 1 1 A 2020-01-31 2020-02-15 0 1 2 A 2020-07-01 2020-07-15 0 1 3 B 2020-01-31 NaT 0 0
关键说明
- 排序是必要前提,必须保证同组内日期按升序排列,否则连续判断会出错
- 如果业务场景的连续间隔不是1天,只需修改
pd.Timedelta(days=1)的参数即可适配 - End列的聚合逻辑已经做了NaT兼容,只要同一个连续块里存在NaT,合并后的End就返回NaT
内容的提问来源于stack exchange,提问作者antnie4
相关产品推荐
相关产品推荐

