如何基于OR条件对两个Pandas DataFrame执行左连接?
问题:多列OR条件的Left Join实现
数据准备
ABC DataFrame
import pandas as pd ABC_data = [['A001', 'B001','C001','xxx','nnn'], ['A002', 'B002','C002','yyy','mmm'], ['A003', 'B003','C003','zzz','ooo']] ABC = pd.DataFrame(ABC_data, columns = ['A', 'B','C','Other_1','Other_2']) print(ABC)
输出:
A B C Other_1 Other_2 0 A001 B001 C001 xxx nnn 1 A002 B002 C002 yyy mmm 2 A003 B003 C003 zzz ooo
LOP DataFrame
LOP_data = [['A002','sth1'], ['B004','sth2'], ['C002','sth3'], ['C003','sth4']] LOP = pd.DataFrame(LOP_data, columns = ['L', 'other_info']) print(LOP)
输出:
L other_info 0 A002 sth1 1 B004 sth2 2 C002 sth3 3 C003 sth4
需求说明
以ABC为左表、LOP为右表执行left join,连接条件为:LOP['L'] 等于 ABC['A'] 或 ABC['B'] 或 ABC['C']。
注意:L的值只会匹配A/B/C中的某一列,不会同时匹配多列。匹配成功则合并LOP的所有列;无匹配项则对应列值为null。
期望结果
A B C Other_1 Other_2 L L_other_info 0 A001 B001 C001 xxx nnn None None 1 A002 B002 C002 yyy mmm A002 sth1 2 A002 B002 C002 yyy mmm C002 sth3 3 A003 B003 C003 zzz ooo C003 sth4
已尝试方案
- 尝试用
merge函数,但仅支持AND条件,无法满足OR需求; - 复制ABC三份,分别置空不同关键列后与LOP单独合并再拼接,但无法正确去重并保留无匹配的null行,最终失败。
解决方案
核心思路是将ABC的多列匹配条件转化为长格式的一对一匹配,再合并还原,具体实现如下:
# 为ABC添加索引,方便后续还原原结构 ABC = ABC.reset_index() # 将A/B/C列转为长格式,保留其他非匹配列 melted_ABC = ABC.melt( id_vars=['index', 'Other_1', 'Other_2'], value_vars=['A', 'B', 'C'], value_name='L' ) # 和LOP执行left join merged = melted_ABC.merge(LOP, on='L', how='left') # 合并回原表的基础列,调整列名 result = merged.merge(ABC, on='index', how='left') result = result[['A', 'B', 'C', 'Other_1_x', 'Other_2_x', 'L', 'other_info']] result.columns = ['A', 'B', 'C', 'Other_1', 'Other_2', 'L', 'L_other_info'] # 处理无匹配的行:仅保留一行空值记录 mask = result[['L', 'L_other_info']].isna().all(axis=1) non_null_rows = result[~mask] null_rows = result[mask].drop_duplicates(subset=['A', 'B', 'C']) # 合并结果并按原索引排序 final_result = pd.concat([null_rows, non_null_rows]).sort_index() print(final_result)
执行后即可得到符合期望的结果。
内容的提问来源于stack exchange,提问作者xlxdxf
相关产品推荐
相关产品推荐

