Ошибка памяти при использовании pandas read_csv

79

Я пытаюсь сделать что-то довольно простое, читая большой файл csv в фреймворк pandas.

data = pandas.read_csv(filepath, header = 0, sep = DELIMITER,skiprows = 2)

Код либо не работает с a MemoryError, либо никогда не завершается.

Использование памяти в диспетчере задач остановилось на 506 МБ, и после 5 минут отсутствия изменений и отсутствия активности процессора в процессе я остановил его.

Я использую pandas версии 0.11.0.

Я знаю, что раньше была проблема с памятью с анализатором файлов, но, согласно http://wesmckinney.com/blog/?p=543, это должно было быть исправлено.

Размер файла, который я пытаюсь прочитать, составляет 366 МБ, приведенный выше код работает, если я сокращу файл до чего-то короткого (25 МБ).

Также бывало, что я получаю всплывающее сообщение о том, что он не может писать по адресу 0x1e0baf93 ...

Трассировки стека:

Traceback (most recent call last):
  File "F:\QA ALM\Python\new WIM data\new WIM data\new_WIM_data.py", line 25, in
 <module>
    wimdata = pandas.read_csv(filepath, header = 0, sep = DELIMITER,skiprows = 2
)
  File "C:\Program Files\Python\Anaconda\lib\site-packages\pandas\io\parsers.py"
, line 401, in parser_f
    return _read(filepath_or_buffer, kwds)
  File "C:\Program Files\Python\Anaconda\lib\site-packages\pandas\io\parsers.py"
, line 216, in _read
    return parser.read()
  File "C:\Program Files\Python\Anaconda\lib\site-packages\pandas\io\parsers.py"
, line 643, in read
    df = DataFrame(col_dict, columns=columns, index=index)
  File "C:\Program Files\Python\Anaconda\lib\site-packages\pandas\core\frame.py"
, line 394, in __init__
    mgr = self._init_dict(data, index, columns, dtype=dtype)
  File "C:\Program Files\Python\Anaconda\lib\site-packages\pandas\core\frame.py"
, line 525, in _init_dict
    dtype=dtype)
  File "C:\Program Files\Python\Anaconda\lib\site-packages\pandas\core\frame.py"
, line 5338, in _arrays_to_mgr
    return create_block_manager_from_arrays(arrays, arr_names, axes)
  File "C:\Program Files\Python\Anaconda\lib\site-packages\pandas\core\internals
.py", line 1820, in create_block_manager_from_arrays
    blocks = form_blocks(arrays, names, axes)
  File "C:\Program Files\Python\Anaconda\lib\site-packages\pandas\core\internals
.py", line 1872, in form_blocks
    float_blocks = _multi_blockify(float_items, items)
  File "C:\Program Files\Python\Anaconda\lib\site-packages\pandas\core\internals
.py", line 1930, in _multi_blockify
    block_items, values = _stack_arrays(list(tup_block), ref_items, dtype)
  File "C:\Program Files\Python\Anaconda\lib\site-packages\pandas\core\internals
.py", line 1962, in _stack_arrays
    stacked = np.empty(shape, dtype=dtype)
MemoryError
Press any key to continue . . .

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

data <- read.table(paste(INPUTDIR,config[i,]$TOEXTRACT,sep=""), HASHEADER, DELIMITER,skip=2,fill=TRUE)

R не только прекрасно умеет читать вышеуказанный файл, но и читает несколько из этих файлов в цикле for (а затем выполняет некоторые действия с данными). Если у Python действительно есть проблема с файлами такого размера, я могу проиграть битву ...

Энн
источник
1
Определенно, у панд не должно быть проблем с CSV такого размера. Вы можете опубликовать этот файл в Интернете?
Энди Хейден
1
Вы также можете попробовать перейти nrows=something smallк, read_csvчтобы убедиться, что проблема не из-за размера файла, чего, как сказал Энди, не должно быть.
TomAugspurger 09
1
это могло быть как-то связано с «Visual Studio, используя Anaconda и PTVS» ... может быть, попробовать и на обычном питоне
Энди Хайден
3
Я нашел следующее, чтобы решить эту проблему: прочитайте csv как фрагменты csv_chunks = pandas.read_csv(filepath, sep = DELIMITER,skiprows = 1, chunksize = 10000), затем объедините фрагменты df = pandas.concat(chunk for chunk in csv_chunks). Мне все еще интересно узнать, почему чтение за один раз не работает, для меня это похоже на проблему с программой чтения csv.
Anne
11
Если кто-то все еще следит за этим, у меня есть небольшое обновление. Я пришел к выводу, что парсер csv в порядке (и очень быстро), но при создании фреймов данных возникает какая-то проблема с памятью. Причина, по которой я верю в это: когда я использую chunksize=1000хак для чтения csv, а затем пытаюсь объединить все фрагменты в большой фрейм данных, именно в этот момент память взрывается, примерно в 3-4 раза больше по сравнению с размером исходного файла. Кто-нибудь знает, почему может взорваться фреймворк?
Anne

