2016-02-28 25 views
5

Ho un dataframe che mi sottoinsieme in questo modo:panda Esprimere sottoinsieme utilizzando tubi

a b x y 
0 1 2 3 -1 
1 2 4 6 -2 
2 3 6 6 -3 
3 4 8 3 -4 

df = df[(df.a >= 2) & (df.b <= 8)] 
df = df.groupby(df.x).mean() 

Come posso esprimere questo utilizzando l'operatore pipe panda?

df = (df 
     .pipe((x.a > 2) & (x.b < 6) 
     .groupby(df.x) 
     .apply(lambda x: x.mean()) 
+1

Non vedo perché utilizzare 'pipe' sarebbe utile qui. 'df [(df.a> = 2) & (df.b <= 8)]. groupby ('x'). mean()' farà la stessa cosa, no? – jme

+0

che è vero @jme, questo è un esempio di giocattolo e nel mio codice più grande, ho più passaggi. Inoltre l'operatore '.' rende tutto più ordinato. – user308827

+0

Questo è deja vu o [duplicato] (http://stackoverflow.com/questions/35045805) :-) – Primer

risposta

2

Finché è possibile classificare un passo come qualcosa che restituisce un dataframe, e prende una dataframe (possibilmente con più argomenti), quindi è possibile utilizzare pipe. Se c'è un vantaggio nel farlo, è un'altra domanda.

Qui, per esempio, è possibile utilizzare

df\ 
    .pipe(lambda df_, x, y: df_[(df_.a >= x) & (df_.b <= y)], 2, 8)\ 
    .pipe(lambda df_: df_.groupby(df_.x))\ 
    .mean() 

Si noti come la prima fase è un lambda che prende 3 argomenti, con il 2 e l'8 passati come parametri. Questo non è l'unico modo per farlo - è equivalente a

.pipe(lambda df_: df_[(df_.a >= 2) & (df_.b <= 8)])\ 

noti inoltre che è possibile utilizzare

df\ 
    .pipe(lambda df_, x, y: df[(df.a >= x) & (df.b <= y)], 2, 8)\ 
    .groupby('x')\ 
    .mean() 

Qui lambda prende df_, ma opera su df, e la seconda pipe è stata sostituito con uno groupby.

  • Il primo cambio funziona qui, ma è gragile. È che succede a per funzionare poiché questo è il primo stadio pipe. Se sarebbe una fase successiva, potrebbe richiedere un DataFrame con una dimensione e tentare di filtrarlo su una maschera con un'altra dimensione, ad esempio.

  • Il secondo cambiamento va bene. Di fronte, penso che sia più leggibile. In sostanza, tutto ciò che prende un DataFrame e ne restituisce uno, può essere chiamato direttamente o tramite pipe.

+0

grazie a @Ami, si usa 'df_' nel proprio lambda, solo' df' funzionerà anche? – user308827

+0

e inoltre, posso ancora avere .groupby not .pipe (lambda ... .gruppo)? – user308827

+1

Prego. Vedi gli aggiornamenti. –

1

Si può provare, ma penso che è più complicato:

print df[(df.a >= 2) & (df.b <= 8)].groupby(df.x).mean() 
    a b x y 
x     
3 4.0 8 3 -4.0 
6 2.5 5 6 -2.5 


def masker(df, mask): 
    return df[mask] 

mask1 = (df.a >= 2) 
mask2 = (df.b <= 8)  

print df.pipe(masker, mask1).pipe(masker, mask2).groupby(df.x).mean() 
    a b x y 
x     
3 4.0 8 3 -4.0 
6 2.5 5 6 -2.5 
+0

grazie a @jezrael, si dispone di un punto valido per complessità – user308827

1

Credo che questo metodo è chiaro per quanto riguarda i vostri passi di filtraggio e le operazioni successive. L'utilizzo di loc[(mask1) & (mask2)] è probabilmente più performante, tuttavia.

>>> (df 
    .pipe(lambda x: x.loc[x.a >= 2]) 
    .pipe(lambda x: x.loc[x.b <= 8]) 
    .pipe(pd.DataFrame.groupby, 'x') 
    .mean() 
    ) 

    a b y 
x    
3 4.0 8 -4.0 
6 2.5 5 -2.5 

alternativa:

(df 
.pipe(lambda x: x.loc[x.a >= 2]) 
.pipe(lambda x: x.loc[x.b <= 8]) 
.groupby('x') 
.mean() 
) 
+0

grazie ad Alexander, posso ancora avere .groupby not .pipe (pd.DataFrame.groupby, 'x') vale a dire lo stesso modo di usare .groupby come nel mio codice sopra – user308827