2016-06-09 27 views
5

Sono curioso del comportamento dei panda groupby-apply quando la funzione apply restituisce una serie.pandas groupby-applica il comportamento, restituendo una serie (tipo di output incoerente)

Quando le serie sono di lunghezza diversa, restituisce una serie con più indici.

In [1]: import pandas as pd 

In [2]: df1=pd.DataFrame({'state':list("AABBB"), 
    ...:     'city':list("vwxyz")}) 

In [3]: df1 
Out[3]: 
    city state 
0 v  A 
1 w  A 
2 x  B 
3 y  B 
4 z  B 

In [4]: def f(x): 
    ...:   return pd.Series(x['city'].values,index=range(len(x))) 
    ...: 

In [5]: df1.groupby('state').apply(f) 
Out[5]: 
state 
A  0 v 
     1 w 
B  0 x 
     1 y 
     2 z 
dtype: object 

Restituisce un oggetto Series.

Tuttavia, se ogni serie ha la stessa lunghezza, viene ruotata su DataFrame.

In [6]: df2=pd.DataFrame({'state':list("AAABBB"), 
    ...:     'city':list("uvwxyz")}) 

In [7]: df2 
Out[7]: 
    city state 
0 u  A 
1 v  A 
2 w  A 
3 x  B 
4 y  B 
5 z  B 

In [8]: df2.groupby('state').apply(f) 
Out[8]: 
     0 1 2 
state 
A  u v w 
B  x y z 

È davvero questo il comportamento previsto? Abbiamo intenzione di verificare il tipo di reso se usiamo applicare in questo modo? O c'è un'opzione in apply che non sto apprezzando?

Nel caso in cui sei curioso, nel mio caso di utilizzo effettivo, la serie restituita avrà la stessa lunghezza della lunghezza del gruppo. Sembra un caso ideale per transform tranne per il fatto che ho trovato che apply con la restituzione di una serie è in realtà un ordine di grandezza più veloce su un set di dati di grandi dimensioni. Questo può essere un altro argomento.

Edit: Liberamente ispirato risposta del Parfait, si può certamente fare questo:

X=df.groupby('state').apply(f) 
if not isinstance(X,pd.Series): 
    X=X.stack() 
X 

Che darà lo stesso tipo di uscita sia per df=df1 o df=df2. Suppongo che sto solo chiedendo se questo è davvero il modo normale o preferito per gestire questo.

risposta

3

In sostanza, un dataframe è costituito da serie di lunghezza uguale (tecnicamente un contenitore di dizionari di oggetti serie). Come indicato nelle panadas split-apply-combine documenti, l'esecuzione di un groupby () si riferisce a uno o più dei seguenti

  • dividendo i dati in gruppi in base alcuni criteri
  • applicando una funzione ad ogni gruppo indipendente
  • Combinando i risultati in una struttura dati

Avviso di cui sopra non ha precisato annuncio ata frame viene sempre prodotto ma una struttura dati generalizzata. Pertanto, un'operazione di groupby() può essere scaricata in una serie o se iniziare come una serie può essere trasferita a un dataframe.

Per il primo dataframe, si eseguono raggruppamenti non uguali (o lunghezze dell'indice non uguali) che costringono un ritorno di serie che nell'elaborazione "Combina" non produce adeguatamente un frame di dati. Poiché un frame di dati non può combinare diverse serie di lunghezze, esso produce invece una serie di più indici. Potete vederlo con le istruzioni di stampa nella funzione definita con un raggruppamento di lunghezza 2 e un raggruppamento B di lunghezza 3.

def f(x): 
    print(x) 
    return pd.Series(x['city'].values, index=range(len(x))) 

s1 = df1.groupby('state').apply(f) 

print(s1) 
# city state 
# 0 v  A 
# 1 w  A 
# city state 
# 0 v  A 
# 1 w  A 
# city state 
# 2 x  B 
# 3 y  B 
# 4 z  B 
# state 
# A  0 v 
#  1 w 
# B  0 x 
#  1 y 
#  2 z 
# dtype: object 

Tuttavia, è possibile manipolare il risultato della serie multi-index resettando indice e quindi regolando i suoi livelli gerarchici:

df = df1.groupby('state').apply(f).reset_index() 
print(df) 

# state level_1 0 
# 0  A  0 v 
# 1  A  1 w 
# 2  B  0 x 
# 3  B  1 y 
# 4  B  2 z 

Ma più rilevante per le vostre esigenze è unstack() che ruota un livello dell'indice etichette, producendo un frame di dati. Considerare fillna() per completare il risultato None.

df = df1.groupby('state').apply(f).unstack() 
print(df) 

#  0 1  2 
# state    
# A  v w None 
# B  x y  z 
+0

Capisco _quando questo accade, ma sembra ancora strano. Se non sto lavorando in modo interattivo, sembra che devo controllare il tipo di dati del risultato per procedere. Chiamare '.reset_index()' o '.unstack()' avrà comunque risultati completamente diversi a seconda che iniziassi con i dati 'df1' o' df2'. –

+0

Un buon punto sull'utilizzo di 'stack' e' unstack' è il modo migliore per forzare tra i due tipi di output, grazie. Ho modificato la domanda per includerla. –

+0

Come detto 'groupby(). Apply()' non garantisce il ritorno di un frame di dati in quanto dipende dagli input e dalle operazioni e quindi può generare strutture diverse. Considerare una funzione/classe definita dall'utente per gestire i vari output. – Parfait

Problemi correlati