Помилка пам'яті при використанні панд read_csv


79

Я намагаюся зробити щось досить просте, читаючи великий файл CSV у фреймі даних pandas.

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

Код або не працює MemoryError, або просто ніколи не закінчується.

Використання пам’яті в диспетчері завдань зупинилося на рівні 506 Мб, і через 5 хвилин без змін і без активності процесора я зупинив це.

Я використовую pandas версії 0.11.0.

Мені відомо, що раніше виникала проблема пам’яті з парсером файлів, але згідно з http://wesmckinney.com/blog/?p=543 це мало бути виправлено.

Файл, який я намагаюся прочитати, становить 366 Мб. Код, наведений вище, працює, якщо я скорочую файл на щось коротке (25 Мб).

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

Tracktrace:

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 такого розміру. Чи можете ви розмістити цей файл в Інтернеті?
Andy Hayden,

1
Ви також можете спробувати перейти nrows=something smallдо, read_csvщоб переконатися, що це не розмір файлу, що викликає проблеми, чого, як сказав Енді, не повинно бути.
TomAugspurger

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.
Енн

11
Якщо хтось все ще стежить за цим, я трохи поновив. Я прийшов до думки, що синтаксичний аналізатор CSV чудовий (і дуже швидкий), але при створенні фреймів даних виникає певна проблема з пам'яттю. Причина, по якій я вірю в це: коли я використовую chunksize=1000хак для читання csv, а потім намагаюся об'єднати всі фрагменти у великий фрейм даних, саме в цей момент пам'ять вибухає, приблизно в 3-4 рази розмір пам'яті порівняно з розміром вихідного файлу. Хтось уявляє, чому кадр даних може підірватися?
Енн

Відповіді:


32

Обмеження пам’яті Windows

Помилки пам’яті часто трапляються з python при використанні 32-бітної версії в Windows. Це пов’язано з тим, що 32-бітні процеси за замовчуванням отримують лише 2 ГБ пам’яті для відтворення .

Хитрощі для зменшення використання пам'яті

Якщо ви не використовуєте 32-бітний python у Windows, але прагнете покращити ефективність своєї пам’яті під час читання файлів CSV, є хитрість.

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

Як це працює

За замовчуванням pandas намагатимуться вгадати, які dtypes має ваш файл csv. Це дуже важка операція, оскільки, визначаючи dtype, вона повинна зберігати всі необроблені дані як об'єкти (рядки) в пам'яті.

Приклад

Скажімо, ваш csv виглядає так:

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

Цей приклад, звичайно, не проблема читати в пам’яті, але це лише приклад.

Якби панди читали вищезазначений файл csv без будь-якої опції dtype, вік зберігався б у вигляді рядків у пам'яті, поки панди не прочитали достатньо рядків файлу csv, щоб зробити кваліфіковану здогадку.

Я думаю, що за замовчуванням у пандах читають 1 000 000 рядків перед тим, як відгадати dtype.

Рішення

Вказавши dtype={'age':int}як варіант .read_csv()заповіту, дайте пандам зрозуміти, що вік слід інтерпретувати як число. Це економить багато пам’яті.

Проблема з пошкодженими даними

Однак, якщо ваш файл 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)

Я бачу, як це може прискорити читання даних, але зменшуючи пам’ять? Звичайно, для вгадування типу даних не потрібно зберігати більше кількох рядкових значень у колонці? Тобто, якщо у вас немає базільйонів стовпців або read_csvфункція не робить щось неймовірно забавне, я був би дуже здивований, якщо обсяг пам'яті помітно вищий.
Hannes Ovrén

2
@ HannesOvrén Тип даних неможливо вгадати, перш ніж прочитати значну частину даних, інакше ви ризикуєте змінити їх кілька разів, що складає вартість. Я думаю, що pandas за замовчуванням читає перший мільйон рядків перед тим, як зробити здогад. Я знизив профіль пам'яті нашого продукту на основі панд у 50 разів, додавши dtypes до завантажень csv.
firelynx

1
Хм, думаючи про це, я думаю, може бути проблематично вирішити, чи буде "3" плаваючою або int, якщо ви також десь не бачите "2,5". Дякую за пояснення. Я не знав про це.
Hannes Ovrén

Це не правда. З dtype і в пам'яті дорожче, і в часі повільніше. Перевірено 6 разів із dtype у read_csv. Середні значення: ... пам’ять немає dtype: 12,121,429.333333334 | пам'ять з dtype: 12,124,160.0 ... За час, перевірений 13 разів, середні показники складають: ... час немає dtypes: 2.0494697460761437 | час з dtypes: 2.100334332539485 ... Використовується: import os import psutil process = psutil.Process (os.getpid ()) print (process.memory_info (). rss) ___ Рядки даних: 1,5 мільйона з трьох окремих наборів даних, cols 90% мають тип об’єкта. * Очевидно, поплавок має менший розмір, ніж тип струни
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слід використовувати менше пам'яті ..
guillefix

2

Я використовую Pandas на своєму Linux-сервері і зіткнувся з багатьма витоками пам'яті, які вдалося вирішити лише після оновлення Pandas до останньої версії після клонування з github.


1

Я також зіткнувся з цією проблемою, коли працював у віртуальній машині, або де-небудь інше, де пам'ять жорстко обмежена. Це не має нічого спільного з пандами, чи numpy чи csv, але це завжди трапляється, якщо ви спробуєте використовувати більше пам'яті, як вам дозволено, навіть не лише в python.

Єдиний шанс у вас є те, що ви вже спробували, спробуйте перебити велике на менші шматочки, які поміщаються в пам'ять.

Якщо ви коли-небудь запитували себе, що це таке MapReduce, ви дізналися самі ... MapReduce спробував би розподілити фрагменти на багатьох машинах, ви спробували б обробити фрагменти на одній машині один за іншим.

Те, що ви виявили при об'єднанні фрагментних файлів, може бути справді проблемою, можливо, в цій операції потрібна якась копія ... але врешті-решт це, можливо, рятує вас у вашій поточній ситуації, але якщо ваш CSV стає трохи більшим ти можеш знову бігти об цю стіну ...

Також може бути, що панди настільки розумні, що насправді завантажують окремі фрагменти даних лише в пам'ять, якщо ви щось з цим робите, наприклад, конкатенацію у великий df?

Ви можете спробувати кілька речей:

  • Не завантажуйте всі дані відразу, а розділіть на частини
  • Наскільки мені відомо, hdf5 може робити ці фрагменти автоматично і завантажує лише ту частину, над якою працює ваша програма
  • Переконайтеся, що типи в порядку, рядок 0,111111 потребує більше пам'яті, ніж плаваючий
  • Що вам потрібно насправді, якщо адреса є рядком, вона може вам не знадобитися для чисельного аналізу ...
  • База даних може допомогти отримати доступ та завантажити лише ті частини, які вам дійсно потрібні (наприклад, лише 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")

0

Додайте такі: оцінки = pd.read_csv (..., low_memory = False, memory_map = True )

Моя пам’ять із цими двома: # 319.082.496 Без цих двох: # 349.110.272


-1

Незважаючи на те, що це обхідне рішення не стільки, скільки виправлення, я спробував би перетворити цей CSV на JSON (має бути тривіальним) і read_jsonзамість цього використати метод - я писав і читав значні JSON / фрейми даних (100 Мб) у Pandas, це без жодних проблем.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.