2012-11-26 8 views
35

Angenommen, ich habe eine verschachtelte Wörterbuch 'user_dict' mit Struktur:Baukonstruktion Pandas Datenrahmen von Artikel im verschachtelten Wörterbuch

Stufe 1: UserId (Long Integer)

Stufe 2: Kategorie (String)

Stufe 3: Verschiedene Attribute (Schwimmer, ints, etc ..)

Zum Beispiel, ein Eintrag des Wörterbuchs wäre:

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 die gleiche Struktur und „user_dict“ enthält eine große Anzahl von Gegenständen, die ich zu einem Pandas Datenrahmen füttern wollen, den Aufbau der Serie von der Attribute. In diesem Fall wäre ein hierarchischer Index für diesen Zweck nützlich.

Speziell meine Frage ist, ob es eine Möglichkeit gibt, dem DataFrame-Konstruktor zu verstehen, dass die Serie aus den Werten der "Ebene 3" im Wörterbuch erstellt werden sollte?

Wenn ich versuche, so etwas wie:

df = pandas.DataFrame(users_summary) 

Gegenstände in „Ebene 1“ (die Benutzer-ID) als Spalt genommen, das ist das Gegenteil von dem, was ich erreichen will (User-ID als Index).

Ich weiß, ich könnte die Serie nach dem Iterieren über die Wörterbucheinträge erstellen, 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 json-Objekten zu erstellen, die in einer Datei aufgelistet sind.

Antwort

51

Ein Pandas MultiIndex besteht aus einer Liste von Tupeln. Der natürlichste Ansatz wäre also, das Eingabediktat so umzuformen, dass es sich bei den Schlüsseln um Tupel handelt, die den von Ihnen benötigten Multiindexwerten entsprechen. Dann können Sie einfach Ihren Datenrahmen konstruieren pd.DataFrame.from_dict verwenden, mit der Option orient='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, um Ihren Datenrahmen aufzubauen, indem die Komponente Datenrahmen verketten:

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 
+1

Gibt es eine vernünftige Möglichkeit, dies zu verallgemeinern, um mit willkürlichen Tiefen-Listen zu arbeiten? z.B. listet in einer beliebigen Tiefe auf, in der einige Zweige kürzer als andere sein können, und eine None oder Nan wird verwendet, wenn kürzere Zweige nicht das Ende erreichen? – naught101

+3

Haben Sie Pandas JSON Unterstützung (io Tools) und Normalisierung angeschaut? http://pandas.pydata.org/pandas-docs/dev/io.html#normalization –

+0

Rette mein Leben !!!!!!!!!! Lerne viel !! Danke – Wen

10

So habe ich zu verwenden, eine for-Schleife für das Iterieren durch das Wörterbuch, aber eine Sache, die ich gefunden habe, die viel schneller arbeitet, ist, zu einem Panel und dann zu einem Datenrahmen zu konvertieren. Sagen Sie bitte ein Wörterbuch d

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 schlagen Sie den Befehl to_frame haben

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 

wo pd.Panel (d) [Artikel] ergibt sich ein Datenrahmen() um es in einen Datenrahmen zu verwandeln. Ich verwende auch reset_index, um die Haupt- und Nebenachse in Spalten zu verwandeln, 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 

Schließlich, wenn Sie den Weg nicht wie der Rahmen sieht man die Transponierung Funktion Panel verwenden können, um das Erscheinungsbild zu ändern, bevor to_frame() aufrufen, siehe Dokumentation hier 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.

+0

Solch eine elegante Lösung! – vk1011

+0

Das war leichter zu verstehen. Vielen Dank. – Moondra

Verwandte Themen