Открытие 20ГБ файла для анализа с пандами

33

В настоящее время я пытаюсь открыть файл с пандами и python для целей машинного обучения, для меня было бы идеально, чтобы они все были в DataFrame. Теперь размер файла составляет 18 ГБ, а объем оперативной памяти - 32 ГБ, но я получаю ошибки памяти.

Из вашего опыта это возможно? Если нет, знаете ли вы лучший способ обойти это? (таблица кустов - увеличьте размер моей оперативной памяти до 64 - создайте базу данных и получите к ней доступ из python)

Хари Прасад
источник
У меня была такая же проблема, я предлагаю вам увеличить размер подкачки, подкачки, размер вашего жесткого диска.
СМИ,
Основное правило при загрузке данных в pandasтом, что вам нужно иметь 5-10 раз больше оперативной памяти. Я рекомендую делать inplaceоперации, явно вызывать garbage.collectorдля выделения объектов.
Кирите Гак,
4
Сделайте этот вопрос лучше, указав свою конечную цель. Вы делаете предварительный анализ данных, чистку данных, тренируете модель или что? Какие данные?
Пит
1
Рассматривали ли вы использовать Dask ?
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()

Вот документация метода

Олель Даниэль
источник
это относится и к zip-файлу?
Джеймс Вежба
Это должно работать, если заархивированный файл также является CSV-файлом, вам необходимо передать тип сжатия в качестве аргумента метода
Olel Daniel
22

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

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

Весьма вероятно, что 32 ГБ ОЗУ будет недостаточно для того, чтобы Панды обрабатывали ваши данные. Обратите внимание, что целое число «1» - это один байт, когда он хранится в виде текста, и 8 байт, когда он представлен какint64 (это значение по умолчанию, когда Pandas считывает его из текста). Вы можете сделать тот же пример с числом с плавающей запятой "1.0", которое float64по умолчанию расширяется от 3-байтовой строки до 8-байтовой . Вы можете выиграть немного места, давая Pandas точно знать, какие типы использовать для каждого столбца и форсируя наименьшее возможное представление, но мы даже не начали говорить о служебной структуре данных Python здесь, которая может добавить дополнительный или два указателя здесь или там легко и указатели по 8 байт каждый на 64-битной машине.

Подводя итог: нет, 32 ГБ ОЗУ, вероятно, недостаточно для того, чтобы Панды обрабатывали файл размером 20 ГБ.

Во втором случае (который более реалистичен и, вероятно, относится к вам), вам необходимо решить проблему управления данными . Действительно, необходимость загрузки всех данных, когда вам действительно нужны только их части для обработки, может быть признаком плохого управления данными. Здесь есть несколько вариантов:

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

  2. Если ваши данные в основном числовые (то есть массивы или тензоры), вы можете рассмотреть возможность их хранения в формате HDF5 (см. PyTables ), что позволяет вам удобно читать только необходимые фрагменты огромных массивов с диска. Базовые numpy.save и numpy.load достигают того же эффекта с помощью сопоставления памяти массивов на диске. Для ГИС и связанных растровых данных существуют выделенные базы данных , которые могут не подключаться к пандам так же напрямую, как SQL, но также должны позволять вам делать срезы и запросы достаточно удобно.

  3. Насколько мне известно, Pandas не поддерживает такое «частичное» отображение памяти в HDF5 или в массивах с нулевыми значениями. Если вам все еще нужно какое-то «чистое панда» решение, вы можете попытаться обойти его путем «разделения»: либо хранить столбцы вашей огромной таблицы отдельно (например, в отдельных файлах или в отдельных «таблицах» одного HDF5). файл) и загружать только необходимые по требованию или хранить фрагменты строк отдельно. Однако затем вам нужно будет реализовать логику загрузки необходимых фрагментов, таким образом, заново изобретая велосипеды, уже внедренные в большинство баз данных SQL, поэтому, возможно, вариант 1 все же будет проще здесь. Если ваши данные поступают в CSV, вы можете обработать их порциями, указав chunksizeпараметр для pd.read_csv.

KT.
источник
5
Что-то, что следует упомянуть в «первом случае», это то, что если у OP много записей с одинаковым значением в данных (например, с нулями), то данные называются разреженными, и можно использовать скудную разреженную матрицу , а не 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

Внутри чанка я делаю некоторую фильтрацию и повторную выборку по времени. Сделав это, я уменьшил размер HDF5 с 20 ГБ до нескольких сотен МБ для дальнейшего автономного исследования данных.

Маркус Джонс
источник
5

По моему опыту, инициализация read_csv()с параметром low_memory=Falseпомогает при чтении больших файлов. Я не думаю, что вы упомянули тип файла, который вы читаете, поэтому я не уверен, насколько это применимо к вашей ситуации.

chainD
источник
1

Если ваш файл CSV, то вы можете просто сделать это в Chunk by Chunk. Вы можете просто сделать:

import pandas as pd
for chunk in pd.read_csv(FileName, chunksize=ChunkSizeHere)
(Do your processing and training here)
Абдул
источник