Pandas多表字符串匹配效率优化:替代iterrows循环的高效方案
Pandas多条件匹配的高效优化方案
当Table1(3.5w行)和Table2(5k行)用嵌套iterrows+fnmatch实现匹配时,逐行循环的O(M*N)时间复杂度会导致效率极低。以下是几个针对性的优化方案:
1. 预处理倒排索引(最快实现)
先为Table1构建单词/组合到ID的映射字典,后续直接通过字典查询匹配结果,避免重复遍历Table1。
代码示例
# 构建Column C单词到ID的倒排索引 c_word_to_ids = {} for idx, row in Table1.iterrows(): word = row['Column C'] c_word_to_ids.setdefault(word, []).append(idx) # 构建Column C+Column D组合到ID的倒排索引 cd_pair_to_ids = {} for idx, row in Table1.iterrows(): key = (row['Column C'], row['Column D']) cd_pair_to_ids.setdefault(key, []).append(idx) # 批量生成Table2的目标列 Table2['Column E'] = Table2['Column C'].map(lambda x: c_word_to_ids.get(x, [])) Table2['Column F'] = Table2.apply( lambda row: cd_pair_to_ids.get((row['Column C'], row['Column D']), []), axis=1 )
- 核心优势:仅遍历Table1两次,后续查询为O(1)字典查找,5k行Table2的处理耗时几乎可忽略。
2. 向量化字符串匹配(简洁高效)
利用Pandas内置的str.contains向量化方法替代逐行循环,结合布尔索引筛选ID,代码简洁且性能远超iterrows。
代码示例(包含匹配)
# 生成Column E:Table1中包含Table2每行Column C的ID Table2['Column E'] = Table2['Column C'].apply( lambda x: Table1[Table1['Column C'].str.contains(x, case=False, na=False)].index.tolist() ) # 生成Column F:同时包含Column C和Column D的ID Table2['Column F'] = Table2.apply( lambda row: Table1[ (Table1['Column C'].str.contains(row['Column C'], case=False, na=False)) & (Table1['Column D'].str.contains(row['Column D'], case=False, na=False)) ].index.tolist(), axis=1 )
精确匹配版本(更快)
如果需求是精确匹配而非包含,直接用==替代str.contains:
Table2['Column E'] = Table2['Column C'].apply( lambda x: Table1[Table1['Column C'] == x].index.tolist() )
- 核心优势:无需手动构建字典,代码易读,性能比
iterrows提升10-100倍。
3. NumPy布尔矩阵加速(极致性能)
将字符串匹配转换为NumPy布尔矩阵,利用底层C实现的矩阵运算批量获取匹配ID,适合超大数据集场景。
代码示例
import numpy as np # 提取目标列的NumPy数组 t1_c = Table1['Column C'].values t2_c = Table2['Column C'].values t1_d = Table1['Column D'].values t2_d = Table2['Column D'].values # 生成Column E的匹配矩阵(Table2每行 vs Table1所有行) match_c = np.char.find(t1_c.reshape(1, -1), t2_c.reshape(-1, 1)) != -1 Table2['Column E'] = [Table1.index[mask].tolist() for mask in match_c] # 生成Column F的组合匹配矩阵 match_d = np.char.find(t1_d.reshape(1, -1), t2_d.reshape(-1, 1)) != -1 match_cd = match_c & match_d Table2['Column F'] = [Table1.index[mask].tolist() for mask in match_cd]
- 核心优势:NumPy的底层运算比Pandas更高效,适合数据量突破10w级的场景。
4. Dask分布式处理(超大数据量)
如果数据量超过内存限制,用Dask DataFrame替代Pandas,自动拆分数据到多核心/集群并行处理,解决内存不足问题。
代码示例
import dask.dataframe as dd # 读取数据为Dask DataFrame(支持本地文件/云存储) dask_t1 = dd.read_csv('table1.csv') dask_t2 = dd.read_csv('table2.csv') # 定义匹配函数 def get_matching_ids_c(c_val): return dask_t1[dask_t1['Column C'].str.contains(c_val)].index.compute().tolist() def get_matching_ids_cd(row): return dask_t1[ (dask_t1['Column C'].str.contains(row['Column C'])) & (dask_t1['Column D'].str.contains(row['Column D'])) ].index.compute().tolist() # 应用函数并计算结果 dask_t2['Column E'] = dask_t2['Column C'].apply(get_matching_ids_c, meta=object) dask_t2['Column F'] = dask_t2.apply(get_matching_ids_cd, axis=1, meta=object) result_df = dask_t2.compute()
- 核心优势:自动处理数据分片与并行计算,支持TB级数据处理。
内容的提问来源于stack exchange,提问作者petchde
相关产品推荐
相关产品推荐

