如何更高效计算DataFrame中重复ID的Diff列?求优化方案
需求与数据集
计算规则
- 若存在重复ID:
- 非最后一条重复记录的
Diff为当前End_Date与上一条End_Date的天数差值 - 最后一条重复记录及无重复ID的记录的
Diff为End_Date与Start_Date的天数差值
- 非最后一条重复记录的
原始数据集
import pandas as pd import numpy as np df = pd.DataFrame({ 'ID': [118645, 118985, 119023, 119225, 119225, 119276, 119863, 119924, 119924, 119924, 119924, 119987], 'Start_Date': ['2021-01-04', '2021-01-11', '2021-01-07', '2021-01-08', '2021-01-08', '2021-01-07', '2021-01-11', '2021-01-13', '2021-01-13', '2021-01-13', '2021-01-13', '2021-01-12'], 'End_Date': ['2021-04-28', '2022-01-24', '2021-09-08', '2021-04-11', '2021-04-11', '2021-03-16', '2021-03-25', '2021-09-06', '2021-11-09', '2022-05-23', '2022-11-10', '2021-02-23'] })
现有实现方案
df['Diff'] = np.where(df.ID == df.ID.shift(), (pd.to_datetime(df["End_Date"]) - pd.to_datetime(df["End_Date"]).shift()) // np.timedelta64(1, 'D'), None) df['Diff'] = np.where(df.ID != df.ID.shift(), (pd.to_datetime(df["End_Date"]) - pd.to_datetime(df["Start_Date"])) // np.timedelta64(1, 'D'), df['Diff']) df_unique = df.drop_duplicates(subset="ID", keep="last") df_unique['Diff'] = df_unique['End_Date'].sub(df_unique['Start_Date'], axis=0) df_final = df_unique.combine_first(df)
执行后得到结果:
Index ID Start_Date End_Date Diff 0 118645 2021-01-04 2021-04-28 114 1 118985 2021-01-11 2022-01-24 378 2 119023 2021-01-07 2021-09-08 244 3 119225 2021-01-08 2021-04-11 93 4 119225 2021-01-08 2021-04-11 93 5 119276 2021-01-07 2021-03-16 68 6 119863 2021-01-11 2021-03-25 73 7 119924 2021-01-13 2021-09-06 236 8 119924 2021-01-13 2021-11-09 64 9 119924 2021-01-13 2022-05-23 195 10 119924 2021-01-13 2022-11-10 666 11 119987 2021-01-12 2021-02-23 42
更优实现方案
通过分组处理简化逻辑,避免多次创建临时DataFrame,步骤更清晰:
# 转换日期列为datetime类型(若原始数据为字符串格式) df['Start_Date'] = pd.to_datetime(df['Start_Date']) df['End_Date'] = pd.to_datetime(df['End_Date']) # 标记每个ID的最后一条记录 df['is_last'] = df.groupby('ID')['End_Date'].transform(lambda x: x == x.iloc[-1]) # 一次性计算Diff列 df['Diff'] = np.where( df['is_last'], (df['End_Date'] - df['Start_Date']).dt.days, (df['End_Date'] - df['End_Date'].shift()).dt.days ) # 可删除临时标记列 df = df.drop(columns='is_last')
方案优势
- 逻辑直观:通过分组标记最后一条记录,一次
np.where完成所有计算 - 性能更优:减少中间DataFrame的创建,降低内存占用
- 代码简洁:行数更少,可读性更强
执行后得到的结果与现有实现完全一致。
内容的提问来源于stack exchange,提问作者dagi_de
相关产品推荐
相关产品推荐

