Aggiunta di meta-informazioni / metadati a DataFrame di panda


93

È possibile aggiungere alcune meta-informazioni / metadati a un DataFrame panda?

Ad esempio, il nome dello strumento utilizzato per misurare i dati, lo strumento responsabile, ecc.

Una soluzione alternativa sarebbe creare una colonna con quelle informazioni, ma sembra uno spreco memorizzare una singola informazione in ogni riga!


Si prega di notare la risposta @ryanjdillon (attualmente sepolta vicino al fondo) che menziona l'attributo sperimentale aggiornato "attrs" che sembra un inizio, forse
JohnE

Risposte:


87

Certo, come la maggior parte degli oggetti Python, puoi allegare nuovi attributi a pandas.DataFrame:

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

Si noti, tuttavia, che mentre è possibile allegare attributi a un dataframe, operazioni eseguite sul dataframe (come ad esempio groupby, pivot, joino locper citarne solo alcuni) può restituire una nuova dataframe senza i metadati in allegato. Pandas non dispone ancora di un metodo affidabile per propagare i metadati allegati a DataFrames .

È possibile conservare i metadati in un file . Puoi trovare un esempio di come memorizzare i metadati in un file HDF5 qui .


5
+1 per la scelta del nome dello strumento! Hai qualche esperienza nel tentativo di scaricare questi attributi extra in HDFStore?
Dan Allan

4
@DanAllan: If store = pd.HDFStore(...), allora gli attributi possono essere memorizzati con store.root._v_attrs.key = value.
unutbu

3
A chiunque altro potrebbe usarlo: i documenti hanno aggiunto una sezione su questo. pandas.pydata.org/pandas-docs/dev/cookbook.html#hdfstore
Dan Allan


5
In panda 0.23.1, la creazione di un nuovo attributo assegnando un dizionario, una lista o una tupla dà un avvertimento (cioè df = pd.DataFrame(); df.meta = {}produce 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). (Non viene dato alcun avviso se l'attributo è già stato creato come in df = pd.DataFrame(); df.meta = ''; df.meta = {}).
teichert

14

A partire da panda 1.0, forse prima, ora c'è una Dataframe.attrsproprietà. È sperimentale, ma probabilmente è quello che vorrai in futuro. Per esempio:

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

Trovalo nei documenti qui .

Provandolo con to_parquete poi from_parquet, non sembra persistere, quindi assicurati di verificarlo con il tuo caso d'uso.


Questo è interessante e sembra persistere per copy / loc / iloc, ma non per groupby.
JohnE

Solo un suggerimento, ma magari mostrare un esempio di come usarlo? La documentazione praticamente non è nulla, ma solo giocando con essa posso vedere che è inizializzato come un dizionario vuoto e sembra essere impostato in modo che debba essere un dizionario anche se ovviamente si potrebbe annidare un elenco al suo interno, per esempio.
JohnE

1
Potresti trovare utile questa discussione su Stackoverflow in quanto dimostra come aggiungere metadati personalizzati ai file parquet, se necessario
rdmolony,

1
@rdmolony Fantastico. Penso che usare a dataclassper i metadati e poi sottoclassare DataFrameper avere un metodo che fa il caricamento / scaricamento come nel post che hai condiviso potrebbe essere una bella soluzione.
ryanjdillon

1
Questo è carino. In contrasto con la risposta accettata, questo preserva gli attributi dopo il salvataggio e il caricamento da pickle!
CGFoX

13

Mi sono imbattuto in questo problema da solo. A partire da panda 0.13, i DataFrame hanno un attributo _metadata su di essi che persiste attraverso funzioni che restituiscono nuovi DataFrame. Inoltre sembra sopravvivere alla serializzazione (ho provato solo json, ma immagino che anche hdf sia coperto).


16
_metadatanon fa parte dell'API pubblica, quindi sconsiglio vivamente di fare affidamento su questa funzionalità.
shoyer

@Stephan puoi approfondire questo per favore? Perché è importante far parte dell'API pubblica? La tua affermazione è vera anche per la versione 0.15?
TomCho

1
@ TomCho sì, quella risposta è ancora vera oggi. Potresti dare un'occhiata a xray ( github.com/xray/xray ) per un esempio alternativo di un array etichettato che supporta i metadati, specialmente se hai dati multidimensionali ( .attrsfa parte dell'API xray)
shoyer

