Відкриття файлу об'ємом 20 ГБ для аналізу з пандами


33

Зараз я намагаюся відкрити файл з пандами та пітоном для цілей машинного навчання, для мене було б ідеально мати їх у DataFrame. Тепер файл має 18 Гб, а моя оперативна пам’ять - 32 ГБ, але я постійно отримую помилки в пам'яті.

З вашого досвіду це можливо? Якщо ви не знаєте кращого способу подолати це? (таблиця вуликів? збільшити розмір моєї оперативної пам’яті до 64? створити базу даних та отримати доступ до неї з python)


У мене була така ж проблема, я пропоную вам збільшити своп, пейджинг, розмір вашого жорсткого диска.
ЗМІ

Під час завантаження даних у програмі pandasнеобхідно мати 5-10 разів більше оперативної пам’яті. Я рекомендую робити inplaceоперації, явно закликати garbage.collectorвиділити об'єкти.
Кіріті Гак

4
Зробіть це питання кращим, вказавши свою кінцеву мету. Ви робите дослідницький аналіз даних, чистку даних, навчаєте модель чи що? Які дані?
Піт

1
Чи плануєте ви використовувати даск ?
rpanai

Відповіді:


32

Якщо це файл csv і вам не потрібно отримувати доступ до всіх даних одразу під час тренування алгоритму, ви можете їх читати шматками. pandas.read_csvМетод дозволяє читати файл на шматки , як це:

import pandas as pd
for chunk in pd.read_csv(<filepath>, chunksize=<your_chunksize_here>)
    do_processing()
    train_algorithm()

Ось документація методу


чи це стосується також поштового файлу?
James Wierzba

Це має спрацювати, якщо заархівований файл також є файлом csv, вам слід передати тип стиснення як аргумент методу
Olel Daniel

22

Є дві можливості: або вам потрібно мати всі свої дані в пам'яті для обробки (наприклад, ваш алгоритм машинного навчання хотів би споживати все це відразу), або ви можете обійтися без нього (наприклад, для вашого алгоритму потрібні лише зразки рядків або стовпчиків одразу).

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

Дуже ймовірно, що 32 ГБ оперативної пам’яті не вистачить, щоб Pandas обробляв ваші дані. Зауважте, що ціле число "1" - це лише один байт, коли він зберігається у вигляді тексту, але 8 байт, якщо вони представлені якint64 (що є типовим, коли Pandas читає його з тексту). Ви можете зробити той же приклад із номером з плаваючою комою "1.0", який розширюється з 3-байтового рядка до 8-байтного float64за замовчуванням. Ви можете виграти певний простір, даючи Pandas точно знати, які типи використовувати для кожного стовпця, і примушуючи найменші можливі подання, але ми навіть не почали говорити про структуру даних Python сюди, що може легко додати додатковий вказівник або два тут чи там легко , а покажчики - 8 байт на 64-бітній машині.

Підсумовуючи: ні, 32 ГБ оперативної пам’яті, мабуть, недостатньо, щоб Pandas обробляв файл 20 ГБ.

У другому випадку (який більш реалістичний і, мабуть, стосується вас), вам потрібно вирішити проблему управління даними . Дійсно, завантаження всіх даних, коли вам справді потрібні лише частини їх для обробки, може бути ознакою поганого управління даними. Тут є кілька варіантів:

  1. Використовуйте базу даних SQL. Якщо можете, це майже завжди перший вибір і гідне зручне рішення. 20 Гб звучить як розмір більшості баз даних SQL добре справляється без необхідності розповсюджуватися навіть на ноутбуці (більш високого класу). Ви зможете індексувати стовпці, робити базові агрегації за допомогою SQL та отримувати необхідні підпроби в Pandas для більш складної обробки за допомогою простої pd.read_sql. Переміщення даних до бази даних також надасть вам можливість подумати про фактичні типи даних та розміри стовпців.

  2. Якщо ваші дані здебільшого числові (тобто масиви чи тензори), ви можете розглянути можливість зберігання їх у форматі HDF5 (див. PyTables ), що дозволяє зручно читати з диска лише необхідні фрагменти величезних масивів. Основні numpy.save та numpy.load досягають такого ж ефекту і за допомогою відображення на карті масивів на диску. Для GIS та пов'язаних з ними растрових даних є спеціальні бази даних , які можуть не підключатися до панд настільки ж безпосередньо, як SQL, але також повинні дозволяти робити фрагменти та запити досить зручно.

  3. Наскільки я знаю, Pandas не підтримує таке "часткове" відображення пам'яті HDF5 або numpi-масивів. Якщо ви все-таки хочете отримати якесь рішення "чисто-панди", ви можете спробувати обійти "шардінг": або зберігати стовпці величезної таблиці окремо (наприклад, в окремих файлах, або в окремих "таблицях" одного HDF5 файл) і завантажувати лише потрібні під замовлення або окремо зберігати шматки рядків . Однак вам знадобиться реалізувати логіку для завантаження необхідних фрагментів, тим самим винаходити велосипеди, які вже ввійшли в більшість баз даних SQL, тому, можливо, варіант 1 все-таки буде простішим. Якщо ваші дані надходять у CSV, ви можете обробити їх фрагментами, вказавши chunksizeпараметр для pd.read_csv.


5
У першому випадку слід зазначити те, що якщо в ОП багато записів з однаковим значенням у даних (наприклад, нулі), то, як кажуть, дані є рідкісними, а матка матриці "шипі" може використовуватися, а не pandas dataframe - рідкісні дані потребують значно менше пам’яті.
Рікардо Крус

9

У мене це питання було кілька днів тому! Не впевнений, чи допоможе це у вашому конкретному випадку, оскільки ви не надаєте так багато деталей, але моя ситуація полягала в тому, щоб працювати в автономному режимі на "великому" наборі даних. Дані були отримані у форматі CSV-файлів розміром 20 ГБ із лічильників енергії, даних часових рядів з інтервалом у кілька секунд.

Файл IO:

data_root = r"/media/usr/USB STICK"
fname = r"meters001-050-timestamps.csv.gz"
this_file = os.path.join(data_root,fname)
assert os.path.exists(this_file), this_file
this_file

Створіть ітератор фрагмента безпосередньо над файлом gzip (не розпаковуйте!)

cols_to_keep = [0,1,2,3,7]
column_names = ['METERID','TSTAMP','ENERGY','POWER_ALL','ENERGY_OUT',]
parse_dates = ['TSTAMP']
dtype={'METERID': np.int32, 
       'ENERGY': np.int32,
       'POWER_ALL': np.int32,
       'ENERGY_OUT': np.int32,
      }
df_iterator = pd.read_csv(this_file, 
                        skiprows=0, 
                        compression='gzip',
                        chunksize=1000000, 
                        usecols=cols_to_keep,
                        delimiter=";",
                        header=None,
                        names = column_names,
                      dtype=dtype,
                     parse_dates=parse_dates,
                     index_col=1,
                     )

Ітерація над шматками

new_df = pd.DataFrame()
count = 0
for df in df_iterator:
    chunk_df_15min = df.resample('15T').first()
    #chunk_df_30min = df.resample('30T').first()
    #chunk_df_hourly = df.resample('H').first()
    this_df = chunk_df_15min
    this_df = this_df.pipe(lambda x: x[x.METERID == 1])
    #print("chunk",i)
    new_df = pd.concat([new_df,chunk_df_15min])
    print("chunk",count, len(chunk_df_15min), 'rows added')
    #print("chunk",i, len(temp_df),'rows added')
    #break
    count += 1

Всередині шматка шматка я вчасно роблю фільтрацію та повторний відбір проб. Цим я зменшив розмір з 20 ГБ до декількох сотень МБ HDF5 для подальшої роботи в автономному режимі.


5

На мій досвід, ініціалізація read_csv()параметром, low_memory=Falseяк правило, допомагає при читанні у великих файлах. Я не думаю, що ви згадали про тип файлу, який ви читаєте, тому я не впевнений, наскільки це стосується вашої ситуації.


1

Якщо ваш файл CSV, ви можете просто зробити це в Chunk by Chunk. Ви можете просто зробити:

import pandas as pd
for chunk in pd.read_csv(FileName, chunksize=ChunkSizeHere)
(Do your processing and training here)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.