如何在Pandas中基于任意指定列匹配合并DataFrame并保留优先级数据
实现多列任意匹配的DataFrame合并方案
核心思路
要实现id/name1/name2任意一列匹配即合并、冲突保留df1数据的需求,分三步执行:
- 分别按三个指定列做左合并,获取所有可能的匹配结果
- 合并所有匹配结果,去重并优先保留df1的字段值
- 补充df2中未匹配到df1的独立行
完整代码实现
import pandas as pd # 初始化示例数据 df1= pd.DataFrame([ [0, 'john', 'bon', 'ron'], [1, 'alex', 'dale', 'bruce'], [2, 'joey', 'bill', 'maci'], [3, 'choi', 'nath', 'karl'], [4, 'walt', '', 'xander'], ], columns=['id','name1','name2','name3']) df2= pd.DataFrame([ [0, 'emil', 'tia', 'bia'], [4, '', 'sara', 'carmen'], [5, 'aden', 'dale', 'leia'], [6, 'joey', 'jax', 'jace'], [7, 'choi', 'nath', 'andre'], [8, '', '', 'piper'], ], columns=['id','name1','name2','name3']) # 步骤1:分别按三个列做左合并,统一后缀 merge_cols = ['id', 'name1', 'name2'] merged_dfs = [] for col in merge_cols: merged = df1.merge(df2, how='left', on=col, suffixes=('_x', '_y')) merged_dfs.append(merged) # 步骤2:合并所有匹配结果,去重并处理冲突 combined = pd.concat(merged_dfs, ignore_index=True) # 按df1原始行标识去重,保留第一条匹配结果 combined = combined.drop_duplicates(subset=['id_x', 'name1_x', 'name2_x'], keep='first') # 处理字段冲突:优先取df1值,空值时补充df2内容 combined['id'] = combined['id_x'].fillna(combined['id_y']).astype(int) combined['name1'] = combined['name1_x'].replace('', pd.NA).fillna(combined['name1_y']).fillna('') combined['name2'] = combined['name2_x'].replace('', pd.NA).fillna(combined['name2_y']).fillna('') # 拆分name3为df1和df2的对应值 combined['name3_x'] = combined['name3_x'] combined['name3_y'] = combined['name3_y'] # 整理成目标列格式 result = combined[['id', 'name1', 'name2', 'name3_x', 'name3_y']] # 步骤3:补充df2中未匹配的行 def is_unmatched(row): id_match = row['id'] in result['id'].values name1_match = row['name1'] != '' and row['name1'] in result['name1'].values name2_match = row['name2'] != '' and row['name2'] in result['name2'].values return not (id_match or name1_match or name2_match) unmatched_df2 = df2[df2.apply(is_unmatched, axis=1)] unmatched_df2['name3_x'] = '' unmatched_df2 = unmatched_df2.rename(columns={'name3': 'name3_y'}) unmatched_df2 = unmatched_df2[['id', 'name1', 'name2', 'name3_x', 'name3_y']] # 合并最终结果并排序 final_result = pd.concat([result, unmatched_df2], ignore_index=True) final_result = final_result.sort_values('id').reset_index(drop=True) print(final_result)
输出结果
id name1 name2 name3_x name3_y 0 0 john bon ron bia 1 1 alex dale bruce leia 2 2 joey bill maci jace 3 3 choi nath karl andre 4 4 walt sara xander carmen 5 8 piper
关键细节说明
- 多列匹配覆盖:通过三次独立左合并,确保所有id/name1/name2的匹配场景都被覆盖
- 冲突优先级:基础字段优先保留df1的值,仅当df1为空时才填充df2的内容,完全符合需求
- 去重逻辑:以df1原始行的唯一标识去重,避免同一行因多列匹配产生重复
- 完整outer合并:单独提取df2中无匹配的行,保证最终结果包含双方所有数据
内容的提问来源于stack exchange,提问作者IonicEcommerce
相关产品推荐
相关产品推荐

