代码之家  ›  专栏  ›  技术社区  ›  roblanf

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

  •  2
  • roblanf  · 技术社区  · 8 年前

    我和一位合作者注意到numpy中有一些我们不理解的奇怪之处。这是使用Python 3.5.4和numpy版本1.14.2-py35ha9ae307\u 1实现的(加上一个早期版本,我只是为了以防万一而更新)。

    问题似乎是,如果向numpy数组中添加一个float和一些字符串,则该float会按预期转换为字符串,但有时(很少)该float会以一种非常奇怪的方式被截断。我不知道这是一个bug还是一些我们不了解的行为。不管怎样,这看起来都很奇怪。任何见解都是有用的。

    可复制示例

    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')
    

    该问题很容易解决,例如切换到可以处理不同类型的熊猫数据帧。但这种行为似乎很奇怪。我们之所以注意到这一点,是因为我们正在对数百万个数字进行此操作,而健全性检查突出显示了这一点(我们所有的数字都应该是<1,并且我们偶尔开始得到数字>1)。

    2 回复  |  直到 8 年前
        1
  •  4
  •   Iguananaut    8 年前

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

    Python(3)通常将浮点数表示为字符串,其位数最少,以明确表示特定浮点数。

    在这两种情况下 4.4226657709978137e-05 和 4.4226657709978138e-05 两者都不是由IEEE Double精确表示的。在以下情况下 4.4226657709978137e-05 它最短的明确表示恰好是22个字符,而不是21个字符,所以当您尝试将其填充到 <U21 它会被截断。

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

        2
  •  1
  •   hpaulj    8 年前

    如果要在数组中混合字符串和浮点,则不需要使用 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)
    

    或结构化数据类型:

    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)