web-dev-qa-db-ja.com

Python大きなCSVファイルのメモリ不足(numpy)

Pythonで読み取ろうとする3GBのCSVファイルがあり、中央値の列が必要です。

from numpy import * 
def data():
    return genfromtxt('All.csv',delimiter=',')

data = data() # This is where it fails already.

med = zeros(len(data[0]))
data = data.T
for i in xrange(len(data)):
    m = median(data[i])
    med[i] = 1.0/float(m)
print med

私が得るエラーはこれです:

Python(1545) malloc: *** mmap(size=16777216) failed (error code=12)

*** error: can't allocate region

*** set a breakpoint in malloc_error_break to debug

Traceback (most recent call last):

  File "Normalize.py", line 40, in <module>

  data = data()

  File "Normalize.py", line 39, in data

  return genfromtxt('All.csv',delimiter=',')

File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-
packages/numpy/lib/npyio.py", line 1495, in genfromtxt

for (i, line) in enumerate(itertools.chain([first_line, ], fhd)):

MemoryError

メモリ不足のエラーだと思います。私は4 GBのRAMと64ビットモードでコンパイルされたnumpyとPythonの両方を備えた64ビットMacOSXを実行しています。

どうすれば修正できますか?メモリ管理だけのために、分散アプローチを試すべきですか?

ありがとう

編集:これも試したが運がない...

genfromtxt('All.csv',delimiter=',', dtype=float16)
34
Ihmahr

他の人々が述べたように、非常に大きなファイルの場合は、反復する方がよいでしょう。

ただし、さまざまな理由により、通常はすべてをメモリに格納する必要があります。

genfromtxtloadtxtよりも効率的ではありません(欠落データを処理しますが、loadtxtは2つの関数が共存するため、より「リーンで平均」です)。

データが非常に規則的である場合(たとえば、すべて同じタイプの単純な区切られた行のみ)、_numpy.fromiter_を使用してどちらかを改善することもできます。

十分なRAMがある場合は、np.loadtxt('yourfile.txt', delimiter=',')の使用を検討してください(ファイルにヘッダーがある場合は、skiprowsを指定する必要がある場合もあります)。

簡単に比較すると、loadtxtを使用して〜500MBのテキストファイルをロードすると、ピーク時に最大900MBのRAMが使用されますが、genfromtxtを使用して同じファイルをロードすると、約2.5GBが使用されます。

Loadtxt Memory and CPU usage of numpy.loadtxt while loading a ~500MB ascii file


Genfromtxt Memory and CPU usage of numpy.genfromtxt while loading a ~500MB ascii file


あるいは、次のようなものを検討してください。非常にシンプルで定期的なデータに対してのみ機能しますが、非常に高速です。 (loadtxtgenfromtxtは、多くの推測とエラーチェックを行います。データが非常にシンプルで定期的なものであれば、大幅に改善できます。)

_import numpy as np

def generate_text_file(length=1e6, ncols=20):
    data = np.random.random((length, ncols))
    np.savetxt('large_text_file.csv', data, delimiter=',')

def iter_loadtxt(filename, delimiter=',', skiprows=0, dtype=float):
    def iter_func():
        with open(filename, 'r') as infile:
            for _ in range(skiprows):
                next(infile)
            for line in infile:
                line = line.rstrip().split(delimiter)
                for item in line:
                    yield dtype(item)
        iter_loadtxt.rowlength = len(line)

    data = np.fromiter(iter_func(), dtype=dtype)
    data = data.reshape((-1, iter_loadtxt.rowlength))
    return data

#generate_text_file()
data = iter_loadtxt('large_text_file.csv')
_

Fromiter

Using fromiter to load the same ~500MB data file

70
Joe Kington

Genfromtxt()を使用する際の問題は、ファイル全体をメモリに、つまりnumpy配列にロードしようとすることです。これは小さなファイルには最適ですが、あなたのような3GB入力には不適切です。列の中央値を計算しているだけなので、ファイル全体を読み取る必要はありません。単純ですが、最も効率的な方法ではありませんが、ファイル全体を1行ずつ複数回読み取り、列を繰り返し処理します。

4
CoderMD666

python csv モジュールを使用しないのはなぜですか?

>> import csv
>> reader = csv.reader(open('All.csv'))
>>> for row in reader:
...     print row
2
anijhaw