Python Pandas子串匹配异常问题排查与修正
基于SKU精确匹配优先的DataFrame合并问题解决
问题背景
我有两个DataFrame(DFA和DFB),需要基于SKU列的精确匹配优先、无精确匹配时启用子串匹配的规则,将DFA中的Company列合并到DFB中。
现有实现代码
# 移除空格、特殊字符并转换数据类型为字符串 dfa['Clean SKU'] = dfa['SKU'].replace(r'[^0-9a-zA-Z ]', '', regex=True).replace("'", '') dfb['Clean SKU'] = dfb['SKU'].replace(r'[^0-9a-zA-Z ]', '', regex=True).replace("'", '') dfa['Clean SKU'] = dfa['Clean SKU'].replace(r'\s+', '', regex=True) dfb['Clean SKU'] = dfb['Clean SKU'].replace(r'\s+', '', regex=True) # 转换数据类型 dfa['Clean SKU'] = dfa['Clean SKU'].astype(str) dfb['Clean SKU'] = dfb['Clean SKU'].astype(str) # 创建用于合并的列并转换为小写 dfa['SKU_to_merge'] = dfa['Clean SKU'].str.lower() # 从Clean SKU列提取唯一列表生成匹配正则 pat = r'(%s)'%'|'.join(dfa['Clean SKU'].str.lower().unique()) # 创建匹配列 dfb['SKU_to_merge'] = dfb['Clean SKU'].str.lower().str.extract(pat) # 基于匹配列合并DataFrame dfb = dfb.merge(dfa[['SKU_to_merge','Company']], on='SKU_to_merge', how='left')
问题异常描述
对于SKU为601251x的记录,该SKU在DFA中存在,理应精确匹配601251x并关联Google公司,但实际错误匹配了Amazon。核心需求是:仅当无精确匹配时才启用子串匹配,需要修正该异常。
修正方案
问题出在原正则匹配未优先处理精确匹配,且未按SKU长度排序导致短SKU误匹配长SKU。解决思路是先执行精确匹配,对未匹配记录再按规则做子串匹配:
# 1. 统一清洗SKU(合并重复逻辑,转小写) dfa['Clean SKU'] = dfa['SKU'].replace(r'[^0-9a-zA-Z ]', '', regex=True)\ .replace("'", '').replace(r'\s+', '', regex=True)\ .astype(str).str.lower() dfb['Clean SKU'] = dfb['SKU'].replace(r'[^0-9a-zA-Z ]', '', regex=True)\ .replace("'", '').replace(r'\s+', '', regex=True)\ .astype(str).str.lower() # 2. 先执行精确匹配 dfb = dfb.merge(dfa[['Clean SKU', 'Company']], left_on='Clean SKU', right_on='Clean SKU', how='left', suffixes=('', '_exact')) # 3. 处理未精确匹配的记录,执行子串匹配 unmatched = dfb[dfb['Company'].isna()] if not unmatched.empty: # 按SKU长度倒序生成正则,优先匹配更长的SKU,避免短SKU误匹配 sorted_sku_list = sorted(dfa['Clean SKU'].unique(), key=len, reverse=True) match_pattern = r'(' + '|'.join(sorted_sku_list) + ')' unmatched['matched_sku'] = unmatched['Clean SKU'].str.extract(match_pattern, expand=False) # 合并子串匹配的Company数据 unmatched = unmatched.merge(dfa[['Clean SKU', 'Company']], left_on='matched_sku', right_on='Clean SKU', how='left', suffixes=('', '_sub')) # 用子串匹配结果填补空值 unmatched['Company'] = unmatched['Company_sub'].fillna(unmatched['Company']) # 将修正结果回填到原DFB dfb.loc[dfb['Company'].isna(), 'Company'] = unmatched['Company'] # 清理临时辅助列 dfb = dfb.drop(columns=['Company_exact', 'matched_sku', 'Company_sub', 'Clean SKU_y'], errors='ignore')
修正说明
- 先做精确匹配,确保存在完全一致的SKU能直接关联正确的Company;
- 子串匹配前按SKU长度倒序生成正则,优先匹配更长的SKU,避免短SKU(如
60125)误匹配包含它的长SKU(如601251x); - 仅对未精确匹配的记录执行子串匹配,严格遵循需求规则。
内容的提问来源于stack exchange,提问作者PythonBeginner
相关产品推荐
相关产品推荐

