Hinzufügen von Metainformationen / Metadaten zu Pandas DataFrame


88

Ist es möglich, einem Pandas DataFrame einige Metainformationen / Metadaten hinzuzufügen?

Zum Beispiel der Name des Instruments, mit dem die Daten gemessen werden, das verantwortliche Instrument usw.

Eine Problemumgehung wäre, eine Spalte mit diesen Informationen zu erstellen, aber es erscheint verschwenderisch, in jeder Zeile eine einzelne Information zu speichern!


Bitte beachten Sie die Antwort von @ryanjdillon (derzeit ganz unten vergraben), in der das aktualisierte experimentelle Attribut 'attrs' erwähnt wird, das vielleicht wie ein Anfang erscheint
JohnE

Antworten:


81

Sicher, wie bei den meisten Python-Objekten können Sie neue Attribute an Folgendes anhängen pandas.DataFrame:

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

Beachten Sie jedoch, dass , während Sie Attribute zu einem Datenrahmen anbringen können, durchgeführten Operationen auf dem Datenrahmen (wie groupby, pivot, joinoder um locnur einige zu nennen) einen neuen Datenrahmen zurückkehren können , ohne angebracht Metadaten. Pandas verfügt noch nicht über eine robuste Methode zur Weitergabe von an DataFrames angehängten Metadaten .

Das Beibehalten der Metadaten in einer Datei ist möglich. Ein Beispiel zum Speichern von Metadaten in einer HDF5-Datei finden Sie hier .


5
+1 für die Wahl des Instrumentennamens! Haben Sie Erfahrung mit dem Versuch, diese zusätzlichen Attribute in den HDFStore zu kopieren?
Dan Allan

4
@DanAllan: Wenn store = pd.HDFStore(...), dann können Attribute mit gespeichert werden store.root._v_attrs.key = value.
Unutbu

3
An alle anderen, die dies verwenden könnten: Die Dokumente haben einen Abschnitt dazu hinzugefügt. pandas.pydata.org/pandas-docs/dev/cookbook.html#hdfstore
Dan Allan


4
In Pandas 0.23.1 gibt das Erstellen eines neuen Attributs durch Zuweisen eines Wörterbuchs, einer Liste oder eines Tupels eine Warnung aus (dh df = pd.DataFrame(); df.meta = {}erzeugt 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). (Es wird keine Warnung ausgegeben, wenn das Attribut bereits wie in erstellt wurde. df = pd.DataFrame(); df.meta = ''; df.meta = {})
user3780389

11

Nicht wirklich. Obwohl Sie der DataFrame-Klasse Attribute hinzufügen können, die Metadaten enthalten, wie @unutbu erwähnt, geben viele DataFrame-Methoden einen neuen DataFrame zurück, sodass Ihre Metadaten verloren gehen. Wenn Sie Ihren Datenrahmen bearbeiten müssen, ist es am besten, Ihre Metadaten und Ihren Datenrahmen in eine andere Klasse einzubinden. Siehe diese Diskussion auf GitHub: https://github.com/pydata/pandas/issues/2485

Derzeit gibt es eine offene Pull-Anforderung zum Hinzufügen eines MetaDataFrame-Objekts, das Metadaten besser unterstützen würde.


10

Ich bin gerade auf dieses Problem gestoßen. Ab Pandas 0.13 verfügen DataFrames über ein _metadata-Attribut, das über Funktionen erhalten bleibt, die neue DataFrames zurückgeben. Scheint auch die Serialisierung gut zu überleben (ich habe nur json ausprobiert, aber ich stelle mir vor, dass auch hdf abgedeckt ist).


16
_metadataist nicht Teil der öffentlichen API, daher würde ich dringend empfehlen, sich nicht auf diese Funktionalität zu verlassen.
Shoyer

@Stephan kannst du das bitte näher erläutern? Warum ist es wichtig, Teil der öffentlichen API zu sein? Gilt Ihre Aussage auch für Version 0.15?
TomCho

1
@ TomCho ja, diese Antwort ist heute noch wahr. Sie können sich xray ( github.com/xray/xray ) ansehen, um ein alternatives Beispiel für ein beschriftetes Array zu finden, das Metadaten unterstützt, insbesondere wenn Sie mehrdimensionale Daten haben ( .attrsTeil der Röntgen-API)
Shoyer

17
_metadataist eigentlich ein Klassenattribut, kein Instanzattribut. So DataFrameerben neue Instanzen von vorherigen, solange das Modul geladen bleibt. Nicht _metadatafür irgendetwas verwenden. +1 für xarray!
j08lue

1
_metadata - eine nicht unterstützte Funktion, die meinen Tag gerettet hat! Danke dir.
Joctee

8

Ab Pandas 1.0, möglicherweise früher, gibt es jetzt eine Dataframe.attrsEigenschaft. Es ist experimentell, aber das ist wahrscheinlich das, was Sie in Zukunft wollen werden.

Finden Sie es in den Dokumenten hier .

Wenn Sie dies mit to_parquetund dann from_parquetausprobieren, scheint es nicht zu bestehen. Überprüfen Sie dies daher anhand Ihres Anwendungsfalls.


Dies ist interessant und scheint für copy / loc / iloc bestehen zu bleiben, nicht jedoch für groupby.
JohnE

Nur ein Vorschlag, aber vielleicht ein Beispiel zeigen, wie man es benutzt? Die Dokumentation ist im Grunde nichts, aber wenn ich nur damit herumspiele, kann ich sehen, dass sie als leeres Wörterbuch initialisiert ist und so eingerichtet zu sein scheint, dass es ein Wörterbuch sein muss, obwohl man natürlich eine Liste darin verschachteln könnte. beispielsweise.
JohnE

