You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

嵌套循环与嵌套if语句中的KeyError异常排查

问题分析与解决方案

让我来帮你拆解这个问题,你遇到的KeyError: 9和大量的"No match found"提示,其实是几个常见的pandas操作误区和循环逻辑漏洞导致的,我逐个给你说明:

1. KeyError的核心原因:错误的DataFrame赋值方式

你代码里用dgh[i]['crm_ref'] = accountnumber来赋值是链式索引的错误用法。dgh[i]会尝试从DataFrame中取名为i(这里是行索引9)的列,而不是定位第i行;当你的列名里没有9时,自然就抛出了KeyError。

正确的赋值方式应该用:

  • .loc[i, 'crm_ref']:通过行索引+列名定位赋值(最推荐)
  • .at[i, 'crm_ref']:针对单个标量值的快速赋值

2. 嵌套循环的变量冲突

你在父循环和所有子循环里都用了row变量:

for i, row in dgh.iterrows():
    # ...
    for u, row in temp_key.iterrows():
        # ...

这会直接覆盖父循环的row变量,虽然不是触发KeyError的直接原因,但会导致代码可读性极差,容易引发其他逻辑混乱,建议给子循环的行变量换个名字,比如temp_row。

3. 子循环过早退出,导致匹配失败

在每个子循环的else分支里,你直接写了break:

else:
    break

这意味着只要第一行不匹配,就直接退出子循环,根本不会检查temp_key或temp_city里的其他行——这就是为什么你会看到大量"No match found"的原因:明明可能有后续行能匹配,却被提前终止了。应该去掉这个else里的break,让循环遍历完所有可能的匹配项。

4. NaN判断的错误用法

你用math.isnan(dgh.iloc[i]['crm_ref'])来判断是否匹配成功,但如果crm_ref列的初始类型不是float(比如是object类型的空字符串),math.isnan会抛出TypeError。建议用pandas自带的pd.isna()来判断缺失值,兼容性更好。


修复后的完整代码

import pandas as pd
from fuzzywuzzy import fuzz

# 先确保dgh里有crm_ref列,没有就初始化
if 'crm_ref' not in dgh.columns:
    dgh['crm_ref'] = pd.NA

for i, dgh_row in dgh.iterrows():
    dgh_key = dgh_row['addresskey']
    dgh_name = dgh_row['DGH_custname']
    match_found = False

    # 第一步:按addresskey匹配
    temp_key = crm.loc[crm['addresskey'] == dgh_key].reset_index(drop=True)
    for u, temp_row in temp_key.iterrows():
        crm_name = temp_row['name']
        accountnumber = temp_row['accountnumber']
        # 合并三种模糊匹配条件,满足任一即匹配
        if (fuzz.ratio(dgh_name.lower(), crm_name.lower()) >= 60 or
            fuzz.partial_ratio(dgh_name.lower(), crm_name.lower()) >= 90 or
            fuzz.token_set_ratio(dgh_name.lower(), crm_name.lower()) >= 90):
            dgh.loc[i, 'crm_ref'] = accountnumber
            match_found = True
            break  # 找到匹配就退出子循环
    
    if match_found:
        continue  # 找到匹配就直接进入下一个父循环
    
    # 第二步:按城市匹配
    dgh_city = dgh_row['DGH_custcity']
    temp_city = crm.loc[crm['address1_city'] == dgh_city].reset_index(drop=True)
    for y, temp_row in temp_city.iterrows():
        crm_name = temp_row['name']
        accountnumber = temp_row['accountnumber']
        if (fuzz.ratio(dgh_name.lower(), crm_name.lower()) >= 60 or
            fuzz.partial_ratio(dgh_name.lower(), crm_name.lower()) >= 90 or
            fuzz.token_set_ratio(dgh_name.lower(), crm_name.lower()) >= 90):
            dgh.loc[i, 'crm_ref'] = accountnumber
            match_found = True
            break
    
    if not match_found:
        print(f'No match found for row {i}: {dgh_name}')

额外优化建议

  • 尽量避免用iterrows(),它的运行效率很低,对于大数据集可以用apply()或者向量化操作替代
  • 可以把模糊匹配的逻辑封装成一个独立函数,减少代码重复
  • 如果crm数据集很大,建议先对addresskey和address1_city建立索引,能大幅提升查询速度

内容的提问来源于stack exchange,提问作者Fabio D'Elfant

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 18:52:37