Python не хватает памяти в большом файле CSV (numpy)
У меня есть файл 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 ответа
Как уже упоминали другие люди, для действительно большого файла лучше выполнять итерации.
Тем не менее, вы обычно хотите все это в памяти по разным причинам.
genfromtxt
гораздо менее эффективен, чем loadtxt
(хотя он обрабатывает недостающие данные, тогда как loadtxt
более "худой и злой", поэтому две функции сосуществуют).
Если ваши данные очень регулярные (например, простые строки с одинаковыми типами), вы также можете улучшить их, используя numpy.fromiter
,
Если у вас достаточно оперативной памяти, подумайте об использовании np.loadtxt('yourfile.txt', delimiter=',')
(Вам также может понадобиться указать skiprows
если у вас есть заголовок файла.)
Как быстрое сравнение, загрузка ~500 МБ текстового файла с loadtxt
использует около 900 МБ оперативной памяти при пиковой нагрузке, загружая тот же файл с genfromtxt
использует ~2,5 ГБ.
Loadtxt
Genfromtxt
Поочередно рассмотрим что-то вроде следующего. Это будет работать только для очень простых, регулярных данных, но это довольно быстро. (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
Проблема с использованием genfromtxt() состоит в том, что он пытается загрузить весь файл в память, то есть в массив. Это отлично подходит для небольших файлов, но ПЛОХО для 3 ГБ входов, как у вас. Поскольку вы просто вычисляете медианы столбцов, нет необходимости читать весь файл. Простой, но не самый эффективный способ сделать это - прочитать весь файл построчно несколько раз и перебрать столбцы.
Почему вы не используете модуль Python CSV?
>> import csv
>> reader = csv.reader(open('All.csv'))
>>> for row in reader:
... print row