基于多列合并两个Pandas DataFrame的问题求助
问题描述
我有两个DataFrame,想要基于df1的Name列与df2的label、pref_label、alt_label多列进行合并(不区分大小写)。
示例数据:
import pandas as pd df1 = pd.DataFrame({ 'Name': ['ZYMAXID 9416X', 'ZYPRED'], 'id': [6390, 6391] }) df2 = pd.DataFrame({ 'label': ['ZYPRED', None], 'pref_label': [None, 'ZYMAXID 9416X'], 'alt_label': [None, None] })
期望合并结果:
Name id label pref_label alt_label 0 ZYMAXID 9416X 6390 None ZYMAXID 9416X None 1 ZYPRED 6391 ZYPRED None None
我尝试了以下代码,但报错:
df = df1.merge(df2, left_on=df1["Name"].str.lower(), right_on=['df2["label"].str.lower()','df2["pref_label"].str.lower()''df2["alt_label"].str.lower()', indicator = True)
解决方案
你的代码存在几个问题:
right_on参数要求传入的序列长度与left_on一致,不能直接传递多列的序列数组- 字符串语法错误:
'df2["pref_label"].str.lower()''df2["alt_label"].str.lower()'中间缺少逗号,且不该用字符串包裹序列表达式
下面提供两种可行的解决方法:
方法一:添加匹配键列后合并
这种方法直接给两个DataFrame添加统一的小写匹配键,再进行合并,逻辑更直观:
# 给df1添加小写匹配键 df1['match_key'] = df1['Name'].str.lower() # 给df2生成匹配键:遍历label、pref_label、alt_label,取第一个非空值转小写 df2['match_key'] = df2.apply( lambda row: next((val.lower() for val in [row['label'], row['pref_label'], row['alt_label']] if val is not None), None), axis=1 ) # 基于匹配键合并,最后删除临时键列 result = df1.merge(df2, on='match_key', how='left').drop('match_key', axis=1)
方法二:转长格式匹配后恢复宽格式
如果需要更灵活的多列匹配,可以先把df2转成长格式,匹配后再转回宽格式:
# 将df2的多列转成长格式,保留原行索引 melted_df2 = df2.melt(var_name='col_name', value_name='match_val', ignore_index=False) # 过滤空值并转小写 melted_df2 = melted_df2[melted_df2['match_val'].notna()] melted_df2['match_val'] = melted_df2['match_val'].str.lower() # 给df1添加小写匹配列 df1['Name_lower'] = df1['Name'].str.lower() # 合并后转回宽格式 merged = df1.merge(melted_df2, left_on='Name_lower', right_on='match_val', how='left') result = merged.pivot(index=['Name', 'id'], columns='col_name', values='match_val').reset_index() # 填充空值并调整列顺序与期望结果一致 result = result.fillna(None)[['Name', 'id', 'label', 'pref_label', 'alt_label']]
两种方法都能得到你需要的合并结果,方法一更为简洁,适合当前场景。
内容的提问来源于stack exchange,提问作者rshar
相关产品推荐
相关产品推荐

