Pandas实现两DataFrame部分匹配合并时IndexError报错排查
报错原因定位
报错触发的直接原因是:循环匹配过程中,存在某条Invoice值在df2['Ref']字段中没有任何符合contains匹配规则的记录,此时筛选得到的tmp是空DataFrame,对空结果直接取tmp['Amount'].values[0]相当于从长度为0的数组中取第一个元素,直接抛出索引越界错误。
另外你当前使用的逐行iterrows遍历写法性能极差,你提到df2有62万行数据,这种写法的运行耗时会非常长,完全不适合大数据量场景。
高效实现方案(推荐,适配62万行数据场景)
不要用逐行循环,用向量化的正则提取+等值合并逻辑,运行效率比循环高两个数量级以上,同时自动处理无匹配的场景,不会触发索引报错:
import pandas as pd import re # 1. 构造匹配正则,将df1中所有发票号拼接为或匹配模式 inv_pattern = '|'.join(re.escape(inv_num) for inv_num in df1['Invoice'].unique()) # 2. 从df2的Ref字段中提取匹配到的发票号,无匹配则返回空值 df2['match_key'] = df2['Ref'].str.extract(f'({inv_pattern})', expand=False) # 3. 按匹配到的键做左连接合并,最后删掉临时生成的匹配键列 df_result = df1.merge( df2, left_on='Invoice', right_on='match_key', how='left' ).drop(columns=['match_key'])
运行后得到的合并结果和预期完全一致:
Invoice Currency Ref Type Amount Comment 0 20561 EUR 20561 01 150 bla 1 20562 EUR INV20562 03 175 bla 2 20563 EUR INV20563BG 04 160 bla 3 20564 USD 20564 02 180 bla
如果存在某条Invoice在df2中完全匹配不到,对应df2的字段会自动填充为空值,不会触发报错。
原循环逻辑的修正方案(不推荐,仅作参考)
如果一定要保留遍历写法,必须在取值前判断匹配结果是否为空,避免取空数组的元素:
df4 = df1.copy() for i, row in df1.iterrows(): match_res = df2[df2['Ref'].str.contains(row['Invoice'], na=False)] # 先判断是否存在匹配结果再赋值 if len(match_res) > 0: df4.loc[i, 'Amount'] = match_res['Amount'].iloc[0] else: df4.loc[i, 'Amount'] = pd.NA
注意:这个方案仅适合极小数据量场景,62万行数据下运行速度会非常慢,优先使用前面的向量化合并方案。
内容的提问来源于stack exchange,提问作者Mojumder
相关产品推荐
相关产品推荐

