如何基于两个DataFrame不同日期列的日期条件合并数据
问题背景
现有两个DataFrame,结构如下:
df1结构
包含P_CLIENT_ID(用户ID)、P_DATE_ENCOUNTER(就诊日期)两列,示例数据:
| P_CLIENT_ID | P_DATE_ENCOUNTER |
|---|---|
| 25835 | 2016-12-21 |
| 25835 | 2017-02-21 |
| 25835 | 2017-04-25 |
| 25835 | 2017-06-21 |
| 25835 | 2017-09-04 |
| 25835 | 2018-01-08 |
| 25835 | 2018-04-03 |
df2结构
包含R_CLIENT_ID(用户ID)、R_DATE_TESTED(检测日期)、R_RESULT(检测结果)三列,示例数据:
| R_CLIENT_ID | R_DATE_TESTED | R_RESULT |
|---|---|---|
| 25835 | 2017-03-07 | 20.0 |
| 25835 | 2017-08-03 | 20.0 |
| 25835 | 2018-03-23 | 20.0 |
| 25835 | 2019-06-28 | 20.0 |
| 25835 | 2019-08-19 | 42.0 |
| 25835 | 2020-04-20 | 40.0 |
| 25835 | 2021-06-03 | 20.0 |
合并规则
将df2合并到主表df1上,关联键为用户ID,追加匹配到的最新检测记录,规则如下:
- 仅匹配检测日期早于就诊日期的记录,取最近的一条
- 没有符合条件的检测记录时,检测相关字段置空
预期结果如下:
| P_CLIENT_ID | R_CLIENT_ID | P_DATE_ENCOUNTER | R_DATE_TESTED | R_RESULT |
|---|---|---|---|---|
| 25835 | 25835.0 | 2016-12-21 | NaN | NaN |
| 25835 | 25835.0 | 2017-02-21 | NaN | NaN |
| 25835 | 25835.0 | 2017-04-25 | 2017-03-07 | 20.0 |
| 25835 | 25835.0 | 2017-06-21 | 2017-03-07 | 20.0 |
| 25835 | 25835.0 | 2017-09-04 | 2017-08-03 | 20.0 |
| 25835 | 25835.0 | 2018-01-08 | 2017-08-03 | 20.0 |
| 25835 | 25835.0 | 2018-04-03 | 2018-03-23 | 20.0 |
数据规模
实际数据集df1约70万行,df2约12.5万行。
解决方案
你当前全量merge后去重的方案存在结果不准、性能差的问题,推荐使用专门处理时间邻近匹配的merge_asof方法,逻辑完全匹配需求且运行效率极高:
import pandas as pd import numpy as np # 示例数据构造(已修正原代码df1列名笔误P_CLIENT_D为P_CLIENT_ID) df1 = pd.DataFrame({ 'P_CLIENT_ID': ['25835','25835','25835','25835','25835','25835','25835'], 'P_DATE_ENCOUNTER': ['2016-12-21','2017-02-21','2017-04-25','2017-06-21','2017-09-04','2018-01-08','2018-04-03'] }) df2 = pd.DataFrame({ 'R_CLIENT_ID': ['25835','25835','25835','25835','25835','25835','25835'], 'R_DATE_TESTED': ['2017-03-07','2017-08-03','2018-03-23','2019-06-28','2019-08-19','2020-04-20','2021-06-03'], 'R_RESULT':[20,20,20,20,42,40,20] }) # 1. 将日期列转为datetime类型,是merge_asof的必要前提 df1['P_DATE_ENCOUNTER'] = pd.to_datetime(df1['P_DATE_ENCOUNTER']) df2['R_DATE_TESTED'] = pd.to_datetime(df2['R_DATE_TESTED']) # 2. 按用户ID和日期排序,merge_asof要求两个表的匹配日期列有序 df1 = df1.sort_values(by=['P_CLIENT_ID', 'P_DATE_ENCOUNTER']).reset_index(drop=True) df2 = df2.sort_values(by=['R_CLIENT_ID', 'R_DATE_TESTED']).reset_index(drop=True) # 3. 执行asof合并,按用户分组匹配小于就诊日期的最近检测记录 df_merged = pd.merge_asof( df1, df2, left_on='P_DATE_ENCOUNTER', right_on='R_DATE_TESTED', left_by='P_CLIENT_ID', right_by='R_CLIENT_ID', direction='backward' )
运行上述代码得到的结果完全符合预期,处理你提到的100万级以内数据仅需几秒,不会产生笛卡尔积中间表,内存占用极低。
内容的提问来源于stack exchange,提问作者Mazil_tov998
相关产品推荐
相关产品推荐

