Рабочие процессы «больших данных» с использованием pandas

1115

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

Однажды я надеюсь заменить использование SAS на python и pandas, но в настоящее время мне не хватает внешнего рабочего процесса для больших наборов данных. Я не говорю о «больших данных», требующих распределенной сети, а о файлах, слишком больших для размещения в памяти, но достаточно малых для размещения на жестком диске.

Моя первая мысль - использовать HDFStoreдля хранения больших наборов данных на диске и извлекать только те части, которые мне нужны, во фреймы данных для анализа. Другие упомянули MongoDB как более простую в использовании альтернативу. У меня такой вопрос:

Каковы наиболее эффективные рабочие процессы для выполнения следующих задач:

  1. Загрузка плоских файлов в постоянную структуру базы данных на диске
  2. Запрос этой базы данных для извлечения данных для подачи в структуру данных pandas
  3. Обновление базы данных после манипулирования частями в пандах

Будем очень признательны за примеры из реального мира, особенно от тех, кто использует pandas для «больших данных».

Изменить - пример того, как я бы хотел, чтобы это работало:

  1. Итеративно импортируйте большой плоский файл и сохраните его в постоянной структуре базы данных на диске. Эти файлы обычно слишком велики, чтобы поместиться в памяти.
  2. Чтобы использовать Pandas, я хотел бы читать подмножества этих данных (обычно всего несколько столбцов за раз), которые могут уместиться в памяти.
  3. Я бы создавал новые столбцы, выполняя различные операции с выбранными столбцами.
  4. Затем мне пришлось бы добавить эти новые столбцы в структуру базы данных.

Я пытаюсь найти лучший способ выполнения этих шагов. При чтении ссылок на pandas и pytables кажется, что добавление нового столбца может быть проблемой.

Изменить - конкретно отвечая на вопросы Джеффа:

  1. Я строю модели риска потребительского кредитования. Типы данных включают телефон, SSN и характеристики адреса; стоимость недвижимости; уничижительная информация, такая как судимости, банкротства и т. д. Наборы данных, которые я использую каждый день, содержат в среднем от 1000 до 2000 полей смешанных типов данных: непрерывные, номинальные и порядковые переменные как числовых, так и символьных данных. Я редко добавляю строки, но выполняю много операций, создающих новые столбцы.
  2. Типичные операции включают объединение нескольких столбцов с использованием условной логики в новый составной столбец. Например, if var1 > 2 then newvar = 'A' elif var2 = 4 then newvar = 'B'. Результатом этих операций является новый столбец для каждой записи в моем наборе данных.
  3. Наконец, я хотел бы добавить эти новые столбцы в структуру данных на диске. Я бы повторил шаг 2, исследуя данные с помощью перекрестных таблиц и описательной статистики, пытаясь найти интересные, интуитивно понятные взаимосвязи для моделирования.
  4. Типичный файл проекта обычно составляет около 1 ГБ. Файлы организованы таким образом, что строка состоит из записи данных о потребителях. Каждая строка имеет одинаковое количество столбцов для каждой записи. Так будет всегда.
  5. Довольно редко я использую подмножество строк при создании нового столбца. Однако я довольно часто использую подмножество строк при создании отчетов или генерации описательной статистики. Например, я мог бы захотеть создать простую частоту для определенного направления бизнеса, скажем, для розничных кредитных карт. Для этого я бы выбрал только те записи, в которых направление деятельности = розничная торговля, в дополнение к тем столбцам, по которым я хочу отчитаться. Однако при создании новых столбцов я извлекал бы все строки данных и только те столбцы, которые мне нужны для операций.
  6. Процесс моделирования требует, чтобы я анализировал каждый столбец, искал интересные отношения с некоторой выходной переменной и создавал новые составные столбцы, описывающие эти отношения. Столбцы, которые я исследую, обычно делаются небольшими наборами. Например, я сосредоточусь на наборе из 20 столбцов, в которых рассматриваются только значения собственности, и наблюдаю, как они соотносятся с невыполнением обязательств по ссуде. После того, как они изучены и созданы новые столбцы, я перехожу к другой группе столбцов, скажем, «Образование в колледже», и повторяю процесс. Я создаю переменные-кандидаты, которые объясняют связь между моими данными и некоторым результатом. В самом конце этого процесса я применяю некоторые методы обучения, которые создают уравнение из этих составных столбцов.

