2012-01-21 27 views
32

Python ile okumaya çalıştığım 3 GB CSV dosyam var, medyan sütun bilgisine ihtiyacım var. Bunu sadece bellek hatası dışında olduğunu düşünüyorumPython büyük CSV dosyasındaki bellek yetersiz (numpy)

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 

:

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 

alıyorum hata budur. 64bit modunda derlenmiş 64bit MacOSX 4GB ram ve hem numpy hem de Python ile çalışıyorum.

Bunu nasıl düzeltirim? Sadece bellek yönetimi için dağıtılmış bir yaklaşım denemeliyim?

Teşekkür

DÜZENLEME: Ayrıca, bu ancak hiçbir şans ile çalıştı ...

genfromtxt('All.csv',delimiter=',', dtype=float16) 
+1

kullanın [pandas.read_csv] (http://wesmckinney.com/blog/?p=543) önemli ölçüde daha hızlı. –

cevap

58

Diğer kişilerin belirttiği gibi, gerçekten büyük bir dosya için yineleme yapmaktan daha iyidir. Bununla birlikte, genel olarak çeşitli şeylerden dolayı bellekte bulunan tüm şeyleri sık sık istiyorsunuzdur. (Bu eksik veri işleme olsa loadtxt daha "yalın ve ortalama" oysa ki, neden iki işlev birlikte var)

genfromtxt çok daha az verimli loadtxt fazla.

Verileriniz çok düzenliyse (ör., Tümüyle aynı türde yalnızca basit sınırlandırılmış satırlar), numpy.fromiter'u kullanarak da geliştirebilirsiniz. Eğer yeterli ram varsa

, (Ayrıca dosya üzerinde bir başlık varsa skiprows belirtmeniz gerekebilir.) np.loadtxt('yourfile.txt', delimiter=',') kullanmayı düşünün hızlı bir karşılaştırma olarak

, yükleme ~ loadtxt ile 500MB metin dosyası kullanır ~ 900MB ram kullanımında, aynı dosyayı genfromtxt ile yüklerken ~ 2.5GB kullanır.

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


Alternatif olarak, aşağıdaki gibi bir şey düşünün. Sadece çok basit, düzenli veriler için çalışacak, ancak oldukça hızlı. (loadtxt ve genfromtxt çok fazla tahmin ve hata denetimi yapar. Verileriniz çok basit ve düzenliyse, bunları büyük ölçüde geliştirebilirsiniz.)

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

+0

İlgi alanı dışında, bellek profillerini nasıl aldınız? – huon

+5

Temel olarak kaba kuvvet. :) İşte benim kabuk senaryom, ilgileniyorsanız: https://gist.github.com/2447356 Zarif olmaktan uzak ama yeterince yakın. –

+0

Ah, güzel! (Ben itiraf etmeliyim ki, 'import memoryprofile' ya da bir şey, drat umuyordum.) – huon

4

genfromtxt (kullanarak sorun) bir içine yani bellek, içine bütün dosya yüklemeye çalıştığında olmasıdır numpy dizisi. Bu küçük dosyalar için mükemmeldir, ancak sizinki gibi 3GB girişler için BAD. Sadece sütun medyalarını hesapladığınız için, tüm dosyayı okumaya gerek yoktur. Bunu yapmak için en basit yol değil, en etkili yol, tüm dosyayı satır-by-line olarak birçok kez okumak ve sütunlar üzerinde yinelemek olacaktır.

+0

Eh, tamam. Fakat bunun için daha sürdürülebilir bir çözüm var mı? Bir java programında olduğu gibi, bunu 5GB'lık bir bellekle başlatmayı seçebilirsiniz. Python için bir eşdeğer var mı? Yani, bir dahaki sefere tek bir 4Gb hattı olan bir CSV dosyasına sahip olabilirim .. – Ihmahr

+1

Python, ne kadar bellek ayırabileceğinizi sınırlamaz. Eğer 64-bit Python'da 'MemoryError' alırsanız, gerçekten hafızanız bitti. –

+1

Maalesef, tüm Python modülleri 64 bit mimariyi desteklemiyor. – cjohnson318

1

Neden python csv modülünü kullanmıyorsunuz?

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

Tüm programım, numpy ve temel lineer cebir kullanıyor çünkü okuyucuyla bu şeyleri yapamam. – Ihmahr

+0

kz26'nın cevabı ile birleştiğinde, bu gerçekten işe yarayan bir çözüm sunuyor. Ayrıca komik: Bir yinelemeden sonra dosya önbelleğe alınır ve işlem% 60'dan% 99'a çıkar. – Ihmahr