2013-06-21 17 views
13

Ho un DataFrame multiindice creato tramite un'operazione di gruppo. Sto cercando di fare un ordinamento composto utilizzando diversi livelli dell'indice, ma non riesco a trovare una funzione di ordinamento che faccia ciò di cui ho bisogno.Ordinamento multiindice in panda

set di dati iniziale simile a questa (quotidiane conteggi di vendita dei vari prodotti):

  Date Manufacturer Product Name Product Launch Date Sales 
0 2013-01-01  Apple   iPod   2001-10-23  12 
1 2013-01-01  Apple   iPad   2010-04-03  13 
2 2013-01-01  Samsung  Galaxy   2009-04-27  14 
3 2013-01-01  Samsung Galaxy Tab   2010-09-02  15 
4 2013-01-02  Apple   iPod   2001-10-23  22 
5 2013-01-02  Apple   iPad   2010-04-03  17 
6 2013-01-02  Samsung  Galaxy   2009-04-27  10 
7 2013-01-02  Samsung Galaxy Tab   2010-09-02  7 

Io uso groupby per ottenere una somma sopra l'intervallo di date:

> grouped = df.groupby(['Manufacturer', 'Product Name', 'Product Launch Date']).sum() 
               Sales 
Manufacturer Product Name Product Launch Date  
Apple  iPad   2010-04-03    30 
      iPod   2001-10-23    34 
Samsung  Galaxy  2009-04-27    24 
      Galaxy Tab 2010-09-02    22 

Fin qui tutto bene!

Ora l'ultima cosa che voglio fare è una sorta di prodotti di ogni costruttore in base alla data di lancio, ma tenerli raggruppati gerarchicamente sotto produttore - qui è tutto quello che sto cercando di fare:

           Sales 
Manufacturer Product Name Product Launch Date  
Apple  iPod   2001-10-23    34 
      iPad   2010-04-03    30 
Samsung  Galaxy  2009-04-27    24 
      Galaxy Tab 2010-09-02    22 

Quando provo sortlevel() perdo la bella gerarchia per-azienda che avevo prima:

> grouped.sortlevel('Product Launch Date') 
               Sales 
Manufacturer Product Name Product Launch Date  
Apple  iPod   2001-10-23    34 
Samsung  Galaxy  2009-04-27    24 
Apple  iPad   2010-04-03    30 
Samsung  Galaxy Tab 2010-09-02    22 

sort() e sort_index() appena venga meno

grouped.sort(['Manufacturer','Product Launch Date']) 
KeyError: u'no item named Manufacturer' 

grouped.sort_index(by=['Manufacturer','Product Launch Date']) 
KeyError: u'no item named Manufacturer' 

Sembra un'operazione semplice, ma non riesco a capirlo.

Non sono legato all'utilizzo di un MultiIndex per questo, ma poiché questo è ciò che restituisce groupby(), è quello con cui ho lavorato.

BTW il codice per produrre il dataframe iniziale è:

data = { 
    'Date': ['2013-01-01', '2013-01-01', '2013-01-01', '2013-01-01', '2013-01-02', '2013-01-02', '2013-01-02', '2013-01-02'], 
    'Manufacturer' : ['Apple', 'Apple', 'Samsung', 'Samsung', 'Apple', 'Apple', 'Samsung', 'Samsung',], 
    'Product Name' : ['iPod', 'iPad', 'Galaxy', 'Galaxy Tab', 'iPod', 'iPad', 'Galaxy', 'Galaxy Tab'], 
    'Product Launch Date' : ['2001-10-23', '2010-04-03', '2009-04-27', '2010-09-02','2001-10-23', '2010-04-03', '2009-04-27', '2010-09-02'], 
    'Sales' : [12, 13, 14, 15, 22, 17, 10, 7] 
} 
df = DataFrame(data, columns=['Date', 'Manufacturer', 'Product Name', 'Product Launch Date', 'Sales']) 
+1

"I dati saranno ordinati lessicograficamente per il livello scelto * seguito dagli altri livelli (in ordine) *" (che fa schifo ...) –