Я редко когда-либо добавляю строки в набор данных. Я почти всегда буду создавать новые столбцы (переменные или функции на языке статистики / машинного обучения).

6
  • 1
    Соотношение размер ядра / полный размер составляет 1%, 10%? Имеет ли это значение - если бы вы могли сжать столбцы до int8 или отфильтровать шумные строки, изменило бы это ваш цикл вычислений и мышления с часов на минуты? (Также добавьте тег big-data.)denis 18 марта '13 в 14: 262013-03-18 11:26
  • 1
    Хранение float32 вместо float64 и int8, где это возможно, должно быть тривиальным (хотя не знаю, какие инструменты / функции делают float64 внутри)denis 18 марта '13 в 14: 592013-03-18 11:59
  • можете ли вы разделить свою задачу на части работы? Andrew Scott Evans 08 дек.
  • 1
    Хорошее решение 2019 года для выполнения pandas-подобных операций с "средними" данными, которые не помещаются в памяти, - это dasklunguini 30 окт '19 в 17:56
  • Существуют альтернативы python + pandas, которые вы, возможно, захотите рассмотреть, когда только начинаете. Примите во внимание тот факт, что Python - это язык программирования общего назначения (а не DSL для обработки и анализа данных) и что pandas - это библиотека, прикрепленная поверх этого. Я бы подумал о том, чтобы посмотреть на R или kdb. Henry Henrinson 16 ноя '19 в 14:02
686
+50

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

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

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

  1. Размер данных, количество строк, столбцов, типы столбцов; вы добавляете строки или только столбцы?
  2. Как будут выглядеть типичные операции. Например, выполните запрос по столбцам, чтобы выбрать группу строк и определенных столбцов, затем выполните операцию (в памяти), создайте новые столбцы, сохраните их.
    (Приведя игрушечный пример, мы сможем предложить более конкретные рекомендации.)
  3. Что вы будете делать после этой обработки? Шаг 2 является специальным или повторяемым?
  4. Входные плоские файлы: сколько, приблизительный общий размер в Гб. Как они организованы, например, по записям? Каждый из них содержит разные поля или у них есть записи для каждого файла со всеми полями в каждом файле?
  5. Вы когда-нибудь выбирали подмножества строк (записей) на основе критериев (например, выбирали строки с полем A> 5)? а затем что-то делать, или вы просто выбираете поля A, B, C со всеми записями (а затем что-то делаете)?
  6. Вы «работаете» над всеми своими столбцами (в группах), или есть хорошая пропорция, которую вы можете использовать только для отчетов (например, вы хотите сохранить данные, но не должны вводить подробности этого столбца до тех пор, пока время окончательных результатов)?

Решение

Убедитесь, что у вас установлены хотя бы панды0.10.1 .

Читайте повторяющиеся файлы по частям и запросы к нескольким таблицам .

Поскольку pytables оптимизирован для работы по строкам (это то, что вы запрашиваете), мы создадим таблицу для каждой группы полей. Таким образом, легко выбрать небольшую группу полей (которая будет работать с большой таблицей, но более эффективно сделать это таким образом ... Думаю, я смогу исправить это ограничение в будущем ... это во всяком случае, более интуитивно понятным):
(Следующий псевдокод.)

import numpy as np
import pandas as pd

# create a store
store = pd.HDFStore('mystore.h5')

# this is the key to your storage:
#    this maps your fields to a specific group, and defines 
#    what you want to have as data_columns.
#    you might want to create a nice class wrapping this
#    (as you will want to have this map and its inversion)  
group_map = dict(
    A = dict(fields = ['field_1','field_2',.....], dc = ['field_1',....,'field_5']),
    B = dict(fields = ['field_10',......        ], dc = ['field_10']),
    .....
    REPORTING_ONLY = dict(fields = ['field_1000','field_1001',...], dc = []),

)

group_map_inverted = dict()
for g, v in group_map.items():
    group_map_inverted.update(dict([ (f,g) for f in v['fields'] ]))

