Добавление метаинформации / метаданных в pandas DataFrame

90

Можно ли добавить некоторую метаинформацию / метаданные в DataFrame pandas?

Например, название инструмента, используемого для измерения данных, ответственный инструмент и т. Д.

Одним из способов решения этой проблемы было бы создание столбца с этой информацией, но кажется расточительным хранить одну часть информации в каждой строке!

P3trus
источник
Обратите внимание на ответ @ryanjdillon (в настоящее время похороненный внизу), в котором упоминается обновленный экспериментальный атрибут attrs, который, возможно, кажется началом
JohnE

Ответы:

85

Конечно, как и большинство объектов Python, вы можете прикрепить новые атрибуты к pandas.DataFrame:

import pandas as pd
df = pd.DataFrame([])
df.instrument_name = 'Binky'

Однако следует отметить, что в то время как вы можете прикрепить атрибуты к DataFrame, операции , выполняемые на DataFrame (например groupby, pivot, joinили locназвать только некоторые из них) может вернуть новый DataFrame без метаданных прилагается. У Pandas пока нет надежного метода распространения метаданных, прикрепленных к DataFrames .

Возможно сохранение метаданных в файле . Вы можете найти пример того , как для хранения метаданных в файле HDF5 здесь .

Unutbu
источник
5
+1 за ваш выбор названия инструмента! У вас есть опыт попытки сбросить эти дополнительные атрибуты в HDFStore?
Дэн Аллан
4
@DanAllan: Если store = pd.HDFStore(...), тогда атрибуты могут быть сохранены с помощью store.root._v_attrs.key = value.
unutbu
3
Всем, кто может это использовать: в документации добавлен раздел об этом. pandas.pydata.org/pandas-docs/dev/cookbook.html#hdfstore
Дэн Аллан,
4
В pandas 0.23.1 создание нового атрибута путем назначения словаря, списка или кортежа дает предупреждение (т . Е. df = pd.DataFrame(); df.meta = {}Производит UserWarning: Pandas doesn't allow columns to be created via a new attribute name - see https://pandas.pydata.org/pandas-docs/stable/indexing.html#attribute-access). (Предупреждение не выводится, если атрибут уже был создан, как в df = pd.DataFrame(); df.meta = ''; df.meta = {}).
teichert
13

Просто столкнулся с этой проблемой сам. Начиная с pandas 0.13, DataFrames имеет атрибут _metadata, который сохраняется через функции, возвращающие новые DataFrames. Также кажется, что сериализация прекрасно переживает (я пробовал только json, но я думаю, что hdf тоже покрыт).

глупая крыша
источник
16
_metadataне является частью общедоступного API, поэтому я настоятельно рекомендую не полагаться на эту функцию.
shoyer
@ Стефан, не могли бы вы рассказать об этом подробнее? Почему важно быть частью публичного API? Верно ли ваше утверждение и для версии 0.15?
TomCho
1
@TomCho: да, этот ответ верен и сегодня. Вы можете взглянуть на xray ( github.com/xray/xray ) для одного альтернативного примера помеченного массива, который поддерживает метаданные, особенно если у вас есть многомерные данные ( .attrsявляются частью xray API)
shoyer
17
_metadataфактически является атрибутом класса, а не атрибутом экземпляра. Таким образом, новые DataFrameэкземпляры наследуются от предыдущих, пока модуль остается загруженным. Не использовать _metadataни для чего. +1 за xarray!
j08lue
1
_metadata - неподдерживаемая функция, которая спасла мне день! Спасибо.
joctee
12

На самом деле, нет. Хотя вы можете добавить атрибуты, содержащие метаданные, в класс DataFrame, как упоминает @unutbu, многие методы DataFrame возвращают новый DataFrame, поэтому ваши метаданные будут потеряны. Если вам нужно манипулировать фреймом данных, лучшим вариантом будет перенос ваших метаданных и DataFrame в другой класс. См. Это обсуждение на GitHub: https://github.com/pydata/pandas/issues/2485

В настоящее время существует открытый запрос на добавление объекта MetaDataFrame, который лучше поддерживает метаданные.

Матти Джон
источник
11

Начиная с pandas 1.0, возможно, раньше, теперь есть Dataframe.attrsсвойство. Это экспериментально, но, вероятно, это то, что вам понадобится в будущем. Например:

import pandas as pd
df = pd.DataFrame([])
df.attrs['instrument_name'] = 'Binky'

Найдите это в документации здесь .

Попробуйте это с помощью, to_parquetа затем from_parquet, похоже, это не сохраняется, поэтому обязательно проверьте это в своем варианте использования.

ryanjdillon
источник
Это интересно и, похоже, сохраняется для copy / loc / iloc, но не для groupby.
JohnE
Просто предложение, но, может быть, покажите пример, как его использовать? Документация в основном пустая, но просто поиграв с ней, я вижу, что она инициализирована как пустой словарь и, кажется, настроена так, что это должен быть словарь, хотя, конечно, можно вложить в него список, например.
JohnE
1
Вы можете найти это обсуждение Stackoverflow полезным, поскольку оно демонстрирует, как при необходимости добавлять пользовательские метаданные в файлы паркета
rdmolony
1
@rdmolony Замечательно. Я думаю, что использование a dataclassдля метаданных, а затем DataFrameсоздание подкласса для метода, выполняющего загрузку / сброс, как в сообщении, которым вы поделились, может быть хорошим решением.
ryanjdillon
1
Это мило. В отличие от принятого ответа, это сохраняет атрибуты после сохранения и загрузки из рассола!
CGFoX
8

Главный ответ - прикрепление произвольных атрибутов к объекту DataFrame - это хорошо, но если вы используете словарь, список или кортеж, он выдаст ошибку «Pandas не позволяет создавать столбцы с новым именем атрибута». Следующее решение работает для хранения произвольных атрибутов.

from types import SimpleNamespace
df = pd.DataFrame()
df.meta = SimpleNamespace()
df.meta.foo = [1,2,3]
bscan
источник
Кроме того, если вы хотите, чтобы это сохранялось во всех копиях вашего фрейма данных, вам необходимо это сделать pd.DataFrame._metadata += ["meta"]. Обратите внимание, что эта часть является атрибутом Pandas, а не атрибутом вашего конкретного
фрейма данных
Этот подход больше не будет работать, поскольку df.metaвызывает предупреждение о том, что Pandas не позволяет создавать новые столбцы таким образом.
anishtain4
@ anishtain4, я только что тестировал его с Pandas 25.1 (выпущен ~ 2 недели назад), и этот код все еще у меня работает. Это предупреждение не срабатывает, так df.metaкак это SimpleNamespace. Панды не будут пытаться построить из него колонну.
bscan
6

Как упоминалось в других ответах и ​​комментариях, _metadataне является частью общедоступного API, поэтому определенно не рекомендуется использовать его в производственной среде. Но вы все равно можете использовать его в исследовательском прототипе и заменить, если он перестанет работать. И сейчас он работает с groupby/ apply, что очень полезно. Это пример (который я не нашел в других ответах):

df = pd.DataFrame([1, 2, 2, 3, 3], columns=['val']) 
df.my_attribute = "my_value"
df._metadata.append('my_attribute')
df.groupby('val').apply(lambda group: group.my_attribute)

Выход:

val
1    my_value
2    my_value
3    my_value
dtype: object
Денис Голомазов
источник
4

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

Он должен позволить вам выполнять быстрое чтение / запись из HDF5 для нескольких распространенных форматов, одним из которых является фрейм данных. Таким образом, вы можете, например, поместить фрейм данных в словарь и включить метаданные в качестве полей в словарь. Например:

save_dict = dict(data=my_df, name='chris', record_date='1/1/2016')
h5io.write_hdf5('path/to/file.hdf5', save_dict)
in_data = h5io.read_hdf5('path/to/file.hdf5')
df = in_data['data']
name = in_data['name']
etc...

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

холдграф
источник
4

Как упоминал @choldgraf, я обнаружил, что xarray является отличным инструментом для прикрепления метаданных при сравнении данных и построении результатов между несколькими фреймами данных.

В своей работе мы часто сравниваем результаты нескольких ревизий прошивки и разных тестовых сценариев, добавить эту информацию очень просто:

df = pd.read_csv(meaningless_test)
metadata = {'fw': foo, 'test_name': bar, 'scenario': sc_01}
ds = xr.Dataset.from_dataframe(df)
ds.attrs = metadata
Jtwilson
источник
2

Я искал решение и обнаружил, что рамка панды имеет свойство attrs

pd.DataFrame().attrs.update({'your_attribute' : 'value'})
frame.attrs['your_attribute']

Этот атрибут всегда будет прикрепляться к вашему кадру, когда вы его пройдете!

Айрат Арифуллин
источник
Обратите внимание, что attrs является экспериментальным и может изменяться без предупреждения, но это очень простое решение. Интересно, переносится ли attrs на новые фреймы данных.
Liquidgenius
К сожалению, attrs не копируется в новые фреймы данных :(
Адам
1

У меня была такая же проблема, и я использовал обходной путь создания нового DF меньшего размера из словаря с метаданными:

    meta = {"name": "Sample Dataframe", "Created": "19/07/2019"}
    dfMeta = pd.DataFrame.from_dict(meta, orient='index')

Затем этот dfMeta можно сохранить вместе с исходным DF в рассоле и т. Д.

См. Раздел Сохранение и загрузка нескольких объектов в файл рассола? (Ответ Лутца) за отличный ответ по сохранению и извлечению нескольких фреймов данных с помощью рассола

СенАнан
источник