10

私は、ASCIIヘッダーを含むいくつかの大きな(約10GBのgzipされた)ファイルを持っています。次に、原則として、それぞれ約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 )

ただし、 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)

そして、はい、それは動作します! しかし、これは非常に非効率的ではありませんか? s のメモリが割り当てられていないか、イベントごとにガベージ コレクションが行われていませんか? 私のラップトップでは、16イベント/秒、つまり〜50MB/秒に達します

memを一度割り当ててから、numpyにそのmemを直接読み込ませる賢い方法を誰かが知っているのではないかと思います。

ところで。私は物理学者なので、この業界ではまだ初心者です。

4

1 に答える 1

7

@Bakuriuは、これがおそらくマイクロ最適化であることはおそらく正しいでしょう。あなたのボトルネックはほぼ間違いなくIOであり、その後は解凍です。メモリを 2 回割り当てることは、おそらく重要ではありません。

ただし、余分なメモリ割り当てを避けたい場合はnumpy.frombuffer、文字列を numpy 配列として表示するために使用できます。

これにより、メモリの重複が回避されますが (文字列と配列は同じメモリ バッファーを使用します)、配列は既定で読み取り専用になります。必要に応じて、書き込みを許可するように変更できます。

あなたの場合、次のように置き換えるfromstringのと同じくらい簡単frombufferです:

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)

このアプローチを使用してメモリが複製されないことを証明するためだけに:

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...

これにより、yelloの代わりにhello.

この特定のケースで重要な最適化であるかどうかに関係なく、これは知っておくと便利なアプローチです。

于 2013-04-12T23:26:28.410 に答える