2016-04-06 12 views
0

私は約28Gbの3列ファイルを持っています。私はPythonでそれを読んでその内容を3Dタプルのリストに入れたいと思います。pythonはファイルの実際のサイズよりも多くのメモリをロードします

f = open(filename) 
col1 = [float(l.split()[0]) for l in f] 
f.seek(0) 
col2 = [float(l.split()[1]) for l in f] 
f.seek(0) 
col3 = [float(l.split()[2]) for l in f] 
f.close() 
rowFormat = [col1,col2,col3] 
tupleFormat = zip(*rowFormat) 
for ele in tupleFormat: 
     ### do something with ele 

は私が実際にファイルの全体の内容を読むことを意味し、ループのためには「ブレーク」コマンドはありません。ここで私が使用しているコードです。スクリプトが実行されているとき、私は仮想メモリ(VIRT列)の156Gと常駐メモリ(RES列)のほぼ同じ量を取ることを 'htop'コマンドから通知します。ファイルサイズがわずか28Gであるのに対し、私のスクリプトは156Gを使用するのはなぜですか?

+1

でも 'int'はヘッダを持つオブジェクトで、予想以上のスペースを占めます。おそらく['numpy.loadtxt()'](http://docs.scipy.org/doc/numpy-1.10.0/reference/generated/numpy.loadtxt.html)を使うことができますか? – Reti43

+0

なぜファイルを3回読むのですか? –

+0

なぜあなたは同時にそれをすべてメモリに必要としていますか? –

答えて

2

Pythonオブジェクトには、オブジェクトや他のものへの参照カウントなど、多くのオーバヘッドがあります。つまり、Pythonの浮動小数点数は8バイトを超えています。私の32ビットのPythonのバージョンは、

>>> import sys 
>>> print(sys.getsizeof(float(0)) 
16 

リストは、それ自身のオーバーヘッドを持っており、そのオブジェクトへの参照を格納する要素ごとに4バイトを必要としています。したがって、リスト内の100個の浮動小数点数は、実際にはサイズを占めます。

>>> a = map(float, range(100)) 
>>> sys.getsizeof(a) + sys.getsizeof(a[0])*len(a) 
2036 

今、numpyの配列は異なります。そのようにPythonのフロートがnumpyの8と比較して20バイトを必要とするオーバーヘッドの少ないビットを有するが、フードの下の生データはC.

>>> import numpy as np 
>>> b = np.array(a) 
>>> sys.getsizeof(b) 
848 
>>> b.itemsize # number of bytes per element 
8 

のように格納されています。そして64bit Python versions require even more

実際に、たくさんのデータをメモリにロードする必要がある場合、numpyはという1つのの方法です。データをロードする方法を見ると、行ごとに3つの浮動小数点数を持つテキスト形式で、任意の数のスペースで分割されていると仮定します。その場合、あなたは単にあなたはまた、より多くのオプションhere、例えばのためにmmapを見ることができるが、私はそれはあなたのためのより適切だろうかと言って、それについてはあまり知らないnumpy.genfromtxt()

data = np.genfromtxt(fname, autostrip=True) 

を使用することができ。

+0

さて、 'np.loadtxt'を使用すると、プロセスのメモリ使用量が少なくなりました。しかし、私は質問があります: 'pickle'表現から変数 'tupleFormat'を読み込み、ファイルを開いて読み込む方が速いでしょうか?私は、 'tupleFormat'のピクルス表現が元のファイルのサイズの少なくとも2倍であることに気づいていますが、ファイルを開くより速く読むのは分かりません。 – dada

+0

@dadaそのデータで何をしたいですか?ハードディスクの読み込み/読み込みは遅い処理です。何度も多くの値をロード/チェックする必要がある場合は、それが物理的な制限でない限り、一度メモリにロードする方がよいでしょう。 – Reti43

0

ジェネレーターを使用して、1行ずつゆっくりと読む必要があります。これを試してください:

col1 = [] 
col2 = [] 
col3 = [] 

rowFormat = [col1, col2, col3] 

with open('test', 'r') as f: 
    for line in f: 
     parts = line.split() 
     col1.append(float(parts[0])) 
     col2.append(float(parts[1])) 
     col3.append(float(parts[2])) 
     # if possible do something here to start seeing results immediately 

tupleFormat = zip(*rowFormat) 
for ele in tupleFormat: 
    ### do something with ele 

ロジックをforループに追加して、プロセス全体が終了するのを待つことができます。

+0

これは怠け者ではなく、一度に読むことはできますか?私は、ジェネレータになるという意味で、各行の現在の値を「収穫」する必要はありませんか? –

+0

http://stackoverflow.com/questions/519633/lazy-method-for-reading-big-file-in-python –

+1

なぜ私のスクリプトを実行しているプロセスで使用されるメモリ量が減るのでしょうか? – dada

0

をタップルごとに保存することはできますか?私。あなたがファイルを読むときに "何かをする"ことができますか?ない場合は、多分あなたは、列フォーマットまたはのいずれかにタプル形式のリストを選択することによって、いくつかのメモリを節約することができ

#!/usr/bin/env python 
import fileinput 
for line in fileinput.FileInput('test.dat'): 
    ele = tuple((float(x) for x in line.strip().split())) 
    # Replace 'print' with your "do something". 
    # Note that ele is now a generator, not a tuple. Wrap it in 
    # ele = tuple(ele) to get a tuple instead if you need it. 
    print ele 

、両方ではなく、例えば....

:その場合は...これを試してみてください
#!/usr/bin/env python 
import fileinput 
elements = [] 
for line in fileinput.FileInput('test.dat'): 
    elements.append(tuple((float(x) for x in line.strip().split()))) 

for ele in elements: 
    # do something 
関連する問題