pd.read_csv()读取浮点数不一致是因float64精度限制所致,ieee 754双精度仅支持15–17位有效数字,超出部分被截断或舍入;推荐用dtype='string'保留原始字符串,再按需转decimal处理。

为什么 pd.read_csv() 读出来的浮点数和原始文件不一致?
这不是 Pandas 的 bug,而是底层用 float64 解析字符串时的固有行为。CSV 里存的是 "0.1234567890123456789" 这样的字符串,Pandas 默认调用 C 库(如 strtod)转成 float64,而 IEEE 754 双精度最多精确到约 15–17 位有效数字。超出部分直接截断或舍入,比如 0.1234567890123456789 可能变成 0.12345678901234568。
常见错误现象:df['price'].iloc[0] == 0.1234567890123456789 返回 False;做等值 join 或 groupby 时意外漏掉数据;导出回 CSV 后数值“变样”。
- 不要依赖默认的
dtype=float—— 它是float64,不是任意精度 - 如果原始数据本质是“高精度小数”(如金融价格、地理坐标),优先考虑用字符串或
decimal类型承载 -
pd.read_csv(..., dtype={'col': 'string'})是最轻量、最安全的兜底方案
用 dtype='string' 保留原始文本再按需转换
这是最推荐的第一步:先不解析,把字段当纯文本读进来,后续在真正需要计算时再用 decimal.Decimal 或带精度控制的函数处理。
import pandas as pd
from decimal import Decimal
<p>df = pd.read_csv('data.csv', dtype={'amount': 'string', 'lat': 'string', 'lng': 'string'})</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill8910" title="361SCAN security check your skill python scripts"><img
src="https://img.php.cn/upload/skill/000/000/081/179231049778675.jpg" alt="361SCAN security check your skill python scripts" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill8910" title="361SCAN security check your skill python scripts" class="overflowclass">361SCAN security check your skill python scripts</a>
<p class="overflowclass">扫描并分析已安装技能,用于查看指定技能目录的名称、描述和详情,或列出所有已安装的技能。</p>
</div>
<a rel="nofollow" href="/xiazai/skill8910" title="361SCAN security check your skill python scripts" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div><h1>此时 df['amount'].iloc[0] 就是原始字符串,无任何精度损失</h1><h1>需要计算时才转 Decimal(注意:不能直接 float())</h1><p>df['amount_dec'] = df['amount'].apply(lambda x: Decimal(x) if pd.notna(x) else None)
</p>
-
'string'是 Pandas 1.0+ 引入的专用字符串 dtype,比object更明确、更安全 - 避免在
apply中用float(x)—— 它又回到float64精度陷阱 - 如果只是做排序或范围筛选,
string列配合str.startswith()或正则也能应付大部分非计算场景
用 converters + Decimal 替代默认浮点解析
如果你必须在读取阶段就得到高精度数值(比如后续要大量算术运算),可以用 converters 参数接管单列解析逻辑,绕过 Pandas 内部的 float64 转换路径。
from decimal import Decimal
import pandas as pd
<p>def to_decimal(x):
return Decimal(x) if x.strip() else None</p><p>df = pd.read_csv(
'data.csv',
converters={'price': to_decimal, 'quantity': to_decimal},</p><h1>注意:此时不能同时设 dtype={'price': 'float64'},会冲突</h1><p>)
</p>
-
converters的函数接收原始字符串,执行时机早于 dtype 推断,完全可控 -
Decimal支持任意精度算术,但 Pandas 对Decimal列的支持有限:不支持.mean()、.sum()等聚合(会回退到 object 操作,慢且易错) - 若需聚合,建议转成
numpy.object_数组后用原生sum()/statistics.mean()处理,而不是依赖 Pandas 方法
别碰 float_precision='round_trip' —— 它不解决精度丢失
这个参数常被误解为“高精度浮点读取”,其实它只影响 写入再读回 场景下的字符串还原能力,对原始 CSV 中已存在的长浮点数无效。
例如:你用 pd.to_csv(float_format='%.20f') 导出一个 float64 值,再用 float_precision='round_trip' 读回来,能还原出相同的字符串表示(比如 "0.12345678901234568000"),但它仍是那个已经丢失精度的 float64 值。
-
float_precision='high'和'round_trip'都不改变底层存储类型,仍是float64 - 它们只在极少数“导出→人工编辑→再导入”流程中有点用,对真实高精度数据毫无帮助
- 真要保精度,唯一可靠路径是:字符串进 → 按需转 Decimal/整数 → 显式控制运算上下文
最易被忽略的一点:很多人以为“只要显示正常就没事”,但 print(df['x'].iloc[0]) 默认只显示 6 位小数,掩盖了底层 float64 实际存储的误差。验证精度是否丢失,一定要用 repr() 或 np.format_float_positional(x, precision=17) 看完整表示。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










