如何按日期条件关联df1与df2:匹配采购日期后的首个销售日期
解决采购与销售数据的日期匹配关联问题
问题背景
现有两个已按日期排序的DataFrame:
- df1:存储id=7的采购数据,包含字段
date_buy、id、qty_buy、rolling_sum_qty_buy,每次采购1个单位 - df2:存储同id的销售数据,包含字段
date_sold、id、qty_sold、rolling_sum_qty_sold,每次销售1个单位
需求:
- 为df1的每条采购记录,匹配df2中首个晚于该采购日期的销售记录
- 保留df1中未匹配到销售的行(对应未售出的库存)
此前基于滚动求和字段左关联的代码会出现销售日期早于采购日期的错误匹配:
df3= df1.merge(df2,how='left',left_on=['rolling_sum_qty_buy'],right_on=['rolling_sum_qty_sold'])
方法1:使用merge_asof(推荐)
由于两个DataFrame已按日期排序,merge_asof可以高效实现「最近正向匹配」,完美契合需求:
# 二次确认df2按销售日期排序(题目已说明排序,此步骤可选) df2_sorted = df2.sort_values('date_sold') # 执行左关联,匹配首个晚于采购日期的销售记录 df3 = pd.merge_asof( df1, df2_sorted, left_on='date_buy', right_on='date_sold', by='id', direction='forward', # 指定寻找右表中第一个大于左表日期的记录 allow_exact_matches=False # 严格排除日期相等的情况,仅匹配晚于的记录 )
关键参数说明
direction='forward':核心逻辑,只找右表中日期大于左表采购日期的第一条记录allow_exact_matches=False:如果业务允许日期相等的匹配,可删除此参数by='id':确保仅关联同一id的采购与销售数据,避免跨id错误匹配
方法2:自定义匹配逻辑(适合复杂场景)
如果需要更灵活的匹配规则(比如额外加业务判断),可以用apply实现自定义匹配:
# 提取df2中已排序的销售日期列表 sold_dates = df2['date_sold'].tolist() # 定义函数:为单个采购日期找到首个晚于它的销售日期 def match_first_sold(date_buy): for date_sold in sold_dates: if date_sold > date_buy: return date_sold return None # 无匹配时返回空值 # 给df1添加匹配到的销售日期字段 df1['date_sold'] = df1['date_buy'].apply(match_first_sold) # 关联df2的其他销售字段 df3 = df1.merge(df2, on=['id', 'date_sold'], how='left')
注意事项
- 此方法灵活性高,但数据量较大时性能不如
merge_asof,需谨慎使用 - 未匹配到销售的行,
date_sold会显示None,关联后df2的字段会自动填充NaN,可直接用于库存统计
结果验证
关联完成后,可通过以下代码检查是否存在错误匹配:
# 筛选销售日期早于/等于采购日期的记录(正常情况应返回空DataFrame) invalid_records = df3[df3['date_sold'] <= df3['date_buy']] print(invalid_records)
内容的提问来源于stack exchange,提问作者mr analyst
相关产品推荐
相关产品推荐

