压缩文件上有效的numpy.fromfile?

Dom*_*ise 9 python zip numpy fromfile

我有一些大的(甚至是大约10GB的压缩文件)文件,其中包含一个ASCII标头,然后原则上每个大约3MB的numpy.recarrays,我们称之为"事件".我的第一个方法看起来像这样:

f = gzip.GzipFile(filename)
f.read(10000) # fixed length ascii header
event_dtype = np.dtype([
        ('Id', '>u4'),                # simplified
        ('UnixTimeUTC', '>u4', 2), 
        ('Data', '>i2', (1600,1024) ) 
        ])
event = np.fromfile( f, dtype = event_dtype, count=1 )
Run Code Online (Sandbox Code Playgroud)

但是,这是不可能的,因为np.fromfile需要一个真正的FILE对象,因为它确实进行了低级别的调用(找到了一个相当旧的票据https://github.com/numpy/numpy/issues/1103).

据我了解,我必须这样做:

s = f.read( event_dtype.itemsize )
event = np.fromstring(s, dtype=event_dtype, count=1)
Run Code Online (Sandbox Code Playgroud)

是的,它有效!但这不是非常低效吗?是不是分配了内存,为每个事件收集垃圾?在我的笔记本电脑上,我达到了16个事件/秒,即~50MB/s

我想知道是否有人知道一个聪明的方法,分配mem一次然后让numpy直接读入该mem.

顺便说一句.我是一名物理学家,所以...还是这个行业的新手.

Joe*_*ton 6

@Bakuriu可能是正确的,因为这可能是微观优化。您的瓶颈几乎肯定是IO,然后是减压。两次分配内存可能并不重要。

但是,如果要避免额外的内存分配,则可以使用numpy.frombuffer该字符串作为numpy数组查看。

这样可以避免重复内存(字符串和数组使用相同的内存缓冲区),但是默认情况下该数组将为只读。然后,可以根据需要将其更改为允许写入。

对你来说,这将是简单的替换fromstringfrombuffer

f = gzip.GzipFile(filename)
f.read(10000) # fixed length ascii header
event_dtype = np.dtype([
        ('Id', '>u4'),                # simplified
        ('UnixTimeUTC', '>u4', 2), 
        ('Data', '>i2', (1600,1024) ) 
        ])
s = f.read( event_dtype.itemsize )
event = np.frombuffer(s, dtype=event_dtype, count=1)
Run Code Online (Sandbox Code Playgroud)

只是为了证明使用这种方法不会复制内存:

import numpy as np

x = "hello"
y = np.frombuffer(x, dtype=np.uint8)

# Make "y" writeable...
y.flags.writeable = True

# Prove that we're using the same memory
y[0] = 121
print x # <-- Notice that we're outputting changing y and printing x...
Run Code Online (Sandbox Code Playgroud)

这样会产生:yello而不是hello

无论在这种特殊情况下这是否是重大的优化,这都是一种有用的方法。