2012-11-26 10 views
35

Załóżmy, że mam zagnieżdżonego słownika 'user_dict' o strukturze:Construct pandy DataFrame od pozycji w zagnieżdżonego słownika

Poziom 1: UserId (Long Integer)

Poziom 2: Kategoria (String)

Poziom 3 Różne atrybuty (pływaki, typu int itp ..)

Przykładowo wpis z tego słownika byłoby:

user_dict[12] = { 
    "Category 1": {"att_1": 1, 
        "att_2": "whatever"}, 
    "Category 2": {"att_1": 23, 
        "att_2": "another"}} 

każda pozycja w „user_dict” ma taką samą strukturę i „user_dict” zawiera dużą liczbę elementów, które chcę karmić do DataFrame pandy, konstruując serię przeprowadzoną atrybuty. W tym przypadku przydatny byłby indeks hierarchiczny.

W szczególności moje pytanie brzmi, czy istnieje sposób, aby pomóc konstruktorowi DataFrame zrozumieć, że seria powinna być zbudowana z wartości "poziomu 3" w słowniku?

Gdy próbuję coś takiego:

df = pandas.DataFrame(users_summary) 

pozycje w „poziom 1” (identyfikator użytkownika) są brane jako kolumny, która jest przeciwieństwem tego, co chcę osiągnąć (mają identyfikator użytkownika jako indeks).

Wiem, że mógłbym skonstruować serię po iteracji nad słownikiem, ale jeśli istnieje bardziej bezpośredni sposób, byłoby to bardzo przydatne. Podobnym pytaniem byłoby pytanie, czy możliwe jest skonstruowanie pandas DataFrame z obiektów json wymienionych w pliku.

Odpowiedz

51

Pandas MultiIndex składa się z listy krotek. Więc najbardziej naturalnym podejściem byłoby przekształcenie twojego dyktowania wejściowego tak, aby jego klucze były krotkami odpowiadającymi wymaganym wartościom wielu indeksów. Następnie można po prostu zbudować swój dataframe korzystając pd.DataFrame.from_dict, korzystając z opcji 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 

Alternatywnym rozwiązaniem byłoby zbudować dataframe przez konkatenację dataframes komponent:

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

Czy istnieje rozsądny sposób uogólnienia tego, aby działał na dowolnie rozmieszczonych listach z głębiami? na przykład wyświetla się na dowolną głębokość, gdzie niektóre gałęzie mogą być krótsze od innych, a brak lub nan jest używany, gdy krótsze gałęzie nie osiągają końca? – naught101

+3

Czy patrzyłeś na wsparcie pandy json (narzędzia io) i normalizacji? http://pandas.pydata.org/pandas-docs/dev/io.html#normalization –

+0

Uratuj mi życie !!!!!!!!!! Naucz się dużo !! dziękuję – Wen

10

Więc ja używałem pętla for do iteracji poprzez słownik, ale jedną rzecz, którą odkryłem, że działa znacznie szybciej, jest konwersja do panelu, a następnie do ramki danych. Say masz słownika 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}}} 

Polecenie

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 

gdzie pd.Panel (d) [artykuł] daje dataframe

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 

Można Kliknijmy to_frame polecenia(), aby przekształcić go w ramkę danych. Używam również reset_index, aby zamienić oś główną i pomocniczą na kolumny zamiast mieć je jako indeksy.

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 

Wreszcie, jeśli nie podoba ci się sposób rama wygląda można skorzystać z funkcji transpozycji panelu, aby zmienić wygląd przed wywołaniem to_frame() patrz dokumentacja tutaj http://pandas.pydata.org/pandas-docs/dev/generated/pandas.Panel.transpose.html

Tylko jako przykład

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 

Mam nadzieję, że to pomoże.

+0

Takie eleganckie rozwiązanie! – vk1011

+0

To było łatwiejsze do zrozumienia. Dziękuję Ci. – Moondra