Pandas按日期排序并合并DataFrame:订单与发货数据跨日期匹配方案咨询
解决思路与实现方案
根据你描述的场景,核心突破口在于你提到的**「同一客户的两次订单之间不会存在针对该客户的其他发货记录」**——这意味着每个客户的订单和发货是严格按时间顺序一一对应的,哪怕实际发货日期和要求日期有偏差也没关系。基于这个规则,咱们可以用「分组+序号匹配」的方式完成合并,具体步骤如下:
第一步:预处理数据,确保记录按时间排序
首先得把两张表的日期转换成datetime类型,然后按「客户ID+日期」排序,保证每个客户的记录是按时间先后排列的:
import pandas as pd # 假设你的订单表是df_orders,发货表是df_shipments # 转换日期列格式,避免字符串排序出错 df_orders['日期'] = pd.to_datetime(df_orders['日期']) df_shipments['日期'] = pd.to_datetime(df_shipments['日期']) # 按客户ID和日期排序,重置索引 df_orders_sorted = df_orders.sort_values(by=['客户ID', '日期']).reset_index(drop=True) df_shipments_sorted = df_shipments.sort_values(by=['客户ID', '日期']).reset_index(drop=True)
第二步:为每个客户的记录添加组内序号
接下来,给每个客户的订单和发货记录分别添加一个组内序号(比如第1条、第2条),这样同一客户的第n条订单就能精准对应第n条发货记录:
# 给订单表添加组内序号(从1开始计数) df_orders_sorted['seq'] = df_orders_sorted.groupby('客户ID').cumcount() + 1 # 给发货表添加同样的组内序号 df_shipments_sorted['seq'] = df_shipments_sorted.groupby('客户ID').cumcount() + 1
第三步:按客户ID+序号合并表
现在用「客户ID」和「组内序号」作为关联键合并两张表,就能得到你想要的结果:
# 合并两张表,用suffixes区分原表字段 merged_df = pd.merge( df_orders_sorted[['客户ID', '日期', '金额', 'seq']], df_shipments_sorted[['客户ID', '日期', '金额', 'seq']], on=['客户ID', 'seq'], suffixes=('_x', '_y') ) # 调整列顺序,移除序号列,重置索引 final_df = merged_df[['客户ID', '日期_x', '日期_y', '金额_x', '金额_y']].reset_index(drop=True)
结果验证
用你提供的示例数据测试,最终输出和你期望的完全一致:
| 客户ID | 日期_x | 日期_y | 金额_x | 金额_y |
|---|---|---|---|---|
| 12 | 2020-10-29 | 2020-11-01 | x | x |
| 12 | 2020-12-29 | 2021-01-05 | x | x |
| 14 | 2021-01-15 | 2021-03-16 | x | x |
| 16 | 2021-04-01 | 2021-04-05 | x | x |
| 16 | 2021-04-10 | 2021-04-12 | x | x |
额外处理:排查异常记录
如果某个客户的订单数和发货数不匹配(比如多了订单或多了发货),默认的内连接会过滤掉不匹配的记录。如果你想保留这些异常以便排查,可以把合并方式改成outer:
merged_df_outer = pd.merge( df_orders_sorted[['客户ID', '日期', '金额', 'seq']], df_shipments_sorted[['客户ID', '日期', '金额', 'seq']], on=['客户ID', 'seq'], suffixes=('_x', '_y'), how='outer' )
之后查看merged_df_outer中的NaN值,就能快速定位哪些客户的订单和发货记录数量不一致。
内容的提问来源于stack exchange,提问作者Moritz Backhaus
相关产品推荐
相关产品推荐

