【问题标题】:Fastest way to read in and slice binary data files in Python在 Python 中读取和切片二进制数据文件的最快方法
【发布时间】:2017-10-25 10:31:36
【问题描述】:

我有一个处理脚本,旨在提取“uint16”类型的二进制数据文件,并一次以 6400 个块进行各种处理。代码最初是用 Matlab 编写的,但由于分析代码是用 Python 编写的,我们希望通过在 Python 中完成所有操作来简化流程。问题是我注意到我的 Python 代码比 Matlab 的 fread 函数慢得多。

简单地说Matlab代码是这样的:

fid = fopen(filename); 
frame = reshape(fread(fid,80*80,'uint16'),80,80);  

虽然我的 Python 代码很简单:

with open(filename, 'rb') as f: 
    frame = np.array(unpack("H"*6400, f.read(12800))).reshape(80, 80).astype('float64')

文件大小从 500 MB -> 400 GB 变化很大,所以我相信找到一种更快的 Python 数据解析方法可以为更大的文件带来好处。 500 MB 通常有大约 50000 个块,并且这个数字随着文件大小线性增加。我看到的速度差异大致是:

Python = 4 x 10^-4 seconds / chunk

Matlab = 6.5 x 10^-5 seconds / chunk

随着时间的推移,Matlab 的处理显示比我实现的 Python 方法快约 5 倍。我已经探索过诸如 numpy.fromfile 和 numpy.memmap 之类的方法,但是因为这些方法需要在某些时候将整个文件打开到内存中,所以它限制了用例,因为我的二进制文件非常大。是否有一些我缺少的pythonic方法来做到这一点?我原以为 Python 在打开 + 读取二进制文件时会非常快。任何意见是极大的赞赏。

【问题讨论】:

  • 您是否有机会将daskh5py 一起使用。去年,我使用这两个软件包对数百万个粒子进行了大规模模拟。
  • 也看看here
  • @romeric 我不确定 dask 是否会工作,因为我正在使用“.bin”文件,并且转换为 h5py 之类的文件对于用例会适得其反。不幸的是,我目前无法控制数据文件格式。第二篇文章似乎只是将 f.seek 命令与 np.fromfile 组合使用。我看到的问题是我可以转到正确的位置,但它会将文件的其余部分读入 numpy 数组,这会使我的用例中的内存过载。
  • fromfile 没有计数或大小参数吗?
  • 如果您能将readunpackarray 步骤的时间分开可能会有所帮助。

标签: python matlab performance python-2.7 numpy


【解决方案1】:

将块写入文件:

In [117]: dat = np.random.randint(0,1028,80*80).astype(np.uint16)
In [118]: dat.tofile('test.dat')
In [119]: dat
Out[119]: array([266, 776, 458, ..., 519,  38, 840], dtype=uint16)

按照自己的方式导入:

In [120]: import struct
In [121]: with open('test.dat','rb') as f:
     ...:     frame = np.array(struct.unpack("H"*6400,f.read(12800)))
     ...:     
In [122]: frame
Out[122]: array([266, 776, 458, ..., 519,  38, 840])

使用fromfile导入

In [124]: np.fromfile('test.dat',count=6400,dtype=np.uint16)
Out[124]: array([266, 776, 458, ..., 519,  38, 840], dtype=uint16)

比较时间:

In [125]: %%timeit
     ...:  with open('test.dat','rb') as f:
     ...:      ...:     frame = np.array(struct.unpack("H"*6400,f.read(12800)))
     ...: 
1000 loops, best of 3: 898 µs per loop

In [126]: timeit np.fromfile('test.dat',count=6400,dtype=np.uint16)
The slowest run took 5.41 times longe....
10000 loops, best of 3: 36.6 µs per loop

fromfile 更快。

struct.unpack 的时间,没有np.array 是 266 µs;对于f.read, 23。所以它是unpack 加上更通用和强大的np.array 需要更长的时间。文件读取本身不是问题。 (np.array 可以处理多种输入,列表列表,对象列表等,因此必须花更多时间解析和评估输入。)

fromfile 上的一个稍快的变体是您的阅读加上frombuffer

In [133]: with open('test.dat','rb') as f:
     ...:      frame3 = np.frombuffer(f.read(12800),dtype=np.uint16)

【讨论】:

  • 我无法使 f.seek + np.fromfile 的组合工作,但您提供的替代方案有效!使用 np.frombuffer(我以前从未听说过)我能够将 python 降低到 24 us / 块,这比 matlab 等效速度快约 2 倍。干杯。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-05-01
  • 2013-04-07
  • 1970-01-01
  • 1970-01-01
  • 2019-09-12
  • 2019-10-02
相关资源
最近更新 更多