如何将含多日期字段的重复ID数据合并为单行?
按ID合并含重复日期字段的数据解决方案
原始数据(每行含4个日期字段,同一ID的DateIn存在重复):
ID,LName,FName,DateIn,DateOut,Days,ODateIn,ODateOut,Odays 1,Doe,Jay,7/14/2023,8/14/2023,31.00,8/15/2023,4/22/2024,251.00 1,Doe,Jay,3/4/2021,11/5/2021,246.00,11/12/2021,12/31/2021,49.00 1,Doe,Jay,7/14/2023,8/14/2023,31.00,5/30/2024,7/2/2024,33.00 1,Doe,Jay,5/8/2022,1/1/2023,238.00,2/28/2023,4/8/2023,39.00 2,Smith,Dude,4/16/2022,6/2/2022,47.00,7/23/2022,9/13/2022,52.00 2,Smith,Dude,12/5/2022,3/14/2023,99.00,8/30/2023,10/11/2023,42.00 2,Smith,Dude,1/3/2024,3/30/2024,87.00,7/18/2024,9/1/2024,45.00 3,Doe,Jane,4/6/2020,8/10/2020,126.00,11/12/2020,1/18/2021,67.00 3,Doe,Jane,4/6/2020,8/10/2020,126.00,3/27/2021,6/9/2021,74.00 3,Doe,Jane,4/6/2020,8/10/2020,126.00,10/4/2021,11/30/2021,57.00
目标格式(按ID合并为单行,重复DateIn仅保留一组,O日期保留所有记录):
ID,DateIn1,DateOut1,Days1,DateIn2,DateOut2,Days2,DateIn3,DateOut3,Days3,ODateIn1,ODateOut1,Days1,ODateIn2,ODateOut2,Days2,ODateIn3,ODateOut3,Days3,ODateIn4,ODateOut4,Days4 1,3/4/2021,11/5/2021,246.00,5/8/2022,1/1/2023,238.00,7/14/2023,8/14/2023,31.00,11/12/2021,12/31/2021,49.00,2/28/2023,4/8/2023,39.00,8/15/2023,4/22/2024,251.00,5/30/2024,7/2/2024,33.00 2,4/16/2022,6/2/2022,47.00,12/5/2022,3/14/2023,99.00,1/3/2024,3/30/2024,87.00,7/23/2022,9/13/2022,52.00,8/30/2023,10/11/2023,42.00,7/18/2024,9/1/2024,45.00,,, 3,4/6/2020,8/10/2020,126.00,,,,,,,11/12/2020,1/18/2021,67.00,3/27/2021,6/9/2021,74.00,10/4/2021,11/30/2021,57.00,,,
使用pivot方法时,因DateIn存在重复值导致无法正确合并,以下是可行解决方案:
解决方案步骤
1. 数据预处理与分组
将主日期组(DateIn/DateOut/Days)和O日期组(ODateIn/ODateOut/Odays)分开处理,分别转宽表后再合并:
import pandas as pd # 读取原始数据 df = pd.read_csv("your_data.csv") # ---------------------- 处理主日期组(去重后转宽表) ---------------------- # 提取主日期相关字段并去重 main_dates = df[["ID", "DateIn", "DateOut", "Days"]].drop_duplicates() # 按ID分组,给每个唯一的主日期添加序号(从1开始) main_dates["main_seq"] = main_dates.groupby("ID").cumcount() + 1 # 转宽表:将序号作为后缀添加到字段名 main_wide = main_dates.pivot( index="ID", columns="main_seq", values=["DateIn", "DateOut", "Days"] ).reset_index() # 重命名列,比如DateIn_1 → DateIn1 main_wide.columns = ["ID"] + [f"{col[0]}{col[1]}" for col in main_wide.columns[1:]] # ---------------------- 处理O日期组(保留所有记录转宽表) ---------------------- # 提取O日期相关字段 o_dates = df[["ID", "ODateIn", "ODateOut", "Odays"]] # 按ID分组,给每个O日期记录添加序号(从1开始) o_dates["o_seq"] = o_dates.groupby("ID").cumcount() + 1 # 转宽表:将序号作为后缀添加到字段名 o_wide = o_dates.pivot( index="ID", columns="o_seq", values=["ODateIn", "ODateOut", "Odays"] ).reset_index() # 重命名列,将Odays替换为目标格式的Days o_wide.columns = ["ID"] + [f"{col[0].replace('Odays', 'Days')}{col[1]}" for col in o_wide.columns[1:]] # ---------------------- 合并两个宽表并调整列顺序 ---------------------- # 按ID合并 final_df = pd.merge(main_wide, o_wide, on="ID", how="left") # 按目标格式的列顺序排序 target_cols = [ "ID", "DateIn1", "DateOut1", "Days1", "DateIn2", "DateOut2", "Days2", "DateIn3", "DateOut3", "Days3", "ODateIn1", "ODateOut1", "Days1", "ODateIn2", "ODateOut2", "Days2", "ODateIn3", "ODateOut3", "Days3", "ODateIn4", "ODateOut4", "Days4" ] # 填充缺失列并调整顺序,空值替换为空字符串 final_df = final_df.reindex(columns=target_cols).fillna("") # 导出结果 final_df.to_csv("result.csv", index=False)
代码说明
- 主日期组处理:先去重确保每个ID的DateIn仅保留唯一值,通过
cumcount生成序号后转宽表,得到带数字后缀的字段。 - O日期组处理:不做去重,直接给每个ID下的O日期记录生成序号,转宽表时将
Odays替换为目标格式的Days后缀。 - 合并与调整:将两个宽表按ID合并,按目标列顺序调整后填充空值,最终导出符合要求的CSV。
内容的提问来源于stack exchange,提问作者ThatOneGirl
相关产品推荐
相关产品推荐

