2014-06-23 12 views
10

Często używam pandy groupby do generowania ułożonych tabel. Ale często chcę wyprowadzać wynikowe zagnieżdżone relacje do json. Czy istnieje sposób na wyodrębnienie zagnieżdżonego pliku json z ułożonego w stos stołu, który generuje?panda groupby do nested json

Powiedzmy mam df jak:

year office candidate amount 
2010 mayor joe smith 100.00 
2010 mayor jay gould 12.00 
2010 govnr pati mara 500.00 
2010 govnr jess rapp 50.00 
2010 govnr jess rapp 30.00 

mogę zrobić:

grouped = df.groupby('year', 'office', 'candidate').sum() 

print grouped 
         amount 
year office candidate 
2010 mayor joe smith 100 
      jay gould 12 
    govnr pati mara 500 
      jess rapp 80 

Beautiful! Oczywiście, naprawdę chciałbym zagnieździć json za pomocą komendy wzdłuż linii grouped.to_json. Ale ta funkcja nie jest dostępna. Jakiekolwiek obejścia?

Więc, co naprawdę chcę coś jak:

{"2010": {"mayor": [ 
        {"joe smith": 100}, 
        {"jay gould": 12} 
        ] 
     }, 
      {"govnr": [ 
        {"pati mara":500}, 
        {"jess rapp": 80} 
        ] 
      } 
} 

Don

+2

Powyższy kod w rzeczywistości nie działa tak, jak kolumna kwoty (np. "30 USD") to ciągi znaków, dlatego są dodawane jako ciągi, a nie jako liczby. Ponadto, nie jest jasne, czego chcesz pod względem wydajności json, dlaczego to działa dla ciebie to_json? –

+0

@AndyHayden Good points. Edytowałem, aby naprawić/wyjaśnić. – Don

+0

@Don czy istnieje jakieś rozwiązanie? – skycrew

Odpowiedz

7

Nie sądzę, że istnieje coś wbudowany w pand tworzyć zagnieżdżone słownika danych. Poniżej znajduje się kod, który powinien ogólnie działać w przypadku serii z MultiIndex, przy użyciu kodu zagnieżdżającego iterującego przez każdy poziom MultIndex, dodając warstwy do słownika, dopóki najgłębsza warstwa nie zostanie przypisana do wartości Serial. Page 10

In [99]: from collections import defaultdict 

In [100]: results = defaultdict(lambda: defaultdict(dict)) 

In [101]: for index, value in grouped.itertuples(): 
    ...:  for i, key in enumerate(index): 
    ...:   if i == 0: 
    ...:    nested = results[key] 
    ...:   elif i == len(index) - 1: 
    ...:    nested[key] = value 
    ...:   else: 
    ...:    nested = nested[key] 

In [102]: results 
Out[102]: defaultdict(<function <lambda> at 0x7ff17c76d1b8>, {2010: defaultdict(<type 'dict'>, {'govnr': {'pati mara': 500.0, 'jess rapp': 80.0}, 'mayor': {'joe smith': 100.0, 'jay gould': 12.0}})}) 

In [106]: print json.dumps(results, indent=4) 
{ 
    "2010": { 
     "govnr": { 
      "pati mara": 500.0, 
      "jess rapp": 80.0 
     }, 
     "mayor": { 
      "joe smith": 100.0, 
      "jay gould": 12.0 
     } 
    } 
} 
+0

nice - thanks! – Don

+1

@chrisb Próbuję dostosować twoją odpowiedź do podobnego problemu tutaj, ale potknąłem się przez grouped.intertuples(): http://stackoverflow.com/questions/37819622/valueerror-too-many-wartości-to- rozpakuj-kiedy-za pomocą-itertuples-na-pandas-datafram/37819973 # 37819973 – spaine

0

Jestem świadomy, że to stare pytanie, ale ostatnio spotkałem się z tym samym problemem. Oto moje rozwiązanie. Pożyczyłem wiele rzeczy z przykładu chrisb (dziękuję!).

Ma to tę zaletę, że można przekazać wartość lambda, aby uzyskać ostateczną wartość z dowolnego przelicznika, który chcesz, a także dla każdej grupy.

from collections import defaultdict 

def dict_from_enumerable(enumerable, final_value, *groups): 
    d = defaultdict(lambda: defaultdict(dict)) 
    group_count = len(groups) 
    for item in enumerable: 
     nested = d 
     item_result = final_value(item) if callable(final_value) else item.get(final_value) 
     for i, group in enumerate(groups, start=1): 
      group_val = str(group(item) if callable(group) else item.get(group)) 
      if i == group_count: 
       nested[group_val] = item_result 
      else: 
       nested = nested[group_val] 
    return d 

W pytaniu, można by nazwać tę funkcję jak:

dict_from_enumerable(grouped.itertuples(), 'amount', 'year', 'office', 'candidate') 

Pierwszym argumentem może być tablicą danych, jak również, nie wymagając nawet pandy.