2013-04-12 17 views
8

私はいくつかの大きなファイル(約10GBのgzipファイル)を持っています。これらのファイルには、ASCIIヘッダが入っていて、原則numpy.recarraysがそれぞれ約3MBあり、それらを「イベント」と呼びます。私の最初のアプローチは、このように見えた:zipファイルの効率的なnumpy.fromfile?

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) 

それは本当に低レベルの呼び出し(かなり古いチケットhttps://github.com/numpy/numpy/issues/1103を見つけた)を行うためnp.fromfileは、実際のファイルオブジェクトを必要とするので、これは、不可能です。

私は理解してだから私はこのようにそれをしなければならない。

s = f.read(event_dtype.itemsize) 
event = np.fromstring(s, dtype=event_dtype, count=1) 

そして、はい、それは働きます!しかし、これはひどく非効率的ではありませんか? memが割り当てられておらず、すべてのイベントでガベージが収集されていますか? 私のラップトップでは、16イベント/秒~50MB/sのようなものになります

誰かがスマートな方法を知っていれば、一度memを割り振り、numpyをそのmemに直接読み込ませるのは難しいです。

Btw。私は物理学者なので、まだこのビジネスの初心者です。

+1

I/Oがかかる時間は、その文字列の割り当て/割り当て解除に要した時間よりも数千倍大きいです。ボトルネックがどこにあるのかを確認し、最適化するためにコードをプロファイルする必要があります。ボトルネックがどこにあるかを推測することは、効率的にプログラミングすることに慣れていない場合でも、さらに悪いことです。 – Bakuriu

+1

読み込み専用の配列であれば、numpy.frombufferを使ってメモリの重複を避け、その文字列をメモリバッファとして使うことができます。 –

+0

@Bakariuはそれを明確に表現してくれてありがとう。コードをプロファイリングする経験はありません。そして、その良いことは、その推測は悪いです。 @ジョーキングトン。 –

答えて

3

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

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

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

あなたのケースでは、それはfrombufferfromstringを交換するのと同じくらい簡単になります:

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です。

この特定のケースで重要な最適化であるかどうかにかかわらず、これは意識しておくと便利なアプローチです。

関連する問題