pandas read_csv设置keep_default_na时thousands参数失效报错
问题根因
这是pandas 1.5.0版本之前C解析器的已知缺陷:当同时配置keep_default_na=False、显式传入dtype参数,且CSV文件中存在连续全空行时,解析器在处理完空行后会重置quotechar、thousands的解析状态,导致后续行里被引号包裹、带千分位分隔符的数值不会被提前清洗,直接传入类型转换逻辑时就会抛出ValueError: could not convert string to float: '1,917.6'的错误。
你测试时发现的两个现象完全匹配这个缺陷的触发逻辑:
- 删除所有全空行后,解析状态不会被异常重置,千分位、引号解析规则正常生效
- 只要存在
,,,,,,格式的全空行,空行之后的所有行都会丢失千分位处理能力
解决方案
按实际场景选以下任意一种方案即可:
- 优先方案:升级pandas版本到1.5.0及以上
该解析缺陷在1.5.0版本已被官方修复,升级后原有代码不需要做任何修改即可正常运行。 - 规避方案1:切换解析引擎
不方便升级pandas时,在读入参数中增加engine='python',使用Python原生解析器替代默认的C解析器,不会触发状态重置的bug,修改后的代码如下:import pandas as pd import numpy as np df = pd.read_csv('test.csv', skiprows=1, quotechar='"', thousands=',', keep_default_na=False, engine='python', dtype = {'Open': np.float64, 'High': np.float64, 'Low': np.float64, 'Close': np.float64, 'Volume': np.uint32, 'Symbol': 'string'}) - 规避方案2:延后类型转换
读入阶段先不指定数值列的dtype,等解析器完成千分位处理、空值识别后,再手动转换列类型,示例代码如下:import pandas as pd import numpy as np # 第一阶段:只指定字符串列类型,完成数值解析 df = pd.read_csv('test.csv', skiprows=1, quotechar='"', thousands=',', keep_default_na=False, dtype = {'Symbol': 'string'}) # 第二阶段:单独转换数值列类型,Volume列空值可按业务需求填充默认值 float_cols = ['Open', 'High', 'Low', 'Close'] df[float_cols] = df[float_cols].astype(np.float64) df['Volume'] = df['Volume'].replace('', 0).astype(np.uint32) - 规避方案3:预处理CSV文件
读入文件前先预处理删除所有全空行,也可以绕过这个解析缺陷,适合不方便调整pandas环境和读入逻辑的场景。
内容的提问来源于stack exchange,提问作者misantroop
相关产品推荐
相关产品推荐

