Pandas批量处理CSV报KeyError指定列不存在问题排查
问题根因
报错和glob本身无关,是代码逻辑错误导致的,具体问题点:
- 代码拆成了两个独立的
for fp in files循环,逻辑完全断裂:第一个循环仅逐个读取CSV,df.to_csv没有加括号、没有传入输出参数,根本不会执行写入,读完的df也没有做任何持久化保存。第一个循环结束后,df变量仅保留最后一次遍历到的文件内容,第二个循环遍历文件列表时,根本没有重新读取当前路径对应的文件,全程在反复操作同一个残留的df对象。 - 触发KeyError的直接原因:
glob.glob()的匹配范围包含了你用来做映射的df2源文件。第一个循环读取到这个映射文件时,强行通过names参数给它指定了业务表的29个固定列名,直接覆盖了映射表原本的status/stati/sparte/sparten等列结构,等执行df2[['status','stati']]选取列时,df2的列已经被篡改,自然找不到对应列。单文件测试时不会把映射表本身作为待处理文件读入覆盖结构,所以可以正常运行。 - 其他隐藏bug:第二个循环里每次迭代都执行
df2 = df2.fillna(0)属于无意义重复操作;最后关联gesellschaft字段时right_on直接传入了Series对象而非列名,运行到该步会触发新的报错;所有to_csv调用都没有实际执行,不会生成结果文件。
修复方案
- 合并两个拆分的循环,每个文件的读取、转换、写入在单次循环内完成
- 增加过滤逻辑,避免glob把映射表文件纳入待处理列表
- 修正merge参数错误,补全文件写入逻辑
修复后可直接运行的代码:
import glob import pandas as pd import os # 读取映射表,该文件不要放在待处理CSV的目录下,避免被glob误匹配 df2 = pd.read_csv(r'映射表CSV的完整路径') df2 = df2.fillna(0) # 映射表空值填充仅需执行一次,不要放在循环内 # 匹配所有待处理CSV files = glob.glob(r'待处理CSV所在目录\*.csv') # 保险过滤:如果映射表和待处理文件在同目录,手动排除 map_file_abs = os.path.abspath(r'映射表CSV的完整路径') files = [fp for fp in files if os.path.abspath(fp) != map_file_abs] for fp in files: # 读取当前待处理业务文件 df = pd.read_csv( fp, names=["vermittler", "vermittler 2", "vermittler 3", "kunde", "nachname", "vorname", "strasse", "plz", "ort", "geburtsdatum", "beruf", "land", "per_du", "login", "login 2", "nationalitaet", "rechtsform", "id", "versicherungsscheinnummer", "sparte", "gesellschaft", "zahlweise", "beginn", "ablauf", "beitrag_netto", "status", "risiko", "antragsdatum", "stornodatum"], sep=',', on_bad_lines='skip' ) df = df.fillna(0) df['gesellschaft'] = df['gesellschaft'].astype(object) # 关联status字段映射 df3 = pd.merge( df, df2[['status', 'stati']].astype(object), on='status', how='left' ).drop(columns=['status']) df3.rename({'stati': 'status'}, axis=1, inplace=True) # 关联sparte字段映射 df4 = df3.merge( df2[['sparte', 'sparten']].astype(object), on='sparte', how='left' ).drop(columns=['sparte']) df4.rename({'sparten': 'sparte'}, axis=1, inplace=True) # 关联gesellschaft字段映射,修正原right_on传参错误 df5 = df4.merge( df2[['gesellschaft', 'gesellschaften']].astype(object), on='gesellschaft', how='left' ).drop(columns=['gesellschaft']) df5.rename({'gesellschaften': 'gesellschaft'}, axis=1, inplace=True) # 写入处理后的文件,默认保存在原目录,文件名加_processed后缀 output_path = fp.replace('.csv', '_processed.csv') df5.to_csv(output_path, index=False, encoding='utf-8-sig')
验证要点
- 循环内每次重新读取当前遍历到的文件,不会出现变量残留问题
- 映射表仅读取一次,不会被业务文件的读取逻辑篡改列结构
- 所有字段关联逻辑和单文件测试逻辑完全一致,不会出现行为差异
- 补全了文件写入逻辑,处理完成后会在原目录生成对应结果文件
内容的提问来源于stack exchange,提问作者Anthony Admin
相关产品推荐
相关产品推荐

