Numpy字符串转换时为何会出现数字截断异常?
Numpy浮点数转字符串时的诡异截断问题解析
这绝对是numpy旧版本里一个非常隐蔽的bug,我之前也碰到过类似精度相关的奇怪问题,来帮你理清楚到底发生了什么:
问题复现与现象确认
首先,你的复现代码完全能重现这个问题——在Python 3.5.4 + numpy 1.14.2的环境下,将特定区间的浮点数存入U21类型的numpy数组时,指数部分会被错误截断为e-0,而不是正确的e-05,导致原本小于0.0001的数值看起来变成了0.4+,完全不符合预期。
import numpy as np p = np.empty([1,2],dtype='U21') a = 4.4226657709978134e-05 p[0] = np.array(['string',a]) print(p) # 输出:array([['string', '4.4226657709978134e-0']], dtype='<U21')
从你的测试用例能明确看到,这个问题和浮点数的最后一位小数直接相关:只有当数值落在4.4226657709978132e-05到4.4226657709978137e-05这个极小区间时,才会触发截断bug,超出这个区间的数值都能正常转换。
问题根源
这个问题本质上是numpy 1.14.x版本中浮点数到字符串转换模块的一个bug:
- 浮点数在计算机中是以二进制形式存储的,你测试的这些临界值刚好处于二进制浮点数的精度边界,numpy旧版本的格式化逻辑在解析这类数值的指数部分时出现了错误,导致指数的最后两位被意外截断。
- 这个bug在后续的numpy版本(比如1.15及以上)中已经被官方修复了,属于旧版本的遗留问题。
解决办法
根据你的使用场景,有几个可行的修复方案:
1. 升级numpy版本
这是最彻底的解决方式,直接升级到1.15.x及以上的稳定版本,就能完全避免这个bug。升级命令很简单:
pip install --upgrade numpy
2. 手动提前格式化浮点数
在将浮点数存入numpy数组之前,先用Python内置的str()或者format()函数把浮点数转换成字符串,跳过numpy自动转换的步骤:
import numpy as np p = np.empty([1,2],dtype='U21') a = 4.4226657709978134e-05 # 提前用str()转换浮点数 p[0] = np.array(['string', str(a)], dtype='U21') print(p) # 输出:array([['string', '4.4226657709978134e-05']], dtype='<U21')
3. 使用Pandas处理数据
正如你发现的,Pandas的字符串处理逻辑和numpy独立,不会出现这个问题,而且Pandas本身更适合处理大规模的结构化数据,对于你数百万条数据的场景来说,这也是一个很合适的选择。
内容的提问来源于stack exchange,提问作者roblanf
相关产品推荐
相关产品推荐

