2013-12-06 5 views
10

У меня есть CSV-файл размером 250 МБ, который мне нужно прочитать с ~ 7000 строк и ~ 9000 столбцов. Каждая строка представляет изображение, и каждый столбец является пикселем (значение шкалы серого 0-255)Python MemoryError: не может выделить память массива

Я начал с простого np.loadtxt("data/training_nohead.csv",delimiter=","), но это дало мне ошибку памяти. Я думал, что это странно, так как я запускаю 64-битный Python с установленными 8 гигабайтами памяти, и он умер после использования только около 512 МБ.

С тех пор я пытался несколько других приемов, в том числе:

  1. import fileinput и прочитать одну строку за один раз, добавляя их в массив
  2. np.fromstring после прочтения весь файл
  3. np.genfromtext
  4. Ручной анализ файла (поскольку все данные целые, это было довольно легко кодировать)

Каждый метод дал мне тот же результат. MemoryError около 512 МБ. Хотите знать, если есть что-то особенное 512MB, я создал простую тестовую программу, которая наполненную память до тех пор, питон не разбился:

str = " " * 511000000 # Start at 511 MB 
while 1: 
    str = str + " " * 1000 # Add 1 KB at a time 

Doing это не не разбился примерно до 1 концерта. Я также, просто для удовольствия, попробовал: str = " " * 2048000000 (заполните 2 концерта) - это бег без пробелов. Заполнял ОЗУ и никогда не жаловался. Так что вопрос не общий объем оперативной памяти я могу выделить, но, кажется, сколько раз я могу выделить память ...

Я google'd вокруг бесплодно, пока я не нашел этот пост: Python out of memory on large CSV file (numpy)

Я скопировал код от ответа именно:

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 

Calling iter_loadtxt("data/training_nohead.csv") дал немного другой ошибке, на этот раз:

MemoryError: cannot allocate array memory 

погуглить тыс это ошибка, я нашел только одну, не очень полезную, сообщение: Memory error (MemoryError) when creating a boolean NumPy array (Python)

Поскольку я запускаю Python 2.7, это не было моей проблемой. Любая помощь будет оценена по достоинству.

+3

Вы пытались сделать это за два прохода? 1-й проход: вычисляет размеры массива 'nxm' и dtypes. 2-й проход: поместить данные в массив * preallocated * (указать 'dtype',' count' для 'np.fromiter()' может быть достаточно) – jfs

+0

Я действительно уже знаю размеры массива (7049 x 9146), поэтому я попробую это. EDIT - 9246, а не 9146. Нематериальный, хотя – stevendesu

+0

Это сработало! Пожалуйста, напишите как ответ, чтобы я мог его принять. Бонусные очки: он побежал, как, 8 секунд! Я был очень удивлен. – stevendesu

ответ

4

С некоторой помощью от @ J.F. Себастьян я разработал следующий ответ:

train = np.empty([7049,9246]) 
row = 0 
for line in open("data/training_nohead.csv") 
    train[row] = np.fromstring(line, sep=",") 
    row += 1 

Конечно, этот ответ предполагается предварительное знание количества строк и столбцов. Если вы не располагаете этой информацией заранее, количество строк всегда занимает некоторое время, чтобы вычислить, так как вам нужно прочитать весь файл и подсчитать символы \n. Что-то вроде этого будет достаточно:

num_rows = 0 
for line in open("data/training_nohead.csv") 
    num_rows += 1 

Для числа столбцов, если каждая строка имеет одинаковое количество столбцов, то вы можете просто рассчитывать на первую строку, в противном случае вам необходимо следить за максимальной.

num_rows = 0 
max_cols = 0 
for line in open("data/training_nohead.csv") 
    num_rows += 1 
    tmp = line.split(",") 
    if len(tmp) > max_cols: 
     max_cols = len(tmp) 

Это решение лучше всего подходит для цифровых данных, поскольку строка, содержащая запятую, может действительно усложнить ситуацию.

+1

примечание: 'для i, строка в перечислении (файл)' и 'ncols = max (ncols, len (line.split (',')))' встроенные функции, которые вы могли бы использовать здесь. В общем случае (не в этом случае) строка cvs может охватывать несколько физических линий, т. Е. Правильный способ перечисления строк csv: «для i, строка в перечислении (csv.reader (файл))». – jfs

Смежные вопросы