17
_metadataè in realtà un attributo di classe, non un attributo di istanza. Quindi le nuove DataFrameistanze ereditano da quelle precedenti, fintanto che il modulo rimane caricato. Non usare _metadataper niente. +1 per xarray!
j08lue

1
_metadata: una funzione non supportata che mi ha salvato la giornata! Grazie.
joctee

12

Non proprio. Sebbene sia possibile aggiungere attributi contenenti metadati alla classe DataFrame come menzionato da @unutbu, molti metodi DataFrame restituiscono un nuovo DataFrame, quindi i metadati andrebbero persi. Se è necessario manipolare il dataframe, l'opzione migliore sarebbe racchiudere i metadati e il DataFrame in un'altra classe. Vedi questa discussione su GitHub: https://github.com/pydata/pandas/issues/2485

Attualmente esiste una richiesta pull aperta per aggiungere un oggetto MetaDataFrame, che supporterebbe meglio i metadati.


8

La risposta migliore per allegare attributi arbitrari all'oggetto DataFrame è buona, ma se usi un dizionario, un elenco o una tupla, verrà emesso un errore di "Pandas non consente la creazione di colonne tramite un nuovo nome di attributo". La seguente soluzione funziona per memorizzare attributi arbitrari.

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

Inoltre, se vuoi che questo persista tra le copie del tuo dataframe, devi farlo pd.DataFrame._metadata += ["meta"]. Nota che questa parte è un attributo di Panda, non un attributo del tuo dataframe specifico
bscan

Questo approccio non funzionerà più poiché df.metaattiva un avviso che indica che Pandas non consente la generazione di nuove colonne in questo modo.
anishtain4

@ anishtain4, l'ho appena testato con Pandas 25.1 (rilasciato ~ 2 settimane fa) e questo codice funziona ancora per me. Questo avviso non viene attivato poiché df.metaè un SimpleNamespace. I panda non proveranno a costruire una colonna da esso.
bscan

6

Come accennato in altre risposte e commenti, _metadatanon fa parte dell'API pubblica, quindi non è sicuramente una buona idea usarlo in un ambiente di produzione. Ma potresti comunque volerlo utilizzare in una prototipazione di ricerca e sostituirlo se smette di funzionare. E adesso funziona con groupby/ apply, il che è utile. Questo è un esempio (che non sono riuscito a trovare in altre risposte):

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)

Produzione:

val
1    my_value
2    my_value
3    my_value
dtype: object

4

Arrivando abbastanza tardi a questo, ho pensato che potrebbe essere utile se hai bisogno di metadati per persistere su I / O. C'è un pacchetto relativamente nuovo chiamato h5io che ho usato per ottenere questo risultato.

Dovrebbe consentire di eseguire una rapida lettura / scrittura da HDF5 per alcuni formati comuni, uno dei quali è un dataframe. Quindi puoi, ad esempio, inserire un dataframe in un dizionario e includere metadati come campi nel dizionario. Per esempio:

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...

Un'altra opzione sarebbe quella di esaminare un progetto come xray , che è più complesso in qualche modo, ma penso che ti consenta di usare i metadati ed è abbastanza facile da convertire in un DataFrame.


4

Come accennato da @choldgraf, ho trovato che xarray è uno strumento eccellente per allegare metadati quando si confrontano i dati e si tracciano i risultati tra diversi dataframe.

Nel mio lavoro, confrontiamo spesso i risultati di diverse revisioni del firmware e diversi scenari di test, aggiungere queste informazioni è semplice come questo:

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

Ho cercato una soluzione e ho scoperto che il telaio dei panda ha la proprietà attrs

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

Questo attributo si attaccherà sempre al tuo telaio ogni volta che lo passi!


Nota che attrs è sperimentale e può cambiare senza preavviso, ma questa è una soluzione molto semplice. Mi chiedo se attrae i trasferimenti a nuovi dataframe.
Liquidgenius

Sfortunatamente, gli attributi non vengono copiati nei nuovi dataframe :(
Adam

1

Stavo riscontrando lo stesso problema e ho utilizzato una soluzione alternativa per creare un nuovo DF più piccolo da un dizionario con i metadati:

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

Questo dfMeta può quindi essere salvato insieme al tuo DF originale in pickle ecc

Vedere Salvataggio e caricamento di più oggetti nel file pickle? (Risposta di Lutz) per un'eccellente risposta sul salvataggio e il recupero di più dataframe utilizzando pickle

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.