如何在Pandas DataFrame中合并连续的日期区间
如何合并Pandas DataFrame中连续的日期区间记录?
我来帮你搞定这个问题,咱们一步步拆解操作,确保能得到你想要的结果。
先明确问题场景
你手里有这么一份Pandas DataFrame,其中有些记录的日期是连续的——比如第一行的end_date刚好和第五行的start_date完全重合,需要把这类连续的区间合并成一条记录,保留最早的start_date和最晚的end_date,同时删掉被合并的那条记录。
原始数据集
| ID | Order_ID | start_date | end_date | Product | Sub_Product |
|---|---|---|---|---|---|
| 746 | 001 | 08-Oct-2019 0:00:00 | 16-Nov-2019 0:00:00 | LPP | Abc |
| 746 | 002 | 10-Oct-2019 0:00:00 | 02-Sep-2020 0:00:00 | LPP | Abc |
| 746 | 003 | 10-Oct-2019 0:00:00 | 11-Sep-2020 0:00:00 | LPP | Abc |
| 746 | 004 | 10-Oct-2019 0:00:00 | 08-Jan-2021 0:00:00 | LPP | Abc |
| 746 | 005 | 16-Nov-2019 0:00:00 | 17-Dec-2019 0:00:00 | LPP | Abc |
期望的合并结果
处理后应该得到这样的DataFrame:
| ID | Order_ID | start_date | end_date | Product | Sub_Product |
|---|---|---|---|---|---|
| 746 | 001 | 08-Oct-2019 0:00:00 | 17-Dec-2019 0:00:00 | LPP | Abc |
| 746 | 002 | 10-Oct-2019 0:00:00 | 02-Sep-2020 0:00:00 | LPP | Abc |
| 746 | 003 | 10-Oct-2019 0:00:00 | 11-Sep-2020 0:00:00 | LPP | Abc |
| 746 | 004 | 10-Oct-2019 0:00:00 | 08-Jan-2021 0:00:00 | LPP | Abc |
具体实现步骤
1. 先把日期列转成datetime类型
首先得把字符串格式的日期转成Pandas能识别的datetime类型,不然没法正确做日期匹配:
import pandas as pd # 先构造你的原始DataFrame data = { 'ID': [746, 746, 746, 746, 746], 'Order_ID': ['001', '002', '003', '004', '005'], 'start_date': ['08-Oct-2019 0:00:00', '10-Oct-2019 0:00:00', '10-Oct-2019 0:00:00', '10-Oct-2019 0:00:00', '16-Nov-2019 0:00:00'], 'end_date': ['16-Nov-2019 0:00:00', '02-Sep-2020 0:00:00', '11-Sep-2020 0:00:00', '08-Jan-2021 0:00:00', '17-Dec-2019 0:00:00'], 'Product': ['LPP']*5, 'Sub_Product': ['Abc']*5 } df = pd.DataFrame(data) # 转换日期列 df['start_date'] = pd.to_datetime(df['start_date']) df['end_date'] = pd.to_datetime(df['end_date'])
2. 找出需要合并的记录对
接下来我们要找到所有“前一条的end_date等于后一条的start_date”的记录对:
# 先做个映射:把每个start_date对应的Order_ID存起来 start_to_order = df.set_index('start_date')['Order_ID'].to_dict() # 遍历每一行,找匹配的记录 merge_pairs = [] for idx, row in df.iterrows(): # 如果当前行的end_date存在于start_date的集合里,说明有匹配的记录 if row['end_date'] in start_to_order: # 找到匹配的Order_ID对应的行索引 matched_order = start_to_order[row['end_date']] matched_idx = df[df['Order_ID'] == matched_order].index[0] merge_pairs.append((idx, matched_idx))
3. 合并记录并清理数据
现在我们把每一对匹配的记录合并,更新起始记录的end_date,然后删掉被合并的那条:
# 更新起始记录的end_date为被合并记录的end_date for original_idx, merge_idx in merge_pairs: df.loc[original_idx, 'end_date'] = df.loc[merge_idx, 'end_date'] # 移除被合并的记录,重置索引 df = df.drop([pair[1] for pair in merge_pairs]).reset_index(drop=True)
4. 查看最终结果
运行完上面的代码后,打印df就能得到你想要的合并后的数据了:
print(df)
扩展:处理多层连续的区间
如果你的数据里存在多层连续的情况(比如A的end_date匹配B的start_date,B的end_date又匹配C的start_date),可以用循环重复执行匹配和合并步骤,直到没有新的匹配对为止:
while True: start_to_order = df.set_index('start_date')['Order_ID'].to_dict() merge_pairs = [] for idx, row in df.iterrows(): if row['end_date'] in start_to_order: matched_order = start_to_order[row['end_date']] matched_idx = df[df['Order_ID'] == matched_order].index[0] # 避免自己匹配自己 if idx != matched_idx: merge_pairs.append((idx, matched_idx)) # 如果没有新的匹配对,就退出循环 if not merge_pairs: break # 合并记录 for original_idx, merge_idx in merge_pairs: df.loc[original_idx, 'end_date'] = df.loc[merge_idx, 'end_date'] df = df.drop([pair[1] for pair in merge_pairs]).reset_index(drop=True)
这样就能处理更复杂的连续区间合并啦。
内容的提问来源于stack exchange,提问作者Ambreen
相关产品推荐
相关产品推荐

