You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何按id合并连续日期且属性相同的Pandas重复记录?

问题描述

我有如下数据:

import pandas as pd

have = {'id': [1,1,1], 
     'start_date': ['2014-12-01 00:00:00', '2015-03-01 00:00:00', '2015-06-01 00:00:00'], 
     'end_date': ['2015-02-28 23:59:59', '2015-05-31 23:59:59', '2015-08-02 23:59:59'],
     'attr_1': ['Z', 'Z', 'Z'],
     'attr_2': ['A', 'A', ''],
     'attr_3': ['B', 'B', '']}
have = pd.DataFrame(data=have)

初始数据输出:

id           start_date             end_date attr_1 attr_2 attr_3
0   1  2014-12-01 00:00:00  2015-02-28 23:59:59      Z      A      B
1   1  2015-03-01 00:00:00  2015-05-31 23:59:59      Z      A      B
2   1  2015-06-01 00:00:00  2015-08-02 23:59:59      Z              

需要按每个id合并记录,满足两个条件:

  • 下一条记录的start_date等于上一条记录的end_date + 1秒(时间区间连续)
  • 所有attr_列的取值完全相同

期望得到的结果:

want = {'id': [1,1], 
     'start_date': ['2014-12-01 00:00:00', '2015-06-01 00:00:00'], 
     'end_date': ['2015-05-31 23:59:59', '2015-08-02 23:59:59'],
     'attr_1': ['Z', 'Z'],
     'attr_2': ['A', ''],
     'attr_3': ['B', '']}
want = pd.DataFrame(data=want)

结果输出:

id           start_date             end_date attr_1 attr_2 attr_3
0   1  2014-12-01 00:00:00  2015-05-31 23:59:59      Z      A      B
1   1  2015-06-01 00:00:00  2015-08-02 23:59:59      Z              

实际场景包含百万级记录、数千个id以及60+个需要校验的属性列,需保证处理效率。

解决方案

步骤说明

  1. 转换日期类型:将start_date和end_date转为datetime类型,支持时间运算。
  2. 自动识别属性列:提取所有以attr_开头的列,无需手动指定60+列。
  3. 计算连续条件:按id分组,判断相邻记录是否同时满足「时间连续」和「属性完全一致」。
  4. 生成聚合分组标签:将连续满足条件的记录归为同一组,用于后续合并。
  5. 聚合得到最终结果:按id和分组标签聚合,取每组最早的start_date、最晚的end_date,属性列取组内任意值(同组属性一致)。

高效实现代码

import pandas as pd

# 1. 转换日期列为datetime类型
have['start_date'] = pd.to_datetime(have['start_date'])
have['end_date'] = pd.to_datetime(have['end_date'])

# 2. 自动提取所有属性列
attr_cols = [col for col in have.columns if col.startswith('attr_')]

# 3. 计算时间连续条件:当前行start_date等于上一行end_date+1秒
have['prev_end'] = have.groupby('id')['end_date'].shift(1)
time_continuous = have['start_date'] == have['prev_end'] + pd.Timedelta(seconds=1)

# 4. 计算属性相同条件:当前行与上一行所有属性列值完全一致
attr_same = have.groupby('id')[attr_cols].apply(lambda x: x.eq(x.shift(1)).all(axis=1)).reset_index(drop=True)

# 5. 生成分组标签:不满足连续条件时,分组键递增
have['group_key'] = (~(time_continuous & attr_same)).cumsum()

# 6. 聚合合并记录
result = have.groupby(['id', 'group_key']).agg(
    start_date=('start_date', 'min'),
    end_date=('end_date', 'max'),
    **{col: (col, 'first') for col in attr_cols}
).reset_index(drop=True)

print(result)

关键优化点

  • 全程采用Pandas向量化操作,避免循环,适配百万级数据处理需求。
  • 自动识别属性列,减少代码维护成本。
  • 分组标签生成采用累计求和逻辑,计算高效且逻辑清晰。

内容的提问来源于stack exchange,提问作者legends1337

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 00:34:52