Додавання метаінформації / метаданих до pandas DataFrame


90

Чи можна додати певну метаінформацію / метадані до pandas DataFrame?

Наприклад, назва приладу, що використовується для вимірювання даних, відповідальний прилад тощо.

Одним з обхідних шляхів було б створення стовпця з цією інформацією, але здається марним зберігати по одній інформації в кожному рядку!


Зверніть увагу на відповідь @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, можна знайти тут .


5
+1 для вибору назви інструменту! Чи є у вас досвід спроби скинути ці додаткові атрибути в HDFStore?
Dan Allan,

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

Просто сам натрапив на це питання. Починаючи з панд 0,13, DataFrames мають атрибут _metadata, який зберігається через функції, які повертають нові DataFrames. Також, здається, цілком виживає серіалізація (я пробував лише json, але, думаю, hdf також охоплений).


16
_metadataне є частиною загальнодоступного API, тому я настійно рекомендую не покладатися на цю функціональність.
шоєр

@Stephan, ти можеш детальніше це пояснити? Чому важливо бути частиною загальнодоступного API? Чи справедливо ваше твердження і для версії 0.15?
TomCho

1
@TomCho так, ця відповідь і сьогодні відповідає дійсності. Ви можете поглянути на xray ( github.com/xray/xray ) для одного альтернативного прикладу позначеного масиву, який підтримує метадані, особливо якщо у вас є багатовимірні дані ( .attrsє частиною API xray)
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

Станом на панд 1.0, можливо раніше, зараз є Dataframe.attrsвласність. Це експериментально, але це, мабуть, те, що вам потрібно в майбутньому. Наприклад:

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

Знайдіть його в документації тут .

Спробуйте це, to_parquetа потім from_parquet, здається, не зберігається, тому обов’язково перевірте це у своєму випадку використання.


Це цікаво і, здається, зберігається для copy / loc / iloc, але не для groupby.
JohnE

Просто пропозиція, але, можливо, покажіть приклад, як нею користуватися? Документація в основному нічого, але, лише погравши з нею, я бачу, що вона ініціалізується як порожній словник і, схоже, налаштована таким чином, що це повинен бути словник, хоча, звичайно, можна вкласти в неї список, наприклад.
JohnE

1
Вам може здатися це обговорення Stackoverflow корисним, оскільки воно демонструє, як додати власні метадані до паркетних файлів, якщо потрібно
rdmolony

1
@rdmolony Це чудово. Я думаю, що використання a dataclassдля метаданих, а потім підкласифікація, DataFrameщоб мати метод, що виконує навантаження / скидання, як у дописі, яким ви поділилися, може бути гарним рішенням.
рянджділлон

1
Це добре. На відміну від прийнятої відповіді, це зберігає атрибути після збереження та завантаження з розсолу!
CGFoX

8

Найкраща відповідь на приєднання довільних атрибутів до об'єкта DataFrame хороша, але якщо ви використовуєте словник, список або кортеж, це видасть помилку "Pandas не дозволяють створювати стовпці за допомогою нового імені атрибута". Наступне рішення працює для зберігання довільних атрибутів.

from types import SimpleNamespace
df = pd.DataFrame()
df.meta = SimpleNamespace()
df.meta.foo = [1,2,3]

Крім того, якщо ви хочете, щоб це зберігалося в усіх копіях вашого фрейму даних, вам потрібно це зробити pd.DataFrame._metadata += ["meta"]. Зверніть увагу, що ця частина є атрибутом Pandas, а не атрибутом вашого конкретного фрейму даних
bscan

Цей підхід більше не працюватиме, оскільки 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

Прийшовши до цього досить пізно, я подумав, що це може бути корисним, якщо вам потрібні метадані для збереження над I / O. Існує відносно новий пакет під назвою 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

2

Я шукав рішення і виявив, що фрейм панд має властивість attrs

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

Цей атрибут завжди буде прилипати до вашого кадру щоразу, коли ви його передасте!


Зверніть увагу, що attrs є експериментальним і може змінюватися без попередження, але це дуже просте рішення. Цікаво, чи attrs передає нові кадри даних.
Liquidgenius

На жаль, атрибути не копіюються в нові кадри даних :(
Адам,

1

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

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

Потім цю dfMeta можна зберегти поряд із початковим DF у засолі тощо

Див. Розділ Збереження та завантаження декількох об’єктів у файлі засолу? (Відповідь Луца) для чудової відповіді щодо збереження та отримання декількох кадрів даних за допомогою засолу

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