在Python中读入和分片二进制数据文件的最快方法

问题描述:

我有一个处理脚本,用于在“uint16”类型的二进制数据文件中提取数据,并以6400为单位进行各种处理。该代码最初是用Matlab编写的,但由于分析代码是用Python编写的,我们想通过在Python中完成所有工作来简化流程。问题是我注意到我的Python代码比Matlab的fread函数慢得多。在Python中读入和分片二进制数据文件的最快方法

只要把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是〜5倍比Python的方法,我实现了更快。我已经探索过诸如numpy.fromfile和numpy.memmap之类的方法,但是由于这些方法需要在整个内存中打开整个文件,所以它限制了用例,因为我的二进制文件非常大。是否有一些pythonic方法来做到这一点,我失踪了?我会认为Python在打开+读取二进制文件时会非常快。任何意见是极大的赞赏。

+1

有没有机会使用[dask](http://dask.pydata.org/en/latest/)与[h5py](http://www.h5py.org/)。去年,我使用这两个软件包进行了数以百万计的粒子的大规模模拟。 – romeric

+1

也看看[这里](https://*.com/questions/14245094/how-to-read-part-of-binary-file-with-numpy) – romeric

+0

@romeric我不知道dask会作为我使用的是“.bin”文件,而转换成类似h5py的文件对于用例来说会适得其反。数据文件格式是我目前不能控制的不幸的。第二篇文章似乎只是使用f。与np.fromfile组合使用查找命令。我看到的问题是我可以去正确的位置,但它会将文件的其余部分读入numpy数组,这会使我的用例中的内存超载。 –

写块到一个文件:

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微秒;只是f.read,23。所以这是unpack加上更通用和强大的np.array需要更长的时间。文件读取本身不是问题。 (np.array可以处理多种输入的,列出的名单,对象列表,等等,所以不得不花费更多的时间分析和评估的投入。)

A于fromfile稍快变是你读的加frombuffer

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

我无法获得f.seek + np.fromfile的组合工作,但您提供的替代方案工作!使用np.frombuffer(我以前从来没有听说过),我能够将python降低到24 us/chunk,比matlab等效的速度快大约2倍。干杯。 –