如何高效实现基于子串匹配为Pandas DataFrame分配商户名称?
优化交易商户匹配方案
你的双重循环虽然能实现功能,但iterrows本身效率较低,且嵌套循环代码冗余,这里提供几种更高效简洁的方案:
方案1:构建映射字典 + 字符串提取(推荐)
利用pandas矢量化操作,先将商户缩写与名称转为字典,再通过正则提取匹配的缩写并映射到商户名称,性能远优于循环。
import pandas as pd import re data = {'Date': ['31/07/2023', '31/07/2023', '30/07/2023', '29/07/2023'], 'Concept': ['Compra Uber *eats, Help.uber.com', 'Compra Amzn Mktp Es*k46q26ow5, Luxembourg', 'Compra Uber *eats, Help.uber.com', 'Recibo Orange Espagne S.a.u-orange Espagne Sa Nº'], 'Amount':[-10,-12,-15,-22]} df = pd.DataFrame(data) df_merch = pd.read_csv(r'C:\new\acct\mercants.csv') # 构建缩写到商户名称的映射字典 merch_map = df_merch.set_index('abr')['name'].to_dict() # 生成正则匹配式:转义缩写中的特殊字符,避免正则语法冲突 pattern = '|'.join([re.escape(abr) for abr in merch_map.keys()]) # 提取匹配的缩写并映射得到商户名称 df['Merchant'] = df['Concept'].str.extract(f'({pattern})', expand=False).map(merch_map)
说明:
re.escape用于处理缩写中的特殊字符(如*、.),确保匹配准确- 正则匹配会返回第一个命中的缩写,和原代码
break的逻辑一致
方案2:apply + 字典查找
如果需要灵活扩展匹配规则(比如大小写不敏感),可以用apply结合字典遍历,代码比嵌套循环更简洁:
import pandas as pd data = {'Date': ['31/07/2023', '31/07/2023', '30/07/2023', '29/07/2023'], 'Concept': ['Compra Uber *eats, Help.uber.com', 'Compra Amzn Mktp Es*k46q26ow5, Luxembourg', 'Compra Uber *eats, Help.uber.com', 'Recibo Orange Espagne S.a.u-orange Espagne Sa Nº'], 'Amount':[-10,-12,-15,-22]} df = pd.DataFrame(data) df_merch = pd.read_csv(r'C:\new\acct\mercants.csv') merch_map = df_merch.set_index('abr')['name'].to_dict() def match_merchant(concept): for abr, name in merch_map.items(): # 可修改为if abr.lower() in concept.lower()实现大小写不敏感匹配 if abr in concept: return name return None # 无匹配时返回空值 df['Merchant'] = df['Concept'].apply(match_merchant)
方案3:np.select 矢量化匹配
利用numpy的select函数批量设置匹配条件与对应值,完全避免循环:
import pandas as pd import numpy as np data = {'Date': ['31/07/2023', '31/07/2023', '30/07/2023', '29/07/2023'], 'Concept': ['Compra Uber *eats, Help.uber.com', 'Compra Amzn Mktp Es*k46q26ow5, Luxembourg', 'Compra Uber *eats, Help.uber.com', 'Recibo Orange Espagne S.a.u-orange Espagne Sa Nº'], 'Amount':[-10,-12,-15,-22]} df = pd.DataFrame(data) df_merch = pd.read_csv(r'C:\new\acct\mercants.csv') # 生成条件列表与对应商户名称列表 conditions = [df['Concept'].str.contains(abr, regex=False) for abr in df_merch['abr']] values = df_merch['name'].tolist() # 批量匹配并设置默认值 df['Merchant'] = np.select(conditions, values, default=None)
说明:
str.contains的regex=False参数确保缩写中的特殊字符被当作普通文本处理- 条件列表的顺序决定匹配优先级,与原代码循环顺序一致
方案优势总结
- 性能提升:避免
iterrows逐行处理,矢量化操作在大数据量下性能可提升几十倍 - 代码简洁:逻辑清晰,减少冗余代码,便于维护
- 扩展性强:可轻松添加大小写不敏感、特殊字符适配等规则
内容的提问来源于stack exchange,提问作者Vaidas
相关产品推荐
相关产品推荐

