Angenommen, ich habe ein verschachteltes Wörterbuch 'user_dict' mit folgender Struktur:
- Stufe 1: UserId (Long Integer)
- Stufe 2: Kategorie (String)
- Stufe 3: Verschiedene Attribute (Floats, Ints usw.)
Ein Eintrag in diesem Wörterbuch wäre beispielsweise:
user_dict[12] = {
"Category 1": {"att_1": 1,
"att_2": "whatever"},
"Category 2": {"att_1": 23,
"att_2": "another"}}
Jedes Element in user_dict
hat dieselbe Struktur und user_dict
enthält eine große Anzahl von Elementen, die ich einem Pandas DataFrame zuführen möchte, um die Serie aus den Attributen zu erstellen. In diesem Fall wäre ein hierarchischer Index für diesen Zweck nützlich.
Insbesondere ist meine Frage, ob es eine Möglichkeit gibt, dem DataFrame-Konstruktor zu helfen, zu verstehen, dass die Reihe aus den Werten der "Ebene 3" im Wörterbuch erstellt werden sollte.
Wenn ich etwas versuche wie:
df = pandas.DataFrame(users_summary)
Die Elemente in "Ebene 1" (die Benutzer-IDs) werden als Spalten verwendet, was das Gegenteil von dem ist, was ich erreichen möchte (Benutzer-IDs als Index haben).
Ich weiß, dass ich die Serie nach dem Durchlaufen der Wörterbucheinträge erstellen könnte, aber wenn es einen direkteren Weg gibt, wäre dies sehr nützlich. Eine ähnliche Frage wäre die Frage, ob es möglich ist, einen Pandas-DataFrame aus in einer Datei aufgelisteten JSON-Objekten zu erstellen.
quelle
Antworten:
Ein Pandas MultiIndex besteht aus einer Liste von Tupeln. Der natürlichste Ansatz wäre also, Ihr Eingabediktat so umzuformen, dass seine Schlüssel Tupel sind, die den von Ihnen benötigten Multi-Index-Werten entsprechen. Dann können Sie Ihren Datenrahmen einfach
pd.DataFrame.from_dict
mit der folgenden Option erstellenorient='index'
:user_dict = {12: {'Category 1': {'att_1': 1, 'att_2': 'whatever'}, 'Category 2': {'att_1': 23, 'att_2': 'another'}}, 15: {'Category 1': {'att_1': 10, 'att_2': 'foo'}, 'Category 2': {'att_1': 30, 'att_2': 'bar'}}} pd.DataFrame.from_dict({(i,j): user_dict[i][j] for i in user_dict.keys() for j in user_dict[i].keys()}, orient='index') att_1 att_2 12 Category 1 1 whatever Category 2 23 another 15 Category 1 10 foo Category 2 30 bar
Ein alternativer Ansatz wäre, Ihren Datenrahmen durch Verketten der Komponentendatenrahmen aufzubauen:
user_ids = [] frames = [] for user_id, d in user_dict.iteritems(): user_ids.append(user_id) frames.append(pd.DataFrame.from_dict(d, orient='index')) pd.concat(frames, keys=user_ids) att_1 att_2 12 Category 1 1 whatever Category 2 23 another 15 Category 1 10 foo Category 2 30 bar
quelle
pd.concat
akzeptiert ein Wörterbuch. Vor diesem Hintergrund ist es möglich, die derzeit akzeptierte Antwort in Bezug auf Einfachheit und Leistung zu verbessern, indem ein Wörterbuchverständnis verwendet wird , um Wörterbuchzuordnungsschlüssel für Unterrahmen zu erstellen.pd.concat({k: pd.DataFrame(v).T for k, v in user_dict.items()}, axis=0)
Oder,
pd.concat({ k: pd.DataFrame.from_dict(v, 'index') for k, v in user_dict.items() }, axis=0)
att_1 att_2 12 Category 1 1 whatever Category 2 23 another 15 Category 1 10 foo Category 2 30 bar
quelle
12:{cat1:{cat11:{att1:val1,att2:val2}}}
. Mit anderen Worten: Wie würde jemand die Lösung auf eine irrelevante Anzahl von Kategorien verallgemeinern?json_normalize
. Ich habe eine andere Antwort, die zeigt, wie es funktioniert.v
es sich beispielsweise um eine einzelne Ganzzahl handelt. Kennen Sie in einem solchen Fall eine Alternative?Früher habe ich auch eine for-Schleife zum Durchlaufen des Wörterbuchs verwendet, aber eine Sache, die viel schneller funktioniert, ist die Konvertierung in ein Panel und dann in einen Datenrahmen. Angenommen, Sie haben ein Wörterbuch d
import pandas as pd d {'RAY Index': {datetime.date(2014, 11, 3): {'PX_LAST': 1199.46, 'PX_OPEN': 1200.14}, datetime.date(2014, 11, 4): {'PX_LAST': 1195.323, 'PX_OPEN': 1197.69}, datetime.date(2014, 11, 5): {'PX_LAST': 1200.936, 'PX_OPEN': 1195.32}, datetime.date(2014, 11, 6): {'PX_LAST': 1206.061, 'PX_OPEN': 1200.62}}, 'SPX Index': {datetime.date(2014, 11, 3): {'PX_LAST': 2017.81, 'PX_OPEN': 2018.21}, datetime.date(2014, 11, 4): {'PX_LAST': 2012.1, 'PX_OPEN': 2015.81}, datetime.date(2014, 11, 5): {'PX_LAST': 2023.57, 'PX_OPEN': 2015.29}, datetime.date(2014, 11, 6): {'PX_LAST': 2031.21, 'PX_OPEN': 2023.33}}}
Der Befehl
pd.Panel(d) <class 'pandas.core.panel.Panel'> Dimensions: 2 (items) x 2 (major_axis) x 4 (minor_axis) Items axis: RAY Index to SPX Index Major_axis axis: PX_LAST to PX_OPEN Minor_axis axis: 2014-11-03 to 2014-11-06
Dabei ergibt pd.Panel (d) [item] einen Datenrahmen
pd.Panel(d)['SPX Index'] 2014-11-03 2014-11-04 2014-11-05 2014-11-06 PX_LAST 2017.81 2012.10 2023.57 2031.21 PX_OPEN 2018.21 2015.81 2015.29 2023.33
Sie können dann den Befehl to_frame () drücken, um daraus einen Datenrahmen zu machen. Ich benutze auch reset_index, um die Haupt- und Nebenachse in Spalten umzuwandeln, anstatt sie als Indizes zu haben.
pd.Panel(d).to_frame().reset_index() major minor RAY Index SPX Index PX_LAST 2014-11-03 1199.460 2017.81 PX_LAST 2014-11-04 1195.323 2012.10 PX_LAST 2014-11-05 1200.936 2023.57 PX_LAST 2014-11-06 1206.061 2031.21 PX_OPEN 2014-11-03 1200.140 2018.21 PX_OPEN 2014-11-04 1197.690 2015.81 PX_OPEN 2014-11-05 1195.320 2015.29 PX_OPEN 2014-11-06 1200.620 2023.33
Wenn Ihnen das Aussehen des Rahmens nicht gefällt, können Sie die Transponierungsfunktion des Bedienfelds verwenden, um das Erscheinungsbild vor dem Aufruf von to_frame () zu ändern. Weitere Informationen finden Sie in der Dokumentation unter http://pandas.pydata.org/pandas-docs/dev/generated /pandas.Panel.transpose.html
Nur als Beispiel
pd.Panel(d).transpose(2,0,1).to_frame().reset_index() major minor 2014-11-03 2014-11-04 2014-11-05 2014-11-06 RAY Index PX_LAST 1199.46 1195.323 1200.936 1206.061 RAY Index PX_OPEN 1200.14 1197.690 1195.320 1200.620 SPX Index PX_LAST 2017.81 2012.100 2023.570 2031.210 SPX Index PX_OPEN 2018.21 2015.810 2015.290 2023.330
Hoffe das hilft.
quelle
Wenn jemand den Datenrahmen in einem "langen Format" (Blattwerte haben denselben Typ) ohne Multiindex erhalten möchte, können Sie dies tun:
pd.DataFrame.from_records( [ (level1, level2, level3, leaf) for level1, level2_dict in user_dict.items() for level2, level3_dict in level2_dict.items() for level3, leaf in level3_dict.items() ], columns=['UserId', 'Category', 'Attribute', 'value'] ) UserId Category Attribute value 0 12 Category 1 att_1 1 1 12 Category 1 att_2 whatever 2 12 Category 2 att_1 23 3 12 Category 2 att_2 another 4 15 Category 1 att_1 10 5 15 Category 1 att_2 foo 6 15 Category 2 att_1 30 7 15 Category 2 att_2 bar
(Ich weiß, dass die ursprüngliche Frage wahrscheinlich möchte, dass (I.) Level 1 und 2 als Multiindex und Level 3 als Spalten haben und (II.) Nach anderen Möglichkeiten als der Iteration über Werte im Diktat fragt. Aber ich hoffe, diese Antwort ist immer noch relevant und nützlich (I.): für Leute wie mich, die versucht haben, einen Weg zu finden, um das verschachtelte Diktat in diese Form zu bringen, und Google gibt nur diese Frage zurück und (II.): weil andere Antworten auch eine Iteration beinhalten und ich dies finde Ansatz flexibel und leicht zu lesen, jedoch nicht sicher über die Leistung.)
quelle
Aufbauend auf einer verifizierten Antwort hat dies für mich am besten funktioniert:
ab = pd.concat({k: pd.DataFrame(v).T for k, v in data.items()}, axis=0) ab.T
quelle