Чтение файлов и создание хранилища (по сути, то, что append_to_multipleделает):

for f in files:
   # read in the file, additional options may be necessary here
   # the chunksize is not strictly necessary, you may be able to slurp each 
   # file into memory in which case just eliminate this part of the loop 
   # (you can also change chunksize if necessary)
   for chunk in pd.read_table(f, chunksize=50000):
       # we are going to append to each table by group
       # we are not going to create indexes at this time
       # but we *ARE* going to create (some) data_columns

       # figure out the field groupings
       for g, v in group_map.items():
             # create the frame for this group
             frame = chunk.reindex(columns = v['fields'], copy = False)    

             # append it
             store.append(g, frame, index=False, data_columns = v['dc'])

Теперь у вас есть все таблицы в файле (на самом деле вы можете хранить их в отдельных файлах, если хотите, возможно, вам придется добавить имя файла в group_map, но, вероятно, в этом нет необходимости).

Вот как вы получаете столбцы и создаете новые:

frame = store.select(group_that_I_want)
# you can optionally specify:
# columns = a list of the columns IN THAT GROUP (if you wanted to
#     select only say 3 out of the 20 columns in this sub-table)
# and a where clause if you want a subset of the rows

# do calculations on this frame
new_frame = cool_function_on_frame(frame)

# to 'add columns', create a new group (you probably want to
# limit the columns in this new_group to be only NEW ones
# (e.g. so you don't overlap from the other tables)
# add this info to the group_map
store.append(new_group, new_frame.reindex(columns = new_columns_created, copy = False), data_columns = new_columns_created)

Когда вы будете готовы к post_processing:

# This may be a bit tricky; and depends what you are actually doing.
# I may need to modify this function to be a bit more general:
report_data = store.select_as_multiple([groups_1,groups_2,.....], where =['field_1>0', 'field_1000=foo'], selector = group_1)

Что касается data_columns, вам на самом деле не нужно определять ЛЮБЫЕ data_columns; они позволяют вам подбирать строки на основе столбца. Например, что-то вроде:

store.select(group, where = ['field_1000=foo', 'field_1001>0'])

Они могут быть наиболее интересны вам на этапе генерации окончательного отчета (по сути, столбец данных отделен от других столбцов, что может несколько повлиять на эффективность, если вы определите много).

Вы также можете:

  • создать функцию, которая принимает список полей, ищет группы в groups_map, затем выбирает их и объединяет результаты, чтобы вы получили результирующий фрейм (по сути, это то, что делает select_as_multiple). Таким образом, структура будет для вас довольно прозрачной.
  • индексирует определенные столбцы данных (значительно ускоряет подмножество строк).
  • активировать сжатие.

Дайте мне знать, если у вас возникнут вопросы!

17
  • 5
    Спасибо за ссылки. Вторая ссылка меня немного беспокоит, что я не могу добавлять новые столбцы в таблицы в HDFStore? Это верно? Также я добавил пример того, как я буду использовать эту настройку. Zelazny7 10 янв.
  • 5
    Фактическая структура в hdf зависит от вас. Pytables ориентирован на строки с фиксированными столбцами во время создания. После создания таблицы нельзя добавлять столбцы. Однако вы можете создать новую таблицу с таким же индексом, как и ваша существующая таблица. (см. примеры select_as_multiple в документации). Таким образом, вы можете создавать объекты произвольного размера, имея при этом довольно эффективные запросы. То, как вы используете данные, является ключом к тому, как они должны быть организованы на диске. Отправьте мне письмо вне списка с псевдокодом более конкретного примера. Jeff 11 янв.
  • 1
    Я обновил свой вопрос, чтобы ответить на ваши подробные моменты. Я буду работать над примером, чтобы отправить вас вне списка. Спасибо! Zelazny7 11 янв.
  • 13
    @Jeff, теперь Pandas находится на уровне 0.17.x, решены ли проблемы, описанные выше, в Pandas? ctrl-alt-delete 13 янв.
  • 9
    @Jeff хочет добавить быстрое обновление своего ответа для продвижения dask? Zeugma 9 сен '16 в 18:10
162

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

