如何在pandas merge_asof中保留仅存在于右表的用户?
问题描述
现有如下Pandas数据:
df1
user_id create_at 0 1 2023-01-01 1 1 2023-01-02 2 2 2023-01-01 3 2 2023-01-03 4 2 2023-01-05
df2
user_id withdrawal_request_date 0 1 2023-01-03 1 2 2023-01-02 2 3 2023-01-01
我尝试执行merge_asof操作,代码及结果如下:
pd.merge_asof(df1.sort_values('create_at'), df2.sort_values('withdrawal_request_date'), by = 'user_id', left_on = 'create_at', right_on = 'withdrawal_request_date', direction = 'forward')
执行结果:
user_id create_at withdrawal_request_date 0 1 2023-01-01 2023-01-03 1 2 2023-01-01 2023-01-02 2 1 2023-01-02 2023-01-03 3 2 2023-01-03 NaT 4 2 2023-01-05 NaT
但结果丢失了仅存在于df2中的user_id=3的用户,期望输出如下:
user_id create_at withdrawal_request_date 0 1 2023-01-01 2023-01-03 1 2 2023-01-01 2023-01-02 2 1 2023-01-02 2023-01-03 3 2 2023-01-03 NaT 4 2 2023-01-05 NaT 5 3 NaT 2023-01-01
注意:数据集规模极大,包含数千用户及大量行为数据,因此无法使用outer joins这类方法。
数据定义代码:
import pandas as pd df1 = pd.DataFrame({ 'user_id': [1, 1, 2, 2, 2], 'create_at': pd.to_datetime(['2023-01-01', '2023-01-02', '2023-01-01', '2023-01-03', '2023-01-05']) }) df2 = pd.DataFrame({ 'user_id': [1, 2, 3], 'withdrawal_request_date': pd.to_datetime(['2023-01-03', '2023-01-02', '2023-01-01']) })
解决方案
可以通过拆分处理+高效拼接的方式实现,避免outer join带来的性能问题:
- 先执行原
merge_asof操作得到基础结果 - 筛选出df2中仅有的用户数据(即user_id不在df1中的记录)
- 给这部分数据补充
create_at列,值设为NaT - 将基础结果和补充数据高效拼接
具体代码如下:
# 1. 执行原merge_asof操作 df_merge = pd.merge_asof( df1.sort_values('create_at'), df2.sort_values('withdrawal_request_date'), by='user_id', left_on='create_at', right_on='withdrawal_request_date', direction='forward' ) # 2. 筛选df2独有的用户记录 df2_only = df2[~df2['user_id'].isin(df1['user_id'].unique())].copy() # 3. 补充create_at列 df2_only['create_at'] = pd.NaT # 4. 调整列顺序,和df_merge保持一致,然后拼接 df2_only = df2_only[['user_id', 'create_at', 'withdrawal_request_date']] final_df = pd.concat([df_merge, df2_only], ignore_index=True) print(final_df)
方案优势
- 筛选df2独有用户时,
isin配合unique()是向量化操作,效率远高于循环或全表比对 pd.concat是内存高效的拼接方式,不会产生额外的笛卡尔积,完全适配大规模数据集
内容的提问来源于stack exchange,提问作者Beck
相关产品推荐
相关产品推荐

