Python не хватает памяти в большом файле CSV (numpy) - PullRequest
33 голосов
/ 22 января 2012

У меня есть CSV-файл объемом 3 ГБ, который я пытаюсь прочитать с помощью 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

Я думаю, что это просто ошибка нехватки памяти. Я использую 64-разрядную версию MacOSX с 4 ГБ оперативной памяти, а также numpy и Python, скомпилированные в 64-разрядном режиме.

Как мне это исправить? Должен ли я попробовать распределенный подход, только для управления памятью?

Спасибо

РЕДАКТИРОВАТЬ: также пытался с этим, но не повезло ...

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

Ответы [ 3 ]

65 голосов
/ 23 января 2012

Как уже упоминали другие люди, для действительно большого файла лучше повторить.

Однако по разным причинам вы обычно хотите, чтобы все это было в памяти.

genfromtxt гораздо менее эффективен, чем loadtxt (хотя он обрабатывает пропущенные данные, тогда как loadtxt является более "скудным и средним", поэтому две функции сосуществуют).

Если ваши данные очень регулярны (например, просто строки с разделителями одинакового типа), вы также можете улучшить их, используя numpy.fromiter.

Если у вас достаточно оперативной памяти, рассмотрите возможность использования np.loadtxt('yourfile.txt', delimiter=',') (Вам также может понадобиться указать skiprows, если у вас есть заголовок в файле.)

Для быстрого сравнения: при загрузке текстового файла ~ 500 МБ с помощью loadtxt при максимальной нагрузке используется ~ 900 МБ ОЗУ, а при загрузке того же файла с помощью genfromtxt - ~ 2,5 ГБ.

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


В качестве альтернативы рассмотрим что-то вроде следующего. Это будет работать только для очень простых, регулярных данных, но это довольно быстро. (loadtxt и genfromtxt делают много предположений и проверок на ошибки. Если ваши данные очень простые и регулярные, вы можете значительно улучшить их.)

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

4 голосов
/ 22 января 2012

Проблема с использованием genfromtxt () состоит в том, что он пытается загрузить весь файл в память, то есть в массив numpy. Это отлично подходит для небольших файлов, но ПЛОХО для 3 ГБ входов, как у вас. Поскольку вы просто вычисляете медианы столбцов, вам не нужно читать весь файл. Простой, но не самый эффективный способ сделать это - прочитать весь файл построчно несколько раз и перебрать столбцы.

2 голосов
/ 22 января 2012

Почему вы не используете модуль python csv ?

>> import csv
>> reader = csv.reader(open('All.csv'))
>>> for row in reader:
...     print row
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...