Когда у меня есть файл, который слишком велик для загрузки в память, я разбиваю файл на несколько файлов меньшего размера (либо по строкам, либо по столбцам).

Пример: в случае 30-дневных торговых данных размером ~ 30 ГБ, я разбиваю их на дневной файл размером ~ 1 ГБ. Впоследствии я обрабатываю каждый файл отдельно и обобщаю результаты в конце

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

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

Этот подход не охватывает все сценарии, но очень полезен во многих из них.

2
103

Теперь, через два года после вопроса, есть « внятерный» эквивалент панды: dask . Это превосходно! Хотя он не поддерживает все функции pandas, с ним можно очень далеко продвинуться. Обновление: в течение последних двух лет он постоянно поддерживался, и с Dask работает значительное сообщество пользователей.

И теперь, спустя четыре года после этого вопроса, в Vaex есть еще один высокопроизводительный аналог панды вне ядра . Он «использует отображение памяти, политику нулевого копирования памяти и ленивые вычисления для лучшей производительности (без потери памяти)». Он может обрабатывать наборы данных из миллиардов строк и не сохранять их в памяти (что позволяет даже проводить анализ на неоптимальном оборудовании).

3
  • 6
    а для полностью проработанного примера с dask просто посмотрите здесь stackoverflow.com/questions/37979167/…ℕʘʘḆḽḘ 9 фев '17 в 15:58
  • 1
    В зависимости от ваших данных имеет смысл заглянуть в pystore . Он полагается на dask. gies0r 1 мая '20 в 20:54
  • 4
    Всегда ли "вне ядра"? (т.е. не требует интенсивного использования ОЗУ?). ИМХО, если у вас нет кластера под рукой, Даск - не лучшее решение. Цитата из самой документации Dask : «Если вы хотите управлять терабайтом или меньше табличных данных CSV или JSON, вам следует забыть и Spark, и Dask и использовать Postgres или MongoDB». Michele Piccolini 30 июля '20 в 18: 512020-07-30 15:51
70

Если ваши наборы данных составляют от 1 до 20 ГБ, вы должны получить рабочую станцию ​​с 48 ГБ оперативной памяти. Тогда Pandas может хранить весь набор данных в ОЗУ. Я знаю, что это не тот ответ, который вы здесь ищете, но выполнять научные вычисления на ноутбуке с 4 ГБ оперативной памяти нецелесообразно.

7
  • 11
    «делать научные вычисления на ноутбуке с 4 ГБ ОЗУ нецелесообразно» Определить разумно. Я думаю, что UNIVAC придерживается другой точки зрения. arstechnica.com/tech-policy/2011/09/…grisaitis 26 авг.
  • 3
    Согласовано! попробуйте продолжить работу с памятью, даже если это будет стоить $$ аванс. Если ваша работа приносит финансовую прибыль, то со временем вы окупите расходы за счет повышения эффективности. ansonw 10 ноя '17 в 17:57
  • 4
    Выполнение научных вычислений на рабочей станции с 48 ГБ оперативной памяти нецелесообразно. Yaroslav Nikitenko 6 апр '19 в 6:52
  • 5
    @YaroslavNikitenko r4.2xlarge с 61 ГБ / ОЗУ стоит 0,532 доллара в час. Какие научные вычисления вы не так цените? Звучит необычно, если не безосновательно. rjurney 6 апр '19 в 22:39
  • 4
    @rjurney извини, может мне стоило удалить свой комментарий. Ваше суждение о «необоснованном» научном компьютере кажется очень субъективным. Я годами выполняю свои научные вычисления на ноутбуках, и этого мне кажется достаточно, потому что большую часть времени я пишу код. Мои алгоритмы намного сложнее с точки зрения программирования, чем с вычислительной. Также я почти уверен, что для написания масштабируемых алгоритмов не следует полагаться на текущие аппаратные ограничения. Ваш комментарий о вычислениях других людей может показаться немного оскорбительным (не считая субъективности), не могли бы вы удалить эти несколько слов? Yaroslav Nikitenko 7 апр '19 в 6:05
64

Я знаю, что это старая ветка, но я думаю, что стоит попробовать библиотеку Blaze . Он создан для таких ситуаций.

Из документов:

