É possível adicionar alguma meta-informação / metadados a um DataFrame do pandas?
Por exemplo, o nome do instrumento usado para medir os dados, o instrumento responsável, etc.
Uma solução alternativa seria criar uma coluna com essas informações, mas parece um desperdício armazenar uma única informação em cada linha!
Respostas:
Claro, como a maioria dos objetos Python, você pode anexar novos atributos a
pandas.DataFrame
:import pandas as pd df = pd.DataFrame([]) df.instrument_name = 'Binky'
Note, no entanto, que, enquanto você pode anexar atributos para uma trama de dados, operações realizadas na trama de dados (como
groupby
,pivot
,join
ouloc
para citar apenas alguns) pode retornar uma nova trama de dados sem os metadados anexado. O Pandas ainda não possui um método robusto de propagação de metadados anexados a DataFrames .É possível preservar os metadados em um arquivo . Você pode encontrar um exemplo de como armazenar metadados em um arquivo HDF5 aqui .
fonte
store = pd.HDFStore(...)
, então, os atributos podem ser armazenados comstore.root._v_attrs.key = value
.df = pd.DataFrame(); df.meta = {}
produzUserWarning: 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
). (Nenhum aviso é dado se o atributo já foi criado como emdf = pd.DataFrame(); df.meta = ''; df.meta = {}
).A partir do pandas 1.0, possivelmente anterior, agora existe uma
Dataframe.attrs
propriedade. É experimental, mas provavelmente é isso que você desejará no futuro. Por exemplo:import pandas as pd df = pd.DataFrame([]) df.attrs['instrument_name'] = 'Binky'
Encontre-o na documentação aqui .
Tentando fazer isso com
to_parquet
e entãofrom_parquet
, não parece persistir, então certifique-se de verificar isso com seu caso de uso.fonte
dataclass
para os metadados e, em seguida,DataFrame
criar uma subclasse para ter um método de carregar / despejar como no post que você compartilhou pode ser uma boa solução.Acabei de encontrar esse problema sozinho. A partir do pandas 0.13, DataFrames têm um atributo _metadata que persiste por meio de funções que retornam novos DataFrames. Também parece sobreviver à serialização muito bem (só tentei json, mas imagino que hdf também seja coberto).
fonte
_metadata
não faz parte da API pública, então eu recomendo fortemente que você não dependa dessa funcionalidade..attrs
faz parte da API xray)_metadata
é na verdade um atributo de classe, não um atributo de instância. Portanto, novasDataFrame
instâncias herdam das anteriores, desde que o módulo permaneça carregado. Não use_metadata
para nada. 1 paraxarray
!Na verdade não. Embora você possa adicionar atributos contendo metadados à classe DataFrame como @unutbu menciona, muitos métodos DataFrame retornam um novo DataFrame, portanto, seus metadados seriam perdidos. Se você precisar manipular seu dataframe, a melhor opção seria envolver seus metadados e DataFrame em outra classe. Veja esta discussão no GitHub: https://github.com/pydata/pandas/issues/2485
Atualmente, há uma solicitação de pull aberta para adicionar um objeto MetaDataFrame, que ofereceria um suporte melhor aos metadados.
fonte
A principal resposta de anexar atributos arbitrários ao objeto DataFrame é boa, mas se você usar um dicionário, lista ou tupla, será emitido um erro de "Pandas não permite que colunas sejam criadas por meio de um novo nome de atributo". A solução a seguir funciona para armazenar atributos arbitrários.
from types import SimpleNamespace df = pd.DataFrame() df.meta = SimpleNamespace() df.meta.foo = [1,2,3]
fonte
pd.DataFrame._metadata += ["meta"]
. Observe que esta parte é um atributo dos Pandas, não um atributo do seu dataframe específicodf.meta
dispara um aviso de que o Pandas não permite que novas colunas sejam geradas dessa forma.df.meta
é um SimpleNamespace. Os Pandas não vão tentar construir uma coluna a partir dele.Conforme mencionado em outras respostas e comentários,
_metadata
não faz parte da API pública, portanto, definitivamente não é uma boa ideia usá-lo em um ambiente de produção. Mas você ainda pode querer usá-lo em um protótipo de pesquisa e substituí-lo se ele parar de funcionar. E agora ele funciona comgroupby
/apply
, o que é útil. Este é um exemplo (que não consegui encontrar em outras respostas):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)
Resultado:
val 1 my_value 2 my_value 3 my_value dtype: object
fonte
Chegando bem tarde a isso, achei que isso poderia ser útil se você precisar que os metadados persistam na E / S. Há um pacote relativamente novo chamado h5io que estou usando para fazer isso.
Ele deve permitir que você faça uma leitura / gravação rápida de HDF5 para alguns formatos comuns, um deles sendo um dataframe. Portanto, você pode, por exemplo, colocar um dataframe em um dicionário e incluir metadados como campos no dicionário. Por exemplo:
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...
Outra opção seria examinar um projeto como o xray , que é mais complexo em alguns aspectos, mas acho que permite que você use metadados e é muito fácil de converter em DataFrame.
fonte
Conforme mencionado por @choldgraf, descobri que o xarray é uma excelente ferramenta para anexar metadados ao comparar dados e traçar resultados entre vários dataframes.
Em meu trabalho, frequentemente comparamos os resultados de várias revisões de firmware e diferentes cenários de teste, adicionar essas informações é tão simples quanto isto:
df = pd.read_csv(meaningless_test) metadata = {'fw': foo, 'test_name': bar, 'scenario': sc_01} ds = xr.Dataset.from_dataframe(df) ds.attrs = metadata
fonte
Tenho procurado uma solução e descobri que a moldura dos pandas tem a propriedade
attrs
pd.DataFrame().attrs.update({'your_attribute' : 'value'}) frame.attrs['your_attribute']
Este atributo sempre ficará no seu quadro sempre que você o passar!
fonte
Eu estava tendo o mesmo problema e usei uma solução alternativa para criar um novo DF menor a partir de um dicionário com os metadados:
meta = {"name": "Sample Dataframe", "Created": "19/07/2019"} dfMeta = pd.DataFrame.from_dict(meta, orient='index')
Este dfMeta pode então ser salvo ao lado de seu DF original em picles, etc.
Consulte Salvando e carregando vários objetos no arquivo pickle? (Resposta de Lutz) pela excelente resposta sobre como salvar e recuperar vários dataframes usando pickle
fonte