大型CSV文件(numpy)上的内存不足

时间:2012-01-21 21:26:47

标签: python memory csv numpy scipy

我有一个3GB的CSV文件,我尝试用python阅读,我需要明智的中间列。

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

我认为这只是一个内存不足的错误。我正在运行一个带有4GB内存的64位MacOSX,并且在64位模式下编译了numpy和Python。

我该如何解决这个问题?我应该尝试分布式方法,仅用于内存管理吗?

由于

编辑:也试过这个,但没有运气......

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

3 个答案:

答案 0 :(得分:65)

正如其他人提到的,对于一个非常大的文件,你最好迭代。

但是,出于各种原因,你通常都希望将整个内容放在内存中。

genfromtxt的效率远低于loadtxt(虽然它处理缺失数据,而loadtxt更“精益和平均”,这就是两个函数共存的原因)。

如果您的数据非常规律(例如,只是所有相同类型的简单分隔行),您还可以使用numpy.fromiter进行改进。

如果你有足够的内存,请考虑使用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

答案 1 :(得分:4)

使用genfromtxt()的问题在于它试图将整个文件加载到内存中,即加载到numpy数组中。这对于小文件很有用,但对于像你这样的3GB输入是BAD。由于您只是计算列中位数,因此无需读取整个文件。一个简单但不是最有效的方法是逐行读取整个文件并迭代列。

答案 2 :(得分:2)

为什么不使用python csv模块?

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