Je ne peux pas comprendre la différence entre les fonctions Pandas .aggregate
et .apply
.
Prenons l'exemple suivant: je charge un jeu de données, crée une variable groupby
, définit une fonction simple et l'utilisateur .agg
ou .apply
.
Comme vous pouvez le constater, l'instruction d'impression dans ma fonction produit le même résultat après l'utilisation de .agg
et .apply
. Le résultat, en revanche, est différent. Pourquoi donc?
import pandas
import pandas as pd
iris = pd.read_csv('iris.csv')
by_species = iris.groupby('Species')
def f(x):
...: print type(x)
...: print x.head(3)
...: return 1
Utilisation de apply
:
by_species.apply(f)
#<class 'pandas.core.frame.DataFrame'>
# Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#0 5.1 3.5 1.4 0.2 setosa
#1 4.9 3.0 1.4 0.2 setosa
#2 4.7 3.2 1.3 0.2 setosa
#<class 'pandas.core.frame.DataFrame'>
# Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#0 5.1 3.5 1.4 0.2 setosa
#1 4.9 3.0 1.4 0.2 setosa
#2 4.7 3.2 1.3 0.2 setosa
#<class 'pandas.core.frame.DataFrame'>
# Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#50 7.0 3.2 4.7 1.4 versicolor
#51 6.4 3.2 4.5 1.5 versicolor
#52 6.9 3.1 4.9 1.5 versicolor
#<class 'pandas.core.frame.DataFrame'>
# Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#100 6.3 3.3 6.0 2.5 virginica
#101 5.8 2.7 5.1 1.9 virginica
#102 7.1 3.0 5.9 2.1 virginica
#Out[33]:
#Species
#setosa 1
#versicolor 1
#virginica 1
#dtype: int64
Utiliser agg
by_species.agg(f)
#<class 'pandas.core.frame.DataFrame'>
# Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#0 5.1 3.5 1.4 0.2 setosa
#1 4.9 3.0 1.4 0.2 setosa
#2 4.7 3.2 1.3 0.2 setosa
#<class 'pandas.core.frame.DataFrame'>
# Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#50 7.0 3.2 4.7 1.4 versicolor
#51 6.4 3.2 4.5 1.5 versicolor
#52 6.9 3.1 4.9 1.5 versicolor
#<class 'pandas.core.frame.DataFrame'>
# Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#100 6.3 3.3 6.0 2.5 virginica
#101 5.8 2.7 5.1 1.9 virginica
#102 7.1 3.0 5.9 2.1 virginica
#Out[34]:
# Sepal.Length Sepal.Width Petal.Length Petal.Width
#Species
#setosa 1 1 1 1
#versicolor 1 1 1 1
#virginica 1 1 1 1
apply
applique la fonction à chaque groupe (votre Species
). Votre fonction renvoie 1, vous obtenez donc une valeur pour chacun des 3 groupes.
agg
agrégats chaque colonne (fonctionnalité) pour chaque groupe, vous obtenez donc une valeur par colonne et par groupe.
Lisez les groupby
docs, ils sont très utiles. Il existe également un ensemble de tutoriels flottant sur le Web.
(Remarque: Ces comparaisons sont pertinentes pour les objets DataframeGroupby)
Certains {avantages de l’utilisation de .agg ()} par rapport à .apply (), pour les objets DataFrame GroupBy plausibles seraient:
1) .agg () donne la flexibilité de appliquer plusieurs fonctions à la fois}, ou transmet une liste de fonctions à chaque colonne.
2) De même, appliquant différentes fonctions en même temps à différentes colonnes de dataframe.
Cela signifie que vous avez à peu près le contrôle de chaque colonne avec chaque opération.
Voici le lien pour plus de détails: http://pandas.pydata.org/pandas-docs/version/0.13.1/groupby.html
Toutefois, la fonction d'application peut être limitée à l'application d'une fonction à chaque colonne du cadre de données à la fois. Ainsi, vous devrez peut-être appeler la fonction apply à plusieurs reprises pour appeler différentes opérations sur la même colonne.
Voici quelques exemples de comparaison pour .apply () vs .agg () pour les objets DataframeGroupBy:
Voyons tout d'abord les opérations utilisant .apply ():
In [261]: df = pd.DataFrame({"name":["Foo", "Baar", "Foo", "Baar"], "score_1":[5,10,15,10], "score_2" :[10,15,10,25], "score_3" : [10,20,30,40]})
In [262]: df
Out[262]:
name score_1 score_2 score_3
0 Foo 5 10 10
1 Baar 10 15 20
2 Foo 15 10 30
3 Baar 10 25 40
In [263]: df.groupby(["name", "score_1"])["score_2"].apply(lambda x : x.sum())
Out[263]:
name score_1
Baar 10 40
Foo 5 10
15 10
Name: score_2, dtype: int64
In [264]: df.groupby(["name", "score_1"])["score_2"].apply(lambda x : x.min())
Out[264]:
name score_1
Baar 10 15
Foo 5 10
15 10
Name: score_2, dtype: int64
In [265]: df.groupby(["name", "score_1"])["score_2"].apply(lambda x : x.mean())
Out[265]:
name score_1
Baar 10 20.0
Foo 5 10.0
15 10.0
Name: score_2, dtype: float64
Maintenant, regardez les mêmes opérations utilisant .agg () sans effort:
In [274]: df = pd.DataFrame({"name":["Foo", "Baar", "Foo", "Baar"], "score_1":[5,10,15,10], "score_2" :[10,15,10,25], "score_3" : [10,20,30,40]})
In [275]: df
Out[275]:
name score_1 score_2 score_3
0 Foo 5 10 10
1 Baar 10 15 20
2 Foo 15 10 30
3 Baar 10 25 40
In [276]: df.groupby(["name", "score_1"]).agg({"score_3" :[np.sum, np.min, np.mean, np.max], "score_2":lambda x : x.mean()})
Out[276]:
score_2 score_3
<lambda> sum amin mean amax
name score_1
Baar 10 20 60 20 30 40
Foo 5 10 10 10 10 10
15 10 30 30 30 30
Ainsi, .agg () pourrait être très pratique pour gérer les objets DataFrameGroupBy, par rapport à .apply (). Mais, si vous ne gérez que des objets dataframe purs, et non des objets DataFrameGroupBy, alors apply () peut s'avérer très utile car apply () peut appliquer une fonction le long de n'importe quel axe du dataframe.
(Par exemple: axe = 0 implique une opération de type colonne avec .apply (), qui est un mode par défaut, et un axe = 1 impliquerait pour une opération relative à une ligne tout en traitant des objets de données pures )
Lors de l'utilisation de appliquer à un groupe, j'ai rencontré que .apply renverrait les colonnes groupées. Il y a une note dans la documentation (pandas.pydata.org/pandas-docs/stable/groupby.html):
"... Ainsi, les colonnes groupées peuvent être incluses dans la sortie et définir les index."
.aggregate ne renverra pas les colonnes groupées.