同一DataFrame列内日期对比及标签匹配问题求助
订单与呼叫数据标签匹配需求
我在同一DataFrame中存储了订单数据与呼叫数据,需要实现以下逻辑:
- 对比「Order created」的START时间与「Call Start」相关行的START时间
- 若呼叫的START时间在订单创建后30天内,将该订单的Tag_x和Tag_z值添加到对应的呼叫行
- 若存在多个符合条件的「Order created」记录,需以「Tagx1, Tagx2...」的格式拼接标签值
我尝试将原DataFrame拆分为订单子表(dforder)和呼叫子表(dfcall),使用iterrows()遍历行进行判断,但不确定该方法的使用是否正确。以下是样本数据、期望输出及我编写的代码片段:
样本数据
| CASE ID | Activity Name | START | minit_source_system | Tag_x | Tag_z |
|---|---|---|---|---|---|
| 111 | Order created | Tuesday, March 16, 2021 | NC | Home Phone Installation | VOICE |
| 111 | Fielded Work Order Open | Tuesday, March 16, 2021 | FWDS | Home Phone Installation | VOICE |
| 111 | Job - COMPLETE | Tuesday, March 16, 2021 | FWDS | Home Phone Installation | VOICE |
| 111 | Fielded Work Order Completed | Thursday, March 18, 2021 | FWDS | Home Phone Installation | VOICE |
| 111 | Order created | Wednesday, May 4, 2022 | NC | Home Security Installation | SECURITY |
| 111 | Fielded Work Order Open | Wednesday, May 4, 2022 | FWDS | Home Security Installation | SECURITY |
| 111 | Job - COMPLETE | Wednesday, May 4, 2022 | FWDS | Home Security Installation | SECURITY |
| 111 | Fielded Work Order Completed | Thursday, May 5, 2022 | FWDS | Home Security Installation | SECURITY |
| 111 | Bill Issued | Tuesday, May 10, 2022 | |||
| 111 | Call Start | Tuesday, May 17, 2022 | Gen | ||
| 111 | PureFibre-TS | Tuesday, May 17, 2022 | Gen |
期望输出
| CASE ID | Activity Name | START | minit_source_system | Tag_x | Tag_z |
|---|---|---|---|---|---|
| 111 | Order created | Tuesday, March 16, 2021 | NC | Home Phone Installation | VOICE |
| 111 | Fielded Work Order Open | Tuesday, March 16, 2021 | FWDS | Home Phone Installation | VOICE |
| 111 | Job - COMPLETE | Tuesday, March 16, 2021 | FWDS | Home Phone Installation | VOICE |
| 111 | Fielded Work Order Completed | Thursday, March 18, 2021 | FWDS | Home Phone Installation | VOICE |
| 111 | Order created | Wednesday, May 4, 2022 | NC | Home Security Installation | SECURITY |
| 111 | Fielded Work Order Open | Wednesday, May 4, 2022 | FWDS | Home Security Installation | SECURITY |
| 111 | Job - COMPLETE | Wednesday, May 4, 2022 | FWDS | Home Security Installation | SECURITY |
| 111 | Fielded Work Order Completed | Thursday, May 5, 2022 | FWDS | Home Security Installation | SECURITY |
| 111 | Bill Issued | Tuesday, May 10, 2022 | |||
| 111 | Call Start | Tuesday, May 17, 2022 | Gen | Home Phone Installation, Home Security Installation | VOICE, SECURITY |
| 111 | PureFibre-TS | Tuesday, May 17, 2022 | Gen | Home Phone Installation, Home Security Installation | VOICE, SECURITY |
尝试代码
dfcall= df[df['Activity Name']=="Call Start"] dfcall['Tag_x']=nan dfcall['Tag_z']=nan dfcall=dfcall[['CASE ID','Activity Name','START','Tag_x','Tag_z']].reset_index(drop=True) dforder=df[df['Activity Name']=="Order created"].reset_index(drop=True) dforder=dforder[['CASE ID','Activity Name','START','Tag_x','Tag_z']].reset_index(drop=True) for index, row_c in dfcall.iterrows(): for index, row_o in dforder.iterrows(): if (row_c['CASE ID']==row_o['CASE ID']) & (row_c['START']>row_o['START'])& (((row_c['START'] - row_o['START']).total_seconds()/60/60)<=720): y=row_o['Tag_x'] row_c['Tag_x']=y+" "+"|"+" "+row_o['Tag_x']
问题分析与优化方案
原代码存在的问题
- 时间格式未转换:
START列是字符串格式,无法直接进行时间比较和运算,必须先转换为datetime类型。 iterrows()效率低下:双重iterrows()循环在数据量较大时性能极差,应使用向量化操作替代。- 标签拼接逻辑错误:原代码会重复拼接同一个标签,且格式不符合逗号分隔的要求。
- 遗漏关联行:需求中需更新「Call Start」及同时间的「PureFibre-TS」行,原代码仅处理了前者。
优化实现代码
import pandas as pd # 1. 转换START列为datetime类型,确保时间运算有效 df['START'] = pd.to_datetime(df['START'], format='%A, %B %d, %Y') # 2. 提取订单数据,计算订单创建后30天的截止时间 order_df = df[df['Activity Name'] == 'Order created'].copy() order_df['30_days_limit'] = order_df['START'] + pd.Timedelta(days=30) # 3. 定位所有需要更新的行:Call Start及其同时间的关联行 call_time = df[df['Activity Name'] == 'Call Start']['START'].iloc[0] update_mask = (df['Activity Name'] == 'Call Start') | (df['START'] == call_time) update_df = df[update_mask].copy() # 4. 关联订单与待更新数据,筛选符合时间条件的记录 merged_data = pd.merge( update_df, order_df[['CASE ID', 'START', 'Tag_x', 'Tag_z', '30_days_limit']], on='CASE ID', suffixes=('_call', '_order') ) valid_matches = merged_data[(merged_data['START_call'] >= merged_data['START_order']) & (merged_data['START_call'] <= merged_data['30_days_limit'])] # 5. 按呼叫行分组,拼接标签值 aggregated_tags = valid_matches.groupby(['CASE ID', 'START_call', 'Activity Name', 'minit_source_system']).agg( Tag_x=('Tag_x', lambda x: ', '.join(x)), Tag_z=('Tag_z', lambda x: ', '.join(x)) ).reset_index() # 6. 将拼接后的标签更新回原DataFrame df.update(aggregated_tags.set_index(['CASE ID', 'Activity Name', 'START'])) # 输出结果 print(df)
代码说明
- 时间转换:通过
pd.to_datetime将字符串时间转为可计算的datetime类型,保证时间比较逻辑正确。 - 高效关联:使用
merge替代双重循环,大幅提升数据处理效率。 - 标签聚合:利用
groupby结合lambda函数实现标签的逗号分隔拼接,符合需求格式。 - 批量更新:通过
update方法将结果同步回原DataFrame,确保所有关联行都被正确更新。
内容的提问来源于stack exchange,提问作者user11427018
相关产品推荐
相关产品推荐