Ответы:

32

Ограничение памяти Windows

Ошибки памяти часто возникают с Python при использовании 32-битной версии в Windows. Это связано с тем, что 32-битные процессы по умолчанию получают только 2 ГБ памяти .

Уловки для снижения использования памяти

Если вы не используете 32-битный питон в Windows, но хотите улучшить эффективность своей памяти при чтении файлов CSV, есть уловка.

Функция pandas.read_csv принимает параметр с именем dtype. Это позволяет пандам знать, какие типы существуют в ваших данных csv.

Как это работает

По умолчанию pandas попытается угадать, какие типы есть у вашего CSV-файла. Это очень тяжелая операция, поскольку при определении dtype все необработанные данные должны храниться в памяти в виде объектов (строк).

пример

Допустим, ваш csv выглядит так:

name, age, birthday
Alice, 30, 1985-01-01
Bob, 35, 1980-01-01
Charlie, 25, 1990-01-01

Этот пример, конечно, без проблем прочитать в память, но это всего лишь пример.

Если бы pandas прочитал указанный выше файл csv без какой-либо опции dtype, возраст был бы сохранен в виде строк в памяти, пока pandas не прочитал достаточно строк файла csv, чтобы сделать квалифицированное предположение.

Я думаю, что по умолчанию в pandas нужно прочитать 1000000 строк, прежде чем угадать dtype.

Решение

Указав dtype={'age':int}в качестве опции для .read_csv()pandas, вы узнаете, что возраст следует интерпретировать как число. Это сэкономит вам много памяти.

Проблема с поврежденными данными

Однако, если ваш файл csv будет поврежден, например:

name, age, birthday
Alice, 30, 1985-01-01
Bob, 35, 1980-01-01
Charlie, 25, 1990-01-01
Dennis, 40+, None-Ur-Bz

Тогда указание dtype={'age':int}сломает .read_csv()команду, потому что она не может привести "40+"к int. Так что тщательно дезинфицируйте свои данные!

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

Попробуй сам

df = pd.DataFrame(pd.np.random.choice(['1.0', '0.6666667', '150000.1'],(100000, 10)))
resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
# 224544 (~224 MB)

df = pd.DataFrame(pd.np.random.choice([1.0, 0.6666667, 150000.1],(100000, 10)))
resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
# 79560 (~79 MB)
Firelynx
источник
Я вижу, как это может ускорить чтение данных, но уменьшит объем памяти? Конечно, не нужно хранить больше нескольких строковых значений на столбец, чтобы угадать тип данных? Т.е., если у вас нет миллиарда столбцов или read_csvфункция не делает что-то невероятно интересное, я был бы очень удивлен, если бы использование памяти заметно увеличилось.
Hannes Ovrén
2
@ HannesOvrén Тип данных невозможно угадать до того, как вы прочтете значительную часть данных, в противном случае вы рискуете изменить его несколько раз, что увеличивает стоимость. Я думаю, что pandas по умолчанию читает первый миллион строк, прежде чем делать предположение. Я снизил профиль памяти нашего продукта на основе pandas в 50 раз, добавив dtypes к загрузкам csv.
firelynx
1
Хм, подумав об этом, я думаю, может быть проблематично решить, будет ли «3» числом с плавающей запятой или целым числом, если вы также не увидите где-нибудь «2.5». Спасибо за объяснение. Я не знал об этом.
Hannes Ovrén
Это неправда. С dtype есть и в памяти дороже и по времени медленнее. Проверено 6 раз с dtype в read_csv. Средние значения: ... memory no dtype: 12,121,429,333333334 | память с dtype: 12,124,160.0 ... За время 13 проверок, Средние значения: ... time no dtypes: 2.0494697460761437 | time with dtypes: 2.100334332539485 ... Используется: import os import psutil process = psutil.Process (os.getpid ()) print (process.memory_info (). rss) ___ Строки данных: 1,5 миллиона из трех отдельных наборов данных, столбцы 90% являются типом объекта. * Очевидно, что у float размер меньше, чем у строкового типа
nikolaosmparoutis
@nikolaos_mparoutis Не знаю, как вы пришли к этим результатам. Может быть, вы хотите написать свой собственный ответ, потому что в вашем комментарии сложно понять, что такое код, а что является комментарием. Мой ответ довольно старый, возможно, что-то изменилось.
firelynx
6

