pandas: GroupBy .pipe () vs .apply ()

En el ejemplo de la documentación de pandas sobre el nuevo método .pipe() para objetos GroupBy, un método .apply() que acepte la misma lambda devolverá los mismos resultados.

 In [195]: import numpy as np In [196]: n = 1000 In [197]: df = pd.DataFrame({'Store': np.random.choice(['Store_1', 'Store_2'], n), .....: 'Product': np.random.choice(['Product_1', 'Product_2', 'Product_3'], n), .....: 'Revenue': (np.random.random(n)*50+10).round(2), .....: 'Quantity': np.random.randint(1, 10, size=n)}) In [199]: (df.groupby(['Store', 'Product']) .....: .pipe(lambda grp: grp.Revenue.sum()/grp.Quantity.sum()) .....: .unstack().round(2)) Out[199]: Product Product_1 Product_2 Product_3 Store Store_1 6.93 6.82 7.15 Store_2 6.69 6.64 6.77 

Puedo ver cómo la funcionalidad de la pipe difiere de la apply para objetos DataFrame, pero no para objetos GroupBy. ¿Alguien tiene una explicación o ejemplos de lo que se puede hacer con pipe pero no con apply un GroupBy?

Lo pipe hace la pipe es permitirle pasar una llamada con la expectativa de que el objeto que se llama pipe es el objeto que se pasa a la llamada.

Con apply , asumimos que el objeto que se apply llamadas tiene subcomponentes que se pasarán al llamable que se pasó para apply . En el contexto de un groupby los subcomponentes son segmentos del dataframe que se llama groupby que cada segmento es un dataframe. Esto es análogo para una serie groupby .

La principal diferencia entre lo que puede hacer con una pipe en un contexto groupby es que tiene disponible para llamar el scope completo del objeto groupby . Para aplicar, solo conoces la rebanada local.

Preparar
Considere df

 df = pd.DataFrame(dict( A=list('XXXXYYYYYY'), B=range(10) )) AB 0 X 0 1 X 1 2 X 2 3 X 3 4 Y 4 5 Y 5 6 Y 6 7 Y 7 8 Y 8 9 Y 9 

Ejemplo 1
Haga que la sum de la columna 'B' 1 mientras que cada subgrupo sum la misma cantidad. Esto requiere que el cálculo tenga en cuenta cuántos grupos existen. Esto es algo que no podemos hacer con apply porque apply no sabría cuántos grupos existen.

 s = df.groupby('A').B.pipe(lambda g: df.B / g.transform('sum') / g.ngroups) s 0 0.000000 1 0.083333 2 0.166667 3 0.250000 4 0.051282 5 0.064103 6 0.076923 7 0.089744 8 0.102564 9 0.115385 Name: B, dtype: float64 

Nota:

 s.sum() 0.99999999999999989 

Y:

 s.groupby(df.A).sum() A X 0.5 Y 0.5 Name: B, dtype: float64 

Ejemplo 2
Resta la media de un grupo de los valores de otro. Nuevamente, esto no se puede hacer con apply porque apply no conoce otros grupos.

 df.groupby('A').B.pipe( lambda g: ( g.get_group('X') - g.get_group('Y').mean() ).append( g.get_group('Y') - g.get_group('X').mean() ) ) 0 -6.5 1 -5.5 2 -4.5 3 -3.5 4 2.5 5 3.5 6 4.5 7 5.5 8 6.5 9 7.5 Name: B, dtype: float64