【问题标题】:Fast data reading from text file in numpy从 numpy 中的文本文件中快速读取数据
【发布时间】:2016-03-10 19:47:46
【问题描述】:

如何使用 numpy 加快数据读取和类型转换?我还面临获取 numpy.void 类型对象的问题,因为据我所知是异构数组,而不是 ndarrays。我创建了一个简单的测试,显示numpy.genfromtxt 比纯python 代码慢,但我相信一定有更好的方法。我无法让numpy.loadtxt 工作。

如何提高性能?以及如何获取 ndarray 子数组作为结果?

import timeit
import numpy as np

line = "QUAD4   1       123456  123456781.2345671.2345671.234567        "
text = [line + "\n" for x in range(1000000)]
with open("testQUADs","w") as f:
    f.writelines(text)


setup="""
import numpy as np
"""

st="""
with open("testQUADs", "r") as f:
    fn = f.readlines()
for i, line in enumerate(fn):
    l = [line[0:8], line[8:16], line[16:24], line[24:32], line[32:40], line[40:48], line[48:56], line[56:64], line[64:72], line[72:80]]
    fn[i] = [l[0].strip(), int(l[1]), int(l[2]), int(l[3]), float(l[4]), float(l[5]), float(l[6]), l[7].strip()]
fn = np.array(fn)
"""

stnp="""
array = np.genfromtxt("testQUADs", delimiter=8, dtype="|S8, i4, i4, i4, f8, f8, f8, |S8")
print(array[0])
print(type(array[0]))
"""


print(timeit.timeit(st, setup=setup, number=1))
print(timeit.timeit(stnp, setup=setup, number=1))

输出:

4.560215269000764
(b'QUAD4   ', 1, 123456, 12345678, 1.234567, 1.234567, 1.234567, b'        ')
<class 'numpy.void'>
6.360823633000109

【问题讨论】:

  • 看过 6 次后,我得到了负面评价,老实说,我不明白为什么。我不相信。我已阅读有关此主题的 numpy 用户手册,我已查看有关此主题的 numpy 参考手册,我已在网上查看,但我的问题没有解决。
  • 别介意我会“修复”它,因为其他人可能也会对这个问题感兴趣;)
  • 不幸的是,我的 numpy 经验很少,所以请原谅我的无知,但是是否可以使用 numpy.fromfile() 读取您的数据 - 文档说 - “一种读取二进制数据的高效方法一个已知的数据类型”...

标签: python numpy genfromtxt


【解决方案1】:

你会得到什么

array = np.genfromtxt("testQUADs", delimiter=8, dtype="|S8, i4, i4, i4, f8, f8, f8, |S8")

structured array

array.dtype

看起来像

np.dtype("|S8, i4, i4, i4, f8, f8, f8, |S8")

array.shape是行数;它是一个有 8 个字段的一维数组。

array[0] 是该数组的一个元素或记录;看看它的dtype。不用担心它的type(void 只是复合dtype 记录的类型)。

array['f0'] 是第一个字段,所有行,在本例中为字符串数组。

您可能需要更深入地阅读 dtypestructured 数组文档。许多 SO 发帖者对genfromtxt 生成的一维结构化数组感到困惑。

genfromtxt 就像您的代码一样读取文件,并将每一行拆分为字符串。然后它根据dtype 转换这些字符串,并将结果收集到一个列表中。最后,它将该列表组装成array - 指定dtype的这个一维数组。因为它比你的代码做的更多,所以它有点慢也就不足为奇了。

loadtxt 的作用大致相同,只是在某些区域功率较小。

pandas 有一个更快的 csv 阅读器,因为它使用了更多的编译代码。但是数据框并不比结构化数组更容易理解。


您的 2 种方法不会产生相同的结果:

In [105]: line = "QUAD4   1       123456  123456781.2345671.2345671.234567        "

In [106]: txt=[line,line,line]    # a list of lines instead of a file

In [107]: A = np.genfromtxt(txt, delimiter=8, dtype="|S8, i4, i4, i4, f8, f8, f8, |S8")

In [108]: A
Out[108]: 
array([ ('QUAD4   ', 1, 123456, 12345678, 1.234567, 1.234567, 1.234567, '        '),
       ('QUAD4   ', 1, 123456, 12345678, 1.234567, 1.234567, 1.234567, '        '),
       ('QUAD4   ', 1, 123456, 12345678, 1.234567, 1.234567, 1.234567, '        ')], 
      dtype=[('f0', 'S8'), ('f1', '<i4'), ('f2', '<i4'), ('f3', '<i4'), ('f4', '<f8'), ('f5', '<f8'), ('f6', '<f8'), ('f7', 'S8')])

注意dtype;和3个元素

你的行解析器:

In [109]: fn=txt[:]    
In [110]: for i, line in enumerate(fn):
        l = [line[0:8], line[8:16], line[16:24], line[24:32], line[32:40], line[40:48], line[48:56], line[56:64], line[64:72], line[72:80]]
        fn[i] = [l[0].strip(), int(l[1]), int(l[2]), int(l[3]), float(l[4]), float(l[5]), float(l[6]), l[7].strip()]
   .....:     

In [111]: fn
Out[111]: 
[['QUAD4', 1, 123456, 12345678, 1.234567, 1.234567, 1.234567, ''],
 ['QUAD4', 1, 123456, 12345678, 1.234567, 1.234567, 1.234567, ''],
 ['QUAD4', 1, 123456, 12345678, 1.234567, 1.234567, 1.234567, '']]

In [112]: A1=np.array(fn)

In [113]: A1
Out[113]: 
array([['QUAD4', '1', '123456', '12345678', '1.234567', '1.234567',
        '1.234567', ''],
       ['QUAD4', '1', '123456', '12345678', '1.234567', '1.234567',
        '1.234567', ''],
       ['QUAD4', '1', '123456', '12345678', '1.234567', '1.234567',
        '1.234567', '']], 
      dtype='|S8')

fn 是一个列表列表,可以有多种类型的值。但是当你把它放到一个数组中时,它会把所有东西都变成一个字符串。

我可以将您的 fn 列表转换为结构化数组:

In [120]: np.array([tuple(l) for l in fn],dtype=A.dtype)
Out[120]: 
array([('QUAD4', 1, 123456, 12345678, 1.234567, 1.234567, 1.234567, ''),
       ('QUAD4', 1, 123456, 12345678, 1.234567, 1.234567, 1.234567, ''),
       ('QUAD4', 1, 123456, 12345678, 1.234567, 1.234567, 1.234567, '')], 
      dtype=[('f0', 'S8'), ('f1', '<i4'), ('f2', '<i4'), ('f3', '<i4'), ('f4', '<f8'), ('f5', '<f8'), ('f6', '<f8'), ('f7', 'S8')])

这与 genfromtxt 中的 A 相同,除了字符串的填充。


这里有一个可能有用的变体,虽然它也可能扩展您对结构化数组的知识:

In [132]: dt=np.dtype('a8,(3)i,(3)f,a8')
In [133]: A = np.genfromtxt(txt, delimiter=8, dtype=dt)

A 现在有 4 个字段,其中两个有多个值

A['f1'] 将返回一个 (n,3) 整数数组。

【讨论】:

    【解决方案2】:

    你还有:

    np.loadtxt
    

    如果您确定每行获得相同数量的值,则可以使用它。 但是,一切都从上一个答案中说出来;)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-10-04
      • 2014-04-06
      • 2013-07-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-10
      相关资源
      最近更新 更多