У меня была такая же проблема с памятью при простом чтении текстового файла с разделителями табуляции размером около 1 ГБ (более 5,5 миллионов записей), и это решило проблему с памятью :

df = pd.read_csv(myfile,sep='\t') # didn't work, memory error
df = pd.read_csv(myfile,sep='\t',low_memory=False) # worked fine and in less than 30 seconds

Spyder 3.2.3 Python 2.7.13 64 бита

лось
источник
7
Это противоречит low_memory=False
здравому
2

Я использую Pandas на своем Linux-компьютере и столкнулся со многими утечками памяти, которые были устранены только после обновления Pandas до последней версии после его клонирования с github.

Тарик
источник
1

Я столкнулся с этой проблемой, когда работал на виртуальной машине или где-то еще, где память сильно ограничена. Это не имеет ничего общего с pandas, numpy или csv, но всегда произойдет, если вы попытаетесь использовать больше памяти, чем вам разрешено, даже не только в python.

Единственный шанс, который у вас есть, - это то, что вы уже пробовали, попробуйте разделить большое на более мелкие части, которые уместятся в памяти.

Если вы когда-нибудь спрашивали себя, что такое MapReduce, вы узнали бы сами ... MapReduce попытается распределить фрагменты по многим машинам, вы попытаетесь обработать фрагменты на одной машине один за другим.

То, что вы узнали при объединении файлов фрагментов, действительно может быть проблемой, возможно, для этой операции требуется какая-то копия ... но, в конце концов, это, возможно, спасет вас в вашей текущей ситуации, но если ваш csv станет немного больше ты можешь снова столкнуться с этой стеной ...

Также может быть, что pandas настолько умен, что на самом деле загружает отдельные фрагменты данных в память только в том случае, если вы что-то делаете с ними, например, конкатенация с большим df?

Вы можете попробовать несколько вещей:

  • Не загружайте все данные сразу, а разбивайте их на части
  • Насколько мне известно, hdf5 может выполнять эти фрагменты автоматически и загружает только ту часть, над которой в настоящее время работает ваша программа.
  • Посмотрите, все ли в порядке, строка 0.111111 требует больше памяти, чем float
  • Что вам на самом деле нужно, если есть адрес в виде строки, он может вам не понадобиться для численного анализа ...
  • База данных может помочь получить и загрузить только те части, которые вам действительно нужны (например, только 1% активных пользователей)
Себастьян Нойбауэр
источник
1

Для Pandas 0.12.0 и NumPy 1.8.0 ошибки нет.

Мне удалось создать большой DataFrame и сохранить его в файл csv, а затем успешно прочитать его. См. Пример здесь . Размер файла составляет 554 Мб (он работал даже с файлом 1,1 Гб, потребовалось больше времени, для генерации файла 1,1 Гб использовалась частота использования 30 секунд). Хотя у меня есть 4 Гб оперативной памяти.

Мое предложение - обновить Pandas. Другая вещь, которая может быть полезна, - это попробовать запустить свой скрипт из командной строки, потому что для R вы не используете Visual Studio (это уже было предложено в комментариях к вашему вопросу), поэтому у него есть больше доступных ресурсов.

Александр
источник
1

Я пробовал chunksizeчитать большой файл CSV

reader = pd.read_csv(filePath,chunksize=1000000,low_memory=False,header=0)

Прочитанный теперь список. Мы можем повторитьreader выполнить и записать / добавить в новый CSV или выполнить любую операцию

for chunk in reader:
    print(newChunk.columns)
    print("Chunk -> File process")
    with open(destination, 'a') as f:
        newChunk.to_csv(f, header=False,sep='\t',index=False)
        print("Chunk appended to the file")
muTheTechie
источник
0

Добавьте эти: rating = pd.read_csv (..., low_memory = False, memory_map = True )

Моя память с этими двумя: # 319.082.496 Без этих двух: # 349.110.272

николаосмпарутис
источник
-1

Хотя это обходной путь не столько, сколько исправление, я бы попытался преобразовать этот CSV в JSON (должен быть тривиальным) и read_jsonвместо этого использовать метод - я писал и читал большие JSON / фреймы данных (100 МБ) в Pandas this способ вообще без проблем.

LetMeSOThat4U
источник