Blaze расширяет возможности использования NumPy и Pandas для распределенных вычислений и вычислений вне ядра. Blaze предоставляет интерфейс, аналогичный интерфейсу NumPy ND-Array или Pandas DataFrame, но отображает эти знакомые интерфейсы на множество других вычислительных механизмов, таких как Postgres или Spark.

Изменить: кстати, он поддерживается ContinuumIO и Трэвисом Олифантом, автором NumPy.

1
  • Еще одна библиотека, на которую, возможно, стоит обратить внимание, - это GraphLab Create: она имеет эффективную структуру, подобную DataFrame, которая не ограничена объемом памяти. blog.dato.com/…waterproof 22 апр '15 в 16:17
57

Так обстоит дело с пимонго. Я также создал прототип с использованием sql server, sqlite, HDF, ORM (SQLAlchemy) на python. В первую очередь, pymongo - это база данных на основе документов, поэтому каждый человек будет документом ( dictатрибутов). Многие люди формируют коллекцию, и у вас может быть много коллекций (люди, фондовый рынок, доход).

pd.dateframe -> pymongo Примечание: я использую chunksizein, read_csvчтобы сохранить от 5 до 10k записей (pymongo отбрасывает сокет, если он больше)

aCollection.insert((a[1].to_dict() for a in df.iterrows()))

запрос: gt = больше, чем ...

pd.DataFrame(list(mongoCollection.find({'anAttribute':{'$gt':2887000, '$lt':2889000}})))

.find()возвращает итератор, поэтому я обычно использую его ichunkedдля разделения на итераторы меньшего размера.

Как насчет соединения, так как я обычно получаю 10 источников данных, которые нужно склеить:

aJoinDF = pandas.DataFrame(list(mongoCollection.find({'anAttribute':{'$in':Att_Keys}})))

затем (в моем случае иногда мне нужно сначала аггировать, aJoinDFпрежде чем его "объединить".)

df = pandas.merge(df, aJoinDF, on=aKey, how='left')

Затем вы можете записать новую информацию в свою основную коллекцию с помощью метода обновления ниже. (логическая коллекция против физических источников данных).

collection.update({primarykey:foo},{key:change})

При поиске меньшего размера просто денормализуйте. Например, у вас есть код в документе, и вы просто добавляете текст кода поля и выполняете dictпоиск по мере создания документов.

Теперь у вас есть хороший набор данных, основанный на человеке, вы можете раскрыть свою логику для каждого случая и создать больше атрибутов. Наконец, вы можете считывать в pandas свои 3 максимальных ключевых индикатора в памяти и выполнять сводные / агрегированные / исследования данных. Это работает для меня для 3 миллионов записей с числами / большим текстом / категориями / кодами / числами / ...

Вы также можете использовать два метода, встроенные в MongoDB (MapReduce и агрегатный фреймворк). См. Здесь для получения дополнительной информации об агрегатной структуре , поскольку она кажется проще, чем MapReduce, и удобна для быстрой агрегатной работы. Обратите внимание, что мне не нужно определять свои поля или отношения, и я могу добавлять элементы в документ. В текущем состоянии быстро меняющегося набора инструментов numpy, pandas, python MongoDB помогает мне просто приступить к работе :)

2
  • Привет, я играю с вашим примером , а также и я бегу в эту ошибку при попытке вставить в базу данных: In [96]: test.insert((a[1].to_dict() for a in df.iterrows())) --------------- InvalidDocument: Cannot encode object: 0. Есть идеи, что может быть не так? Мой фрейм данных состоит из всех типов int64 и очень прост. Zelazny7 16 янв.
  • 2
    Да, я сделал то же самое для простого диапазона DF, а int64 от numpy, похоже, беспокоит pymongo. Все данные, с которыми я играл, конвертируются из CSV (против искусственно с помощью range ()) и имеют длинные типы и, следовательно, без проблем. В numpy вы можете конвертировать, но я считаю, что это отвлекает. Я должен признать, что пункты 10.1 для HDF выглядят захватывающе. brian_the_bungler 17 янв.
53

