np.savetxt 默认用 %.18e 格式导致精度丢失,因其固定宽度截断而非按有效数字保留;应改用 fmt='%.17g' 以保障 float64 无损 round-trip,或优先选用 np.save 实现真正无损。

为什么 np.savetxt 默认会丢精度
因为 np.savetxt 默认用 %.18e 格式(科学计数法),对浮点数做固定宽度截断,不是按有效数字保留。比如 0.1234567890123456789 可能被存成 1.2345678901234567e-01,再读回来就只剩 17 位左右——这不是四舍五入问题,是格式化阶段的硬截断。
常见错误现象:np.loadtxt 读回后和原数组 !=,尤其在高精度科学计算、坐标/时间戳场景下误差不可忽略。
- 默认行为不保留原始
float64的全部 15–17 位十进制有效数字 -
fmt='%.18e'看似够长,但指数部分占位、小数点前导零都会挤占有效位数 - 如果数组含
inf或nan,默认格式还可能输出为inf/nan字符串,后续读取时类型丢失
用 fmt='%.17g' 替代默认格式
g 格式比 e 更智能:自动在科学计数法和普通小数之间切换,并优先保留最多有效数字。17 是 float64 可靠表示十进制数的上限(IEEE 754 double 最多需要 17 位十进制数字才能无损 round-trip)。
实操建议:
- 显式指定
fmt='%.17g',不要依赖默认值 - 加
delimiter=','和newline='\n'避免 Windows 换行符干扰 - 若含整数列,
%.17g会自动输出为42而非42.000000000000000,更干净
示例:
np.savetxt('data.csv', arr, fmt='%.17g', delimiter=',', newline='\n')
需要绝对无损?改用 np.save + np.load
CSV 本质是文本交换格式,注定有解析开销和格式边界。如果目标只是“Python 进程间或同环境复现”,np.save 是真正无损、快速、原生支持的方案。
注意点:
-
np.save生成的是二进制.npy文件,不能用 Excel 打开,也不适合跨语言传输 - 保存时加
allow_pickle=False(默认已是 False),避免潜在安全风险 - 如需压缩,用
np.savez_compressed,体积通常比 CSV 小 50% 以上,且仍无损
示例:
np.save('data.npy', arr, allow_pickle=False)
必须用 CSV 且要兼容其他语言?手动转字符串再写
当 CSV 要被 MATLAB、R 或 C++ 程序读取,且对方解析器不支持高精度 g 格式时,最稳妥的方式是绕过 np.savetxt,用 Python 原生 csv 模块 + np.array2string 控制输出。
关键操作:
- 用
np.array2string(arr, separator=',', formatter={'float_kind': lambda x: f'{x:.17g}'})先转字符串 - 再用
csv.writer写入,确保每行字段数一致、引号规则合规 - 特别注意二维数组:需逐行处理,避免
array2string输出带括号和换行
这步容易踩坑:直接拼接字符串可能破坏 CSV 结构(比如字段含逗号或换行),所以仍推荐走标准 csv 模块流程。
精度问题的核心不在“怎么存”,而在“存完能不能原样读回来”。%.17g 覆盖绝大多数场景,但只要有一方不是 Python + NumPy,就得提前确认对方解析器的浮点字面量支持能力——这点常被忽略。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











