numpy的loadtxt在string包含decimal时将错误转换为int

时间:2013-07-12 17:41:17

标签: python numpy

我在尝试将txt文件加载到结构化数组中时遇到了麻烦。

这是一个显示问题的简单示例。

这很好用:

import numpy as np
from StringIO import StringIO 

in1 = StringIO("123 456 789\n231 543 876")
a = np.loadtxt(in1, dtype=[('x', "int"), ('y', "int"), ('z', "int")])

####output
array([(123, 456, 789), (231, 543, 876)], 
      dtype=[('x', '<i8'), ('y', '<i8'), ('z', '<i8')])

但是当其中一个字段包含小数时,我会在尝试将其转换为int时出错:

in2 = StringIO("123 456 789\n231 543.0 876")
a = np.loadtxt(in2, dtype=[('x', "int"), ('y', "int"), ('z', "int")])

####error
ValueError: invalid literal for long() with base 10: '543.0'

我希望python能够将像“543.0”这样的数字转换为543而不会抛出错误。

如果它只是一个数字,我可以使用像

这样的东西
int(float("543.0"))

但我可以和numpy的loadtxt结合使用吗?

实际上,我试图读取的文件大约是2Gigs,并且有一个长度为37的复杂dtype,包含浮点数,字符串和整数的混合。

我尝试过numpy.genfromtxt,它似乎适用于较小的文件,但它会占用2gig文件中太多的内存。

我考虑过的另一个选择是截断所有以“.0”结尾的数字,使用sed,这将起作用,但更多的是黑客而不是真正的解决方案。

有更多的pythonic方法吗?

已回答(感谢Zhenya)......

dtypeTmp = np.dtype([(d[0], "<f8") if d[1] == "<i8" else d for d in dtype1.descr])
events = np.loadtxt("file.txt", dtype=dtypeTmp)
events.astype(dtype1)

2 个答案:

答案 0 :(得分:2)

对于应该是整数的字段,您可以使用执行int(float(fieldval))的转换器。以下显示了一种基于dtype以编程方式创建loadtxt converters参数的方法:

In [77]: in3 = StringIO("123.0 456 789 0.95\n231 543.0 876 0.87")

In [78]: dt = dtype([('x', "int"), ('y', "int"), ('z', "int"), ('r', "float")])

In [79]: converters = dict((k, lambda s: int(float(s))) for k in range(len(dt)) if np.issubdtype(dt[k], np.integer))

In [80]: converters
Out[80]: 
{0: <function __main__.<lambda>>,
 1: <function __main__.<lambda>>,
 2: <function __main__.<lambda>>}

In [81]: a = np.loadtxt(in3, dtype=dt, converters=converters)

In [82]: a
Out[82]: 
array([(123, 456, 789, 0.95), (231, 543, 876, 0.87)], 
      dtype=[('x', '<i8'), ('y', '<i8'), ('z', '<i8'), ('r', '<f8')])

即使这样,在2 gig文件上使用loadtxt时,您仍可能遇到性能或内存问题。你看过pandas了吗?它的csv阅读器比numpy的阅读器要快得多。

答案 1 :(得分:1)

无需手动编辑任何内容:

>>> in2 = StringIO("123 456 789\n231 543.0 876")
>>> dt_temp = np.dtype([('x', "int"), ('y', "float"), ('z', "int")])
>>> a = np.loadtxt(in2, dtype=dt_temp)
>>> 
>>> dt = np.dtype([('x', "int"), ('y', "int"), ('z', "int")])
>>> b = a.astype(dt)
>>> b
array([(123, 456, 789), (231, 543, 876)], 
      dtype=[('x', '<i8'), ('y', '<i8'), ('z', '<i8')])