Один прием, который я нашел полезным для случаев использования больших данных, - это уменьшить объем данных за счет уменьшения точности с плавающей запятой до 32-битной. Это применимо не во всех случаях, но во многих приложениях 64-битная точность является излишней, и двукратная экономия памяти того стоит. Чтобы сделать очевидный момент еще более очевидным:

>>> df = pd.DataFrame(np.random.randn(int(1e8), 5))
>>> df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 100000000 entries, 0 to 99999999
Data columns (total 5 columns):
...
dtypes: float64(5)
memory usage: 3.7 GB

>>> df.astype(np.float32).info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 100000000 entries, 0 to 99999999
Data columns (total 5 columns):
...
dtypes: float32(5)
memory usage: 1.9 GB
1
  • Вообще говоря, я считаю, что вам следует внимательно относиться к каждому типу столбцов и иметь команду, которая обрабатывает их последовательно. Это позволяет выполнять дальнейшее понижающее преобразование (до небольшого int или, что еще лучше, категории). В зависимости от цели вы можете даже использовать какой-нибудь «трюк», например, изменить используемую единицу (использование k $ может помочь вам преобразовать все в int16) или сгруппировать вещи по категориям. В идеале это должно быть сделано до первого экспорта. lcrmorin 24 окт.
48

Я заметил это немного поздно, но я работаю с аналогичной проблемой (модели предоплаты по ипотеке). Мое решение заключалось в том, чтобы пропустить слой pandas HDFStore и использовать прямые таблицы pytables. Я сохраняю каждый столбец как отдельный массив HDF5 в моем окончательном файле.

Мой основной рабочий процесс - сначала получить файл CSV из базы данных. Я сжимаю его, поэтому он не такой большой. Затем я конвертирую его в файл HDF5, ориентированный на строки, перебирая его в Python, преобразовывая каждую строку в реальный тип данных и записывая ее в файл HDF5. На это уходит несколько десятков минут, но при этом не используется память, поскольку выполняется только построчно. Затем я «транспонирую» строковый файл HDF5 в файл HDF5, ориентированный на столбцы.

Перестановка таблицы выглядит так:

def transpose_table(h_in, table_path, h_out, group_name="data", group_path="/"):
    # Get a reference to the input data.
    tb = h_in.getNode(table_path)
    # Create the output group to hold the columns.
    grp = h_out.createGroup(group_path, group_name, filters=tables.Filters(complevel=1))
    for col_name in tb.colnames:
        logger.debug("Processing %s", col_name)
        # Get the data.
        col_data = tb.col(col_name)
        # Create the output array.
        arr = h_out.createCArray(grp,
                                 col_name,
                                 tables.Atom.from_dtype(col_data.dtype),
                                 col_data.shape)
        # Store the data.
        arr[:] = col_data
    h_out.flush()

Чтение его тогда выглядит так:

def read_hdf5(hdf5_path, group_path="/data", columns=None):
    """Read a transposed data set from a HDF5 file."""
    if isinstance(hdf5_path, tables.file.File):
        hf = hdf5_path
    else:
        hf = tables.openFile(hdf5_path)

    grp = hf.getNode(group_path)
    if columns is None:
        data = [(child.name, child[:]) for child in grp]
    else:
        data = [(child.name, child[:]) for child in grp if child.name in columns]

    # Convert any float32 columns to float64 for processing.
    for i in range(len(data)):
        name, vec = data[i]
        if vec.dtype == np.float32:
            data[i] = (name, vec.astype(np.float64))

    if not isinstance(hdf5_path, tables.file.File):
        hf.close()
    return pd.DataFrame.from_items(data)

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

Обычно это работает для меня, но это немного неуклюже, и я не могу использовать причудливую магию pytables.

Изменить: реальное преимущество этого подхода перед массивом записей по умолчанию в pytables заключается в том, что я могу затем загрузить данные в R с помощью h5r, который не может обрабатывать таблицы. Или, по крайней мере, мне не удалось заставить его загружать разнородные таблицы.

