为什么numpy会在字符串转换时截断数字?

时间:2018-05-16 10:22:31

标签: python python-3.x numpy

一位合作者,我注意到一些奇怪的东西,我们不理解。这是使用Python 3.5.4和numpy版本1.14.2-py35ha9ae307_1(加上之前的一个,我更新以防万一)。

问题似乎是如果向一个numpy数组添加一个float以及一些字符串,float会按预期转换为字符串,但有时(非常罕见)float会以非常奇怪的方式被截断。我不知道这是一个错误还是一些我们不理解的行为。无论哪种方式,它似乎很奇怪。任何见解都会很有用。

可重复的示例

import numpy as np
p = np.empty([1,2],dtype='U21')
a = 4.4226657709978134e-05
p[0] = np.array(['string',a])
p

# WTF
Out[5]: array([['string', '4.4226657709978134e-0']], dtype='<U21')

这取决于浮动的最后一位数

# Works as expected
In [26]: np.array(['string',4.4226657709978130e-05], dtype='<U21')
Out[26]: array(['string', '4.422665770997813e-05'], dtype='<U21')

# Works as expected
In [27]: np.array(['string',4.4226657709978131e-05], dtype='<U21')
Out[27]: array(['string', '4.422665770997813e-05'], dtype='<U21')

# Doesn't work as expected
In [28]: np.array(['string',4.4226657709978132e-05], dtype='<U21')
Out[28]: array(['string', '4.4226657709978134e-0'], dtype='<U21')

# Doesn't work as expected
In [29]: np.array(['string',4.4226657709978133e-05], dtype='<U21')
Out[29]: array(['string', '4.4226657709978134e-0'], dtype='<U21')

# Doesn't work as expected
In [30]: np.array(['string',4.4226657709978134e-05], dtype='<U21')
Out[30]: array(['string', '4.4226657709978134e-0'], dtype='<U21')

# Doesn't work as expected
In [31]: np.array(['string',4.4226657709978135e-05], dtype='<U21')
Out[31]: array(['string', '4.4226657709978134e-0'], dtype='<U21')

# Doesn't work as expected
In [32]: np.array(['string',4.4226657709978136e-05], dtype='<U21')
Out[32]: array(['string', '4.4226657709978134e-0'], dtype='<U21')

# Doesn't work as expected
In [33]: np.array(['string',4.4226657709978137e-05], dtype='<U21')
Out[33]: array(['string', '4.4226657709978134e-0'], dtype='<U21')

# Works as expected
In [34]: np.array(['string',4.4226657709978138e-05], dtype='<U21')
Out[34]: array(['string', '4.422665770997814e-05'], dtype='<U21')

# Works as expected
In [35]: np.array(['string',4.4226657709978139e-05], dtype='<U21')
Out[35]: array(['string', '4.422665770997814e-05'], dtype='<U21')

这个问题很容易解决,例如通过切换到可以处理不同类型的Pandas数据帧。但这种行为似乎很奇怪。我们之所以注意到这一点,只是因为我们在数百万的数字上做了这个并且理智检查突出了它(我们所有的数字应该是&lt; 1,我们偶尔开始得到数字&gt; 1)。

2 个答案:

答案 0 :(得分:4)

这与Numpy无关。见https://stackoverflow.com/a/25899600/982257

Python(3)通常将浮点数表示为字符串,其中必须使用最少的数字来明确表示该特定的浮点值。

4.4226657709978137e-054.4226657709978138e-05的情况下,两者都没有完全由IEEE双打表示。在4.4226657709978137e-05的情况下,其最短的明确表示恰好是22个字符,而不是21个字符,因此当您尝试将其填充到<U21时,它会被截断。

要用科学记数法表示大多数双打,你需要至少24个字符。

答案 1 :(得分:1)

如果要在数组中混合字符串和浮点数,则无法使用pandas。对象dtype有效(这是pandas使用的)

In [394]: a = 4.4226657709978134e-05
In [395]: np.array(['string',a])
Out[395]: array(['string', '4.4226657709978134e-05'], dtype='<U22')
In [396]: np.array(['string',a], object)
Out[396]: array(['string', 4.4226657709978134e-05], dtype=object)

或结构化dtype:

In [398]: np.array([('string',a)],'U10,float')
Out[398]: array([('string', 4.42266577e-05)], dtype=[('f0', '<U10'), ('f1', '<f8')])
In [399]: _.item()
Out[399]: ('string', 4.4226657709978134e-05)