7

Die beste Antwort beim Anhängen beliebiger Attribute an das DataFrame-Objekt ist gut. Wenn Sie jedoch ein Wörterbuch, eine Liste oder ein Tupel verwenden, wird der Fehler "Pandas erlaubt nicht, dass Spalten über einen neuen Attributnamen erstellt werden" ausgegeben. Die folgende Lösung dient zum Speichern beliebiger Attribute.

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

Wenn Sie möchten, dass dies über Kopien Ihres Datenrahmens hinweg erhalten bleibt, müssen Sie dies auch tun pd.DataFrame._metadata += ["meta"]. Beachten Sie, dass dieser Teil ein Attribut von Pandas ist, kein Attribut Ihres spezifischen Datenrahmens
bscan

Dieser Ansatz funktioniert nicht mehr, da df.metaeine Warnung ausgelöst wird, dass Pandas auf diese Weise keine neuen Spalten generieren kann.
Anishtain4

@ anishtain4, ich habe es gerade mit Pandas 25.1 getestet (veröffentlicht vor ~ 2 Wochen) und dieser Code funktioniert immer noch für mich. Diese Warnung wird nicht ausgelöst, da df.metaes sich um einen SimpleNamespace handelt. Pandas werden nicht versuchen, eine Spalte daraus zu erstellen.
BSCAN

5

Wie in anderen Antworten und Kommentaren erwähnt, _metadataist es kein Teil der öffentlichen API, daher ist es definitiv keine gute Idee, es in einer Produktionsumgebung zu verwenden. Möglicherweise möchten Sie es dennoch in einem Forschungsprototyp verwenden und ersetzen, wenn es nicht mehr funktioniert. Und im Moment funktioniert es mit groupby/ apply, was hilfreich ist. Dies ist ein Beispiel (das ich in anderen Antworten nicht finden konnte):

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)

Ausgabe:

val
1    my_value
2    my_value
3    my_value
dtype: object

3

Als ich ziemlich spät dazu kam, dachte ich, dass dies hilfreich sein könnte, wenn Sie Metadaten benötigen, um über E / A zu bestehen. Es gibt ein relativ neues Paket namens h5io , mit dem ich dies erreicht habe.

Sie sollten damit ein schnelles Lesen / Schreiben von HDF5 für einige gängige Formate durchführen können, von denen eines ein Datenrahmen ist. So können Sie beispielsweise einen Datenrahmen in ein Wörterbuch einfügen und Metadaten als Felder in das Wörterbuch aufnehmen. Z.B:

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

Eine andere Möglichkeit wäre, ein Projekt wie xray zu untersuchen , das in gewisser Weise komplexer ist, aber ich denke, Sie können damit Metadaten verwenden und es ist ziemlich einfach, es in einen DataFrame zu konvertieren.


3

Wie von @choldgraf erwähnt, hat sich xarray als hervorragendes Werkzeug zum Anhängen von Metadaten beim Vergleichen von Daten und Plotten von Ergebnissen zwischen mehreren Datenrahmen herausgestellt.

In meiner Arbeit vergleichen wir häufig die Ergebnisse mehrerer Firmware-Revisionen und verschiedener Testszenarien. Das Hinzufügen dieser Informationen ist so einfach:

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

Ich habe nach einer Lösung gesucht und festgestellt, dass Pandas Frame die Eigenschaft hat attrs

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

Dieses Attribut bleibt immer bei Ihrem Rahmen, wenn Sie es passieren!


Beachten Sie, dass attrs experimentell ist und sich ohne Vorwarnung ändern kann. Dies ist jedoch eine sehr einfache Lösung. Ich frage mich, ob attrs auf neue Datenrahmen übertragen wird.
Liquidgenius

Leider werden attrs nicht in neue Datenrahmen kopiert :(
Adam

0

Ich hatte das gleiche Problem und verwendete eine Problemumgehung zum Erstellen eines neuen, kleineren DF aus einem Wörterbuch mit den Metadaten:

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

Dieses dfMeta kann dann zusammen mit Ihrem ursprünglichen DF in pickle usw. Gespeichert werden

Siehe Speichern und Laden mehrerer Objekte in einer Pickle-Datei? (Lutz 'Antwort) für eine hervorragende Antwort zum Speichern und Abrufen mehrerer Datenrahmen mit pickle


0

Das Hinzufügen zu @ryanjdillon beantwortet diesen hilfreichen Stackoverflow-Thread und zeigt, wie Parkettdateien benutzerdefinierte Metadaten hinzugefügt werden. Anpassung dieser Antwort an eine Funktion:

from pathlib import Path
from typing import Dict

import pyarrow.parquet as pq

def add_file_engine_metadata_to_parquet_file(filepath: Path, custom_metadata: Dict[str, str]) -> None:
    """Add metadata to existing parquet file.

    Args:
        filepath (Path): Path to parquet file
        custom_metadata (Dict[str, str]): Metadata to be added to file
    """
    table = pq.read_table(filepath)

    existing_metadata = table.schema.metadata
    merged_metadata = {**custom_metadata, **existing_metadata}
    fixed_table = table.replace_schema_metadata(merged_metadata)

    pq.write_table(fixed_table, filepath)

Auf diese Metadaten kann jetzt zugegriffen werden über:

pq.read_metadata(filepath).metadata.decode("utf-8") # decode bytes to string
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.