web-dev-qa-db-fra.com

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

Dans l'exemple de la documentation pandas sur la nouvelle méthode .pipe() pour les objets GroupBy, une méthode .apply() acceptant le même lambda retournerait les mêmes résultats.

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

Je peux voir en quoi la fonctionnalité pipe diffère de apply pour les objets DataFrame, mais pas pour les objets GroupBy. Quelqu'un at-il une explication ou des exemples de ce qui peut être fait avec pipe mais pas avec apply pour un GroupBy?

19
foglerit

Ce que pipe fait est de vous permettre de passer un appelable avec l'espoir que l'objet qui a appelé pipe est l'objet qui est passé à l'appelable.

Avec apply, nous supposons que l'objet qui appelle apply a des sous-composants qui seront chacun transmis à l'appelable qui a été passé à apply. Dans le contexte d'un groupby, les sous-composants sont des tranches de la trame de données qui ont appelé groupby où chaque tranche est une trame de données elle-même. Ceci est analogue à une série groupby.

La principale différence entre ce que vous pouvez faire avec un pipe dans un contexte groupby est que vous avez à la disposition de l'appelable toute la portée de l'objet groupby. Pour postuler, vous ne connaissez que la tranche locale.

Configuration
Considérez df

df = pd.DataFrame(dict(
    A=list('XXXXYYYYYY'),
    B=range(10)
))

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

exemple 1
Réalisez l'ensemble 'B' somme de la colonne à 1 tandis que chaque sous-groupe totalise le même montant. Cela nécessite que le calcul sache combien de groupes existent. C'est quelque chose que nous ne pouvons pas faire avec apply parce que apply ne saurait pas combien de groupes existent.

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

Remarque:

s.sum()

0.99999999999999989

Et:

s.groupby(df.A).sum()

A
X    0.5
Y    0.5
Name: B, dtype: float64

Exemple 2
Soustrayez la moyenne d'un groupe des valeurs d'un autre. Encore une fois, cela ne peut pas être fait avec apply car apply ne connaît pas les autres groupes.

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