4
  • не могли бы вы поделиться со мной частью своего кода? Меня интересует, как вы загружаете данные из некоторого плоского текстового формата, не зная типов данных, прежде чем нажимать на pytables. Кроме того, похоже, что вы работаете только с данными одного типа. Это верно? Zelazny7 27 марта '13 в 2:01
  • 1
    Прежде всего, я предполагаю, что я знаю типы столбцов до загрузки, а не пытаюсь угадать их по данным. Я сохраняю файл «спецификации данных» JSON с именами и типами столбцов и использую его при обработке данных. (Обычно файл представляет собой ужасный вывод BCP без каких-либо меток.) ​​Типы данных, которые я использую, - это строки, числа с плавающей запятой, целые числа или месячные даты. Я превращаю строки в целые числа, сохраняя таблицу перечисления и конвертирую даты в целые числа (месяцы после 2000 года), поэтому в моих данных остаются целые числа и числа с плавающей запятой, а также перечисление. Сейчас я сохраняю числа с плавающей запятой как float64, но я экспериментировал с float32. Johann Hibschman 28 марта '13 в 16: 342013-03-28 16:34
  • 1
    если у вас есть время, пожалуйста , попробуйте внешнюю совместимость с R: pandas.pydata.org/pandas-docs/dev/… , и если у вас возникнут трудности, возможно, мы сможем его настроитьJeff 1 апр '13 в 16:50
  • Я попробую, если смогу. rhdf5 - это боль, поскольку это пакет биопроводников, а не просто использование CRAN, как h5r. Я во власти нашей команды технической архитектуры, и в прошлый раз, когда я попросил об этом, была проблема с rhdf5. В любом случае кажется ошибкой ориентироваться на строки, а не на столбцы, в хранилище OLAP, но теперь я бессвязно. Johann Hibschman 01 апр '13 в 20:09
37

Как отмечали другие, спустя несколько лет появился « внятерный» эквивалент панды: dask . Хотя dask не является заменой pandas и всей его функциональности, он выделяется по нескольким причинам:

Dask - это гибкая библиотека параллельных вычислений для аналитических вычислений, оптимизированная для динамического планирования задач для интерактивных вычислительных рабочих нагрузок коллекций «больших данных», таких как параллельные массивы, фреймы данных и списки, которые расширяют общие интерфейсы, такие как итераторы NumPy, Pandas или Python, на более крупные - чем память или распределенные среды и масштабируется от ноутбуков до кластеров.

Dask emphasizes the following virtues:

  • Familiar: Provides parallelized NumPy array and Pandas DataFrame objects
  • Flexible: Provides a task scheduling interface for more custom workloads and integration with other projects.
  • Native: Enables distributed computing in Pure Python with access to the PyData stack.
  • Fast: Operates with low overhead, low latency, and minimal serialization necessary for fast numerical algorithms
  • Scales up: Runs resiliently on clusters with 1000s of cores Scales down: Trivial to set up and run on a laptop in a single process
  • Responsive: Designed with interactive computing in mind it provides rapid feedback and diagnostics to aid humans

и добавить простой пример кода:

import dask.dataframe as dd
df = dd.read_csv('2015-*-*.csv')
df.groupby(df.user_id).value.mean().compute()

заменяет некоторый код pandas следующим образом:

import pandas as pd
df = pd.read_csv('2015-01-01.csv')
df.groupby(df.user_id).value.mean()

и, что особенно важно, предоставляет через concurrent.futuresинтерфейс общую инфраструктуру для отправки пользовательских задач:

from dask.distributed import Client
client = Client('scheduler:port')

futures = []
for fn in filenames:
    future = client.submit(load, fn)
    futures.append(future)

summary = client.submit(summarize, futures)
summary.result()
2
  • Я добавил этот ответ, так как сообщение @Private регулярно появляется в списке предложенных для удаления по содержанию и длине. wp78de 22 ноя '17 в 3:57
  • Dask хорош, если вам не нужен мультииндекс. Отсутствие мультииндексирования на момент написания является серьезной проблемой. misantroop 8 сен '20 в 4:41
24

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

Просто замените импорт панд, и код должен работать как есть:

# import pandas as pd
import ray.dataframe as pd

# use pd as usual

подробнее можно прочитать здесь:

https://rise.cs.berkeley.edu/blog/pandas-on-ray/


Обновление: часть, которая обрабатывает распространение pandas, была извлечена в проект модификации .

правильный способ его использования сейчас:

# import pandas as pd
import modin.pandas as pd
21

Еще одна вариация

Многие операции, выполняемые в pandas, также могут быть выполнены как запрос к базе данных (sql, mongo)

Использование СУБД или mongodb позволяет выполнять некоторые агрегации в запросе к БД (который оптимизирован для больших данных и эффективно использует кеш и индексы)

Позже вы можете выполнить постобработку с помощью панд.

Преимущество этого метода заключается в том, что вы получаете оптимизацию БД для работы с большими данными, при этом определяя логику в декларативном синтаксисе высокого уровня - и вам не нужно иметь дело с деталями решения, что делать в памяти и что делать. ядра.

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

14

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

13

Особо отмечу пакет Vaex.

Vaex is a python library for lazy Out-of-Core DataFrames (similar to Pandas), to visualize and explore big tabular datasets. It can calculate statistics such as mean, sum, count, standard deviation etc, on an N-dimensional grid up to a billion (109) objects/rows per second. Visualization is done using histograms, density plots and 3d volume rendering, allowing interactive exploration of big data. Vaex uses memory mapping, zero memory copy policy and lazy computations for best performance (no memory wasted).

Взгляните на документацию: https://vaex.readthedocs.io/en/latest/ API очень близок к API панд.

11

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

def addDateColumn():
"""Adds time to the daily rainfall data. Reads the csv as chunks of 100k 
   rows at a time and outputs them, appending as needed, to a single csv. 
   Uses the column of the raster names to get the date.
"""
    df = pd.read_csv(pathlist[1]+"CHIRPS_tanz.csv", iterator=True, 
                     chunksize=100000) #read csv file as 100k chunks

    '''Do some stuff'''

    count = 1 #for indexing item in time list 
    for chunk in df: #for each 100k rows
        newtime = [] #empty list to append repeating times for different rows
        toiterate = chunk[chunk.columns[2]] #ID of raster nums to base time
        while count <= toiterate.max():
            for i in toiterate: 
                if i ==count:
                    newtime.append(newyears[count])
            count+=1
        print "Finished", str(chunknum), "chunks"
        chunk["time"] = newtime #create new column in dataframe based on time
        outname = "CHIRPS_tanz_time2.csv"
        #append each output to same csv, using no header
        chunk.to_csv(pathlist[2]+outname, mode='a', header=None, index=None)
0

Формат файла parquet идеально подходит для описанного вами варианта использования. Вы можете эффективно читать в определенном подмножестве столбцов с помощьюpd.read_parquet(path_to_file, columns=["foo", "bar"])

https://pandas.pydata.org/docs/reference/api/pandas.read_parquet.html

-2

В настоящий момент я работаю «как» вы, только на более низком уровне, поэтому у меня нет PoC для моего предложения.

Тем не менее, мне кажется, что я успешно использую pickle в качестве системы кэширования и передаю выполнение различных функций в файлы на аутсорсинг - выполняя эти файлы из моего командного / основного файла; Например, я использую prepare_use.py для преобразования типов объектов, разделения набора данных на набор данных для тестирования, проверки и прогнозирования.

Как работает ваше кеширование с помощью pickle? Я использую строки для доступа к файлам рассола, которые создаются динамически, в зависимости от того, какие параметры и наборы данных были переданы (при этом я пытаюсь захватить и определить, была ли программа уже запущена, используя .shape для набора данных, dict для переданного параметры). Соблюдая эти меры, я получаю String, чтобы попытаться найти и прочитать .pickle-файл, и могу, если он найден, пропустить время обработки, чтобы перейти к выполнению, над которым я работаю прямо сейчас.

Используя базы данных, я столкнулся с аналогичными проблемами, поэтому я нашел удовольствие в использовании этого решения, однако - есть много ограничений - например, хранение огромных наборов солений из-за избыточности. Обновление таблицы до и после преобразования может быть выполнено с помощью правильной индексации - проверка информации открывает целую другую книгу (я попытался объединить просканированные данные об аренде и в основном перестал использовать базу данных через 2 часа - так как я бы хотел вернуться после каждый процесс трансформации)

Надеюсь, мои 2 цента вам чем-то помогут.

Привет.