pandas中键列拼写不一致时合并两个dataframe的问题咨询
问题原因分析与修复方案
1. 第一个报错 TypeError: expected string or bytes-like object 原因与修复
原因
虽然你确认FULL_NAME是object类型,但pandas的object列允许混合存储多种类型,只要列里存在NaN、None等空值,或者个别值是数字/布尔等非字符串类型,传入fuzzywuzzy的匹配函数时就会触发类型错误。
修复前置步骤:统一预处理姓名列
先对两个表的姓名列做标准化处理,同时解决你提到的多余空格、前缀问题,也避免类型错误:
import pandas as pd import re from fuzzywuzzy import fuzz from fuzzywuzzy import process import difflib def clean_name(name): # 先处理空值,转成空字符串 if pd.isna(name): return "" # 强制转成字符串类型 name = str(name) # 去掉所有多余空格(前后空格、中间连续多空格) name = re.sub(r'\s+', ' ', name.strip()) # 去掉Mr. Ms. Mrs. Dr. 这类前缀,可根据自身场景补充更多前缀规则 name = re.sub(r'^(Mr\.|Ms\.|Mrs\.|Dr\.|Prof\.)\s', '', name, flags=re.IGNORECASE) return name # 对两个表的姓名列做清洗 df1['clean_name'] = df1['FULL_NAME'].apply(clean_name) df2['clean_name'] = df2['FULL_NAME'].apply(clean_name) # 过滤掉清洗后是空字符串的无效行,避免无效匹配 df1_valid = df1[df1['clean_name'] != ''].copy() df2_valid = df2[df2['clean_name'] != ''].copy()
2. 第二个报错 IndexError: list index out of range 原因与修复
原因
difflib.get_close_matches 如果没有找到符合相似度阈值的匹配项,会返回空列表,直接取[0]就会触发索引越界错误;同理fuzzywuzzy的process.extractOne如果找不到匹配会返回None,直接取[0]也会报错。
修复匹配逻辑
匹配时先判断是否有返回结果,没有的话填占位值(比如无匹配),避免报错:
模糊匹配代码(fuzzywuzzy版本,对姓名缺字、顺序颠倒场景适配更好)
def get_best_match(name, candidate_list, threshold=80): # threshold为匹配相似度阈值,范围0-100,分数越高匹配越严格,可根据效果调整 match_res = process.extractOne(name, candidate_list, scorer=fuzz.token_sort_ratio) if match_res and match_res[1] >= threshold: return match_res[0] else: return "无匹配" # 执行匹配 df1_valid['best_match_clean'] = df1_valid['clean_name'].apply( lambda x: get_best_match(x, df2_valid['clean_name'].tolist()) ) # 将匹配到的清洗后姓名关联回df2的原始信息,完成合并 merged_df = df1_valid.merge( df2_valid, left_on='best_match_clean', right_on='clean_name', how='left', suffixes=('_df1', '_df2') )
模糊匹配代码(difflib版本)
def get_close_match(name, candidate_list, cutoff=0.6): # cutoff为相似度阈值,范围0-1,越高匹配越严格,可根据效果调整 matches = difflib.get_close_matches(name, candidate_list, n=1, cutoff=cutoff) return matches[0] if matches else "无匹配" df1_valid['best_match_clean'] = df1_valid['clean_name'].apply( lambda x: get_close_match(x, df2_valid['clean_name'].tolist()) ) # 合并逻辑和上述fuzzywuzzy版本一致 merged_df = df1_valid.merge( df2_valid, left_on='best_match_clean', right_on='clean_name', how='left', suffixes=('_df1', '_df2') )
内容的提问来源于stack exchange,提问作者elle_elle_cee
相关产品推荐
相关产品推荐

