2016-02-15 15 views
16

Vorrei eseguire un pivot su un panda DataFrame, con l'indice due colonne, non uno. Ad esempio, un campo per l'anno, uno per il mese, un campo "item" che mostra "item 1" e "item 2" e un campo "value" con valori numerici. Voglio che l'indice sia di anno + mese.panda: come eseguire un pivot con un multiindice?

L'unico modo in cui sono riuscito a farlo funzionare era combinare i due campi in uno, quindi separarli di nuovo. C'è un modo migliore?

Codice minimo copiato di seguito. Molte grazie!

PS Sì, sono consapevole che ci sono altre domande con le parole chiave 'pivot' e 'multi-index', ma non ho capito se/come possono aiutarmi con questa domanda.

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

Ho fornito diversi esempi dettagliati e approcci alternativi in ​​questo [** D & R **] (https://stackoverflow.com/q/47152691/2336654) – piRSquared

risposta

21

È possibile raggruppare e quindi disimpilare.

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

o utilizzare 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

Credo che se si include item nella vostra MultiIndex, allora si può solo unstack:

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

Questo produce:

   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 

È leggermente più veloce rispetto all'utilizzo di pivot_table e all'incirca alla stessa velocità o leggermente più lento rispetto all'utilizzo di groupby.

+0

È anche possibile fare riferimento direttamente al livello di indice, ad es. df.set_index (['year', 'month', 'item']). unstack ('fcode'). Il primo metodo di Alexander nella sua risposta fallirebbe anche con i dati non numerici (in un problema più generalizzato di quello qui). – Carl

+0

questa è una risposta sorprendente. –