如何基于id、email、手机号三列分别匹配合并两个DataFrame?
解决任意列匹配的DataFrame合并问题
你之前用的merge写法要求id、email、手机号三列同时匹配才会合并,这就是为啥只返回三列都匹配的行。要实现任意一列匹配就合并,得换个思路:分别按每一列单独匹配,再整合结果去重。
具体实现步骤(附代码)
假设你的两个DataFrame列结构如下:
- df1:包含
id、email、mobile及业务列(如user_name、register_date) - df2:包含
id、email、mobile及需要合并的业务列(如order_count、vip_level)
方法一:分三次匹配后合并去重
先分别按单个匹配键做左连接,再合并结果并去重,确保每个df1的行只保留一次有效匹配:
import pandas as pd # 1. 分别按id、email、手机号做左连接,只保留匹配成功的行 merge_id = df1.merge(df2, on='id', how='left', suffixes=('', '_y')) merge_id = merge_id.dropna(subset=[col for col in df2.columns if col != 'id']) merge_email = df1.merge(df2, on='email', how='left', suffixes=('', '_y')) merge_email = merge_email.dropna(subset=[col for col in df2.columns if col != 'email']) merge_mobile = df1.merge(df2, on='mobile', how='left', suffixes=('', '_y')) merge_mobile = merge_mobile.dropna(subset=[col for col in df2.columns if col != 'mobile']) # 2. 合并三次匹配结果,按df1的核心标识去重 combined = pd.concat([merge_id, merge_email, merge_mobile], ignore_index=True) combined = combined.drop_duplicates(subset=['id', 'email', 'mobile'], keep='first') # 3. 补充df1中未匹配到的行 final_df = df1.merge(combined, on=['id', 'email', 'mobile'] + [col for col in df1.columns if col not in ['id', 'email', 'mobile']], how='left') # 清理重复列(去掉带_y后缀的临时列) final_df = final_df.loc[:, ~final_df.columns.str.endswith('_y')]
方法二:用combine_first填充缺失值(更简洁)
如果df2中同一匹配键对应的数据唯一,可通过多次合并后填充缺失值实现:
# 依次按三个键合并,生成带后缀的临时列 df_merged = df1.merge(df2, on='id', how='left', suffixes=('', '_id')) df_merged = df_merged.merge(df2, on='email', how='left', suffixes=('', '_email')) df_merged = df_merged.merge(df2, on='mobile', how='left', suffixes=('', '_mobile')) # 用combine_first优先填充非空值,优先保留先匹配到的结果 for col in df2.columns: df_merged[col] = df_merged[col].combine_first(df_merged[f'{col}_email']).combine_first(df_merged[f'{col}_mobile']) # 删除临时后缀列 df_merged = df_merged.drop([col for col in df_merged.columns if '_id' in col or '_email' in col or '_mobile' in col], axis=1)
注意事项
- 确保匹配列格式一致:比如手机号统一为字符串、去掉空格,email统一大小写,避免因格式问题匹配失败
- 若同一df1行能匹配到多个df2行,需根据业务逻辑调整去重规则(比如
keep='last'保留最后一次匹配,或自定义筛选逻辑)
内容的提问来源于stack exchange,提问作者Salem Shehabeddin
相关产品推荐
相关产品推荐

