2016-02-15 39 views
16

Chciałbym uruchomić oś na pandach DataFrame, z indeksem będącym dwiema kolumnami, a nie jedną. Na przykład jedno pole na rok, jedno na miesiąc, pole "element", które pokazuje "element 1" i "element 2" oraz pole "wartości" z wartościami liczbowymi. Chcę, żeby indeks był rok + miesiąc.pandy: jak uruchomić oś z multi-indeksem?

Jedynym sposobem, w jaki udało mi się to osiągnąć, było połączenie dwóch pól w jeden, a następnie ponowne ich oddzielenie. czy istnieje lepszy sposób?

Minimalny kod skopiowany poniżej. Wielkie dzięki!

PS Tak, zdaję sobie sprawę, że są inne pytania związane ze słowami kluczowymi "pivot" i "multi-index", ale nie rozumiałem, czy/jak mogą mi pomóc w tym pytaniu.

import pandas as pd 
import numpy as np 

df= pd.DataFrame() 
month = np.arange(1, 13) 
values1 = np.random.randint(0, 100, 12) 
values2 = np.random.randint(200, 300, 12) 


df['month'] = np.hstack((month, month)) 
df['year'] = 2004 
df['value'] = np.hstack((values1, values2)) 
df['item'] = np.hstack((np.repeat('item 1', 12), np.repeat('item 2', 12))) 

# This doesn't work: 
# ValueError: Wrong number of items passed 24, placement implies 2 
# mypiv = df.pivot(['year', 'month'], 'item', 'value') 

# This doesn't work, either: 
# df.set_index(['year', 'month'], inplace=True) 
# ValueError: cannot label index with a null key 
# mypiv = df.pivot(columns='item', values='value') 

# This below works but is not ideal: 
# I have to first concatenate then separate the fields I need 
df['new field'] = df['year'] * 100 + df['month'] 

mypiv = df.pivot('new field', 'item', 'value').reset_index() 
mypiv['year'] = mypiv['new field'].apply(lambda x: int(x)/100) 
mypiv['month'] = mypiv['new field'] % 100 
+3

Podałem kilka szczegółowych przykładów i alternatywnych podejść w tym [** Q & A **] (https://stackoverflow.com/q/47152691/2336654) – piRSquared

Odpowiedz

21

Możesz grupować, a następnie otwierać.

>>> df.groupby(['year', 'month', 'item'])['value'].sum().unstack('item') 
item  item 1 item 2 
year month     
2004 1   33  250 
    2   44  224 
    3   41  268 
    4   29  232 
    5   57  252 
    6   61  255 
    7   28  254 
    8   15  229 
    9   29  258 
    10   49  207 
    11   36  254 
    12   23  209 

lub użyj pivot_table:

>>> df.pivot_table(values='value', index=['year', 'month'], columns='item') 
item  item 1 item 2 
year month     
2004 1   33  250 
    2   44  224 
    3   41  268 
    4   29  232 
    5   57  252 
    6   61  255 
    7   28  254 
    8   15  229 
    9   29  258 
    10   49  207 
    11   36  254 
    12   23  209 
10

wierzę, jeśli zawierają item w MultiIndex, to można tylko rozebranie stosu:

df.set_index(['year', 'month', 'item']).unstack(level=-1) 

Daje:

   value  
item  item 1 item 2 
year month    
2004 1   21 277 
    2   43 244 
    3   12 262 
    4   80 201 
    5   22 287 
    6   52 284 
    7   90 249 
    8   14 229 
    9   52 205 
    10  76 207 
    11  88 259 
    12  90 200 

Jest nieco szybszy niż przy użyciu pivot_table i mniej więcej tej samej prędkości lub nieco wolniej niż przy użyciu groupby.

+0

Możesz także bezpośrednio odwoływać się do poziomu indeksu, np. df.set_index (['year', 'month', 'item']). unstack ('fcode'). Pierwsza metoda Alexandra w jego odpowiedzi również zawiedzie w przypadku danych nie numerycznych (w bardziej uogólnionym problemie niż tutaj). – Carl

+0

to jest niesamowita odpowiedź. –