2012-01-21 31 views
32

Tôi có tệp CSV 3 GB mà tôi cố gắng đọc bằng python, tôi cần cột trung bình khôn ngoan.Python hết bộ nhớ trên tệp CSV lớn (numpy)

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 

Các lỗi mà tôi nhận được là:

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 

Tôi nghĩ rằng nó chỉ là một trong số lỗi bộ nhớ. Tôi đang chạy một MacOSX 64bit với 4GB ram và cả numpy và Python được biên dịch trong chế độ 64bit.

Làm cách nào để khắc phục sự cố này? Tôi có nên thử một cách tiếp cận phân tán, chỉ để quản lý bộ nhớ?

Cảm ơn

EDIT: Cũng thử với điều này, nhưng không may mắn ...

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

Sử dụng [pandas.read_csv] (http://wesmckinney.com/blog/?p=543) nó nhanh hơn đáng kể. –

Trả lời

58

Như những người khác đã đề cập, đối với một tệp thực sự lớn, bạn nên tắt lặp lại.

Tuy nhiên, bạn thường muốn toàn bộ nội dung trong bộ nhớ vì nhiều lý do khác nhau.

genfromtxt kém hiệu quả hơn loadtxt (mặc dù nó xử lý dữ liệu bị thiếu, trong khi loadtxt là "gọn gàng và có nghĩa" hơn, đó là lý do hai hàm này cùng tồn tại).

Nếu dữ liệu của bạn rất thường xuyên (ví dụ: chỉ các hàng được phân cách đơn giản của cùng một loại), bạn cũng có thể cải thiện bằng cách sử dụng numpy.fromiter.

Nếu bạn có đủ ram, xem xét sử dụng np.loadtxt('yourfile.txt', delimiter=',') (Bạn cũng có thể cần phải xác định skiprows nếu bạn có một tiêu đề trên các tập tin.)

Là một so sánh nhanh, bốc ~ tập tin văn bản 500MB với loadtxt sử dụng ~ 900MB của ram khi sử dụng cao điểm, trong khi tải cùng một tệp với genfromtxt sử dụng ~ 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


Cách khác, hãy xem xét một cái gì đó như sau. Nó sẽ chỉ làm việc cho dữ liệu rất đơn giản, thường xuyên, nhưng nó khá nhanh. (loadtxtgenfromtxt làm rất nhiều đoán và kiểm tra lỗi. Nếu dữ liệu của bạn rất đơn giản và thường xuyên, bạn có thể cải thiện chúng rất nhiều.)

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

Không quan tâm, bạn đã nhận được các cấu hình bộ nhớ như thế nào? – huon

+5

Về cơ bản, sức mạnh vũ phu. :) Đây là kịch bản shell của tôi, nếu bạn quan tâm: https://gist.github.com/2447356 Nó xa thanh lịch, nhưng nó đủ gần. –

+0

Ah, đẹp quá! (Mặc dù tôi sẽ thừa nhận tôi đã hy vọng cho 'import memoryprofile' hoặc một cái gì đó, drat!) – huon

4

Vấn đề với việc sử dụng genfromtxt() là nó cố gắng để tải toàn bộ tập tin vào bộ nhớ, tức là vào một mảng numpy. Điều này là rất tốt cho các tập tin nhỏ nhưng BAD cho 3GB đầu vào như của bạn. Vì bạn chỉ cần tính toán các cột trung bình, không cần phải đọc toàn bộ tệp. Một cách đơn giản, nhưng không hiệu quả nhất để làm điều đó là đọc toàn bộ từng dòng một tập tin và lặp lại qua các cột.

+0

Vâng, được rồi. Nhưng liệu có một giải pháp bền vững hơn cho điều này? Giống như trong một chương trình java, bạn có thể chọn để bắt đầu nó với, nói, 5GB bộ nhớ. Có tương đương với Python không? Ý tôi là, lần sau tôi có thể chỉ có một tệp CSV với một dòng 4Gb. – Ihmahr

+1

Python không giới hạn số lượng bộ nhớ bạn có thể phân bổ. Nếu bạn nhận được 'MemoryError' trong Python 64-bit, bạn thực sự đã hết bộ nhớ. –

+1

Thật không may, không phải tất cả các mô-đun Python đều hỗ trợ kiến ​​trúc 64 bit. – cjohnson318

1

Tại sao bạn không sử dụng mô-đun python csv?

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

Bởi vì toàn bộ chương trình của tôi sử dụng đại số tuyến tính numpy và cơ bản .. với người đọc tôi không thể làm tất cả những thứ đó. – Ihmahr

+0

Kết hợp với câu trả lời của kz26, điều này thực sự mang lại giải pháp khả thi. Cũng buồn cười: Sau một lần lặp, tệp được lưu trữ và quá trình chuyển từ 60 đến 99% cpu. – Ihmahr

Các vấn đề liên quan