如何在Pandas中合并数据表,仅匹配最接近的计划与实际日期?
Pandas匹配每个计划日期到最近实际日期的正确实现
问题分析
你需要将df1的每个pld_date(计划日期)匹配到同ID下最近的act_date(实际日期),之前用merge_asof或merge全量填充了唯一的有效实际日期,问题出在没有按ID分组匹配,或者未正确配置merge_asof的参数。
解决方案
准备示例数据
先模拟你的数据场景:
import pandas as pd import numpy as np # df1:含ID、计划日期,实际日期全为NaT df1 = pd.DataFrame({ 'ID': ['A', 'A', 'B', 'B'], 'pld_date': pd.to_datetime(['2023-09-01', '2023-09-10', '2023-08-30', '2023-09-15']), 'act_date': pd.NaT }) # df2:含ID、实际日期(仅ID=A有有效日期2023-09-07),计划日期全为NaT df2 = pd.DataFrame({ 'ID': ['A', 'B'], 'act_date': pd.to_datetime(['2023-09-07', pd.NaT]), 'pld_date': pd.NaT })
方法1:使用merge_asof(推荐,性能更优)
merge_asof支持按分组(ID)匹配最近日期,但必须满足两个前提:
- 左右表都要按分组键+日期键排序
- 指定
by参数为分组列(ID),并设置direction='nearest'
代码实现:
# 提取df2中有效的实际日期记录(过滤NaT) valid_act_dates = df2.dropna(subset=['act_date'])[['ID', 'act_date']] # 对df1和有效实际日期表按ID+日期排序 df1_sorted = df1.sort_values(['ID', 'pld_date']) act_dates_sorted = valid_act_dates.sort_values(['ID', 'act_date']) # 按ID分组,匹配最近的实际日期 df3 = pd.merge_asof( df1_sorted, act_dates_sorted, by='ID', # 按ID分组匹配 left_on='pld_date', right_on='act_date', direction='nearest' # 找最近的日期,无论前后 ) # 整理目标列 df3 = df3[['ID', 'pld_date', 'act_date_y']].rename(columns={'act_date_y': 'act_date'})
运行后df3的结果:
| ID | pld_date | act_date |
|---|---|---|
| A | 2023-09-01 | 2023-09-07 |
| A | 2023-09-10 | 2023-09-07 |
| B | 2023-08-30 | NaT |
| B | 2023-09-15 | NaT |
方法2:分组+自定义函数(灵活适配复杂场景)
如果需要更复杂的匹配逻辑,可通过分组后自定义函数计算最近日期:
# 提取有效实际日期并按ID分组 act_dict = valid_act_dates.groupby('ID')['act_date'].apply(list).to_dict() def get_nearest_act(row): # 获取当前ID对应的所有有效实际日期 act_list = act_dict.get(row['ID'], []) if not act_list: return pd.NaT # 计算每个实际日期与计划日期的时间差绝对值,取最小的那个 diffs = [abs(row['pld_date'] - dt) for dt in act_list] return act_list[diffs.index(min(diffs))] # 为df1的每一行匹配最近实际日期 df1['act_date'] = df1.apply(get_nearest_act, axis=1) df3 = df1.copy()
错误原因解释
你之前的merge_asof或merge全量填充日期,大概率是因为:
- 使用
merge_asof时未指定by='ID',导致所有行不区分ID,直接匹配到唯一的有效实际日期 - 使用普通
merge时未做分组筛选,直接按ID全量合并后未过滤最小时间差的记录
内容的提问来源于stack exchange,提问作者Harris Ahmed
相关产品推荐
相关产品推荐