risposta

8

Un hack potrebbe essere quella di cambiare l'ordine dei livelli:

In [11]: g 
Out[11]: 
               Sales 
Manufacturer Product Name Product Launch Date 
Apple  iPad   2010-04-03    30 
      iPod   2001-10-23    34 
Samsung  Galaxy  2009-04-27    24 
      Galaxy Tab 2010-09-02    22 

In [12]: g.index = g.index.swaplevel(1, 2) 

Sortlevel, che (come hai trovato) ordina i livelli MultiIndex in ordine:

In [13]: g = g.sortlevel() 

E scambiare indietro:

In [14]: g.index = g.index.swaplevel(1, 2) 

In [15]: g 
Out[15]: 
               Sales 
Manufacturer Product Name Product Launch Date 
Apple  iPod   2001-10-23    34 
      iPad   2010-04-03    30 
Samsung  Galaxy  2009-04-27    24 
      Galaxy Tab 2010-09-02    22 

Sono dell'opinione che sortlevel non debba ordinare le etichette rimanenti in ordine, quindi creerà un problema github. :) Anche se vale la pena menzionare il documento su "the need for sortedness".

Nota: si potrebbe evitare la prima swaplevel riordinando l'ordine del groupby iniziale:

g = df.groupby(['Manufacturer', 'Product Launch Date', 'Product Name']).sum() 
+1

[Questa nota doc] (http://pandas.pydata.org/pandas-docs/dev/indexing.html#the-need-for-sortedness) suggerisce che i livelli debbano essere ordinati, anche se apparentemente questo è solo un dettaglio di implementazione. Non è chiaro se questo significa che devono essere ordinati gerarchicamente dal livello di indice più alto a quello più basso. – BrenBarn

+0

@BrenBarn È un buon punto, ho sentito Jeff parlarne prima ... :) –

+0

Per inciso, non è possibile eliminare lo scambio/smistamento aggiuntivo nella soluzione facendo il gruppo iniziale nell'ordine scambiato (quindi solo swaplevel dopo il gruppo)? – BrenBarn

0

Se si vuole cercare di evitare più scambi all'interno di una molto profonda MultiIndex, si potrebbe anche provare con questo:

  1. Affettare per livello X (dalla comprensione di lista +.loc + IndexSlice)
  2. Ordina il livello desiderato (sortlevel (2))
  3. Concatenate ogni gruppo di indici X livello

Qui si ha il codice:

import pandas as pd 
idx = pd.IndexSlice 
g = pd.concat([grouped.loc[idx[i,:,:],:].sortlevel(2) for i in grouped.index.levels[0]]) 
g 
0

Se non siete preoccupato di conservare l'indice (spesso preferisco un indice intero arbitrario) puoi semplicemente usare il seguente one-liner:

grouped.reset_index().sort(["Manufacturer","Product Launch Date"]) 
3

Questo rivestimento funziona per me:

In [1]: groupd.sortlevel(["Manufacturer","Product Launch Date"], sort_remaining=False) 

               Sales 
Manufacturer Product Name Product Launch Date  
Apple  iPod   2001-10-23    34 
      iPad   2010-04-03    30 
Samsung  Galaxy  2009-04-27    24 
      Galaxy Tab 2010-09-02    22 

Nota questo funziona anche:

groups.sortlevel([0,2], sort_remaining=False) 

Questo non avrebbe funzionato quando si originariamente pubblicato più di due anni fa, a causa sortlevel di default allineati su TUTTE indici che ha fatto impazzire la gerarchia della tua azienda. sort_remaining che disabilita tale comportamento è stato aggiunto l'anno scorso. Ecco il link di commit per riferimento: https://github.com/pydata/pandas/commit/3ad64b11e8e4bef47e3767f1d31cc26e39593277

+1

Grazie per aver postato una risposta aggiornata. Avevo un multiindice a tre livelli e volevo solo ordinare i primi due. Questo ha funzionato perfettamente. –

Problemi correlati