Les documents montrent comment appliquer plusieurs fonctions sur un objet groupby à la fois en utilisant un dict avec les noms des colonnes de sortie comme clés:
In [563]: grouped['D'].agg({'result1' : np.sum,
.....: 'result2' : np.mean})
.....:
Out[563]:
result2 result1
A
bar -0.579846 -1.739537
foo -0.280588 -1.402938
Cependant, cela ne fonctionne que sur un objet Groupby Series. Et lorsqu'un dict est également transmis à un groupe par DataFrame, il s'attend à ce que les clés soient les noms de colonne auxquels la fonction sera appliquée.
Ce que je veux faire, c'est appliquer plusieurs fonctions à plusieurs colonnes (mais certaines colonnes seront exploitées plusieurs fois). De plus, certaines fonctions dépendent d'autres colonnes de l'objet groupby (comme les fonctions sumif). Ma solution actuelle consiste à aller colonne par colonne et à faire quelque chose comme le code ci-dessus, en utilisant lambdas pour les fonctions qui dépendent d'autres lignes. Mais cela prend beaucoup de temps (je pense qu'il faut beaucoup de temps pour parcourir un objet groupby). Je vais devoir le changer pour que je répète tout l'objet groupby en une seule fois, mais je me demande s'il y a un moyen intégré dans les pandas pour le faire quelque peu proprement.
Par exemple, j'ai essayé quelque chose comme
grouped.agg({'C_sum' : lambda x: x['C'].sum(),
'C_std': lambda x: x['C'].std(),
'D_sum' : lambda x: x['D'].sum()},
'D_sumifC3': lambda x: x['D'][x['C'] == 3].sum(), ...)
mais comme prévu, j'obtiens une KeyError (puisque les clés doivent être une colonne si elle agg
est appelée à partir d'un DataFrame).
Y a-t-il une manière intégrée de faire ce que j'aimerais faire, ou une possibilité que cette fonctionnalité soit ajoutée, ou devrais-je simplement parcourir le groupe manuellement?
Merci
Réponses:
La seconde moitié de la réponse actuellement acceptée est dépassée et comporte deux dépréciations. D'abord et surtout, vous ne pouvez plus transmettre un dictionnaire de dictionnaires à la
agg
méthode groupby. Deuxièmement, n'utilisez jamais.ix
.Si vous souhaitez travailler avec deux colonnes distinctes en même temps, je suggère d'utiliser la
apply
méthode qui transmet implicitement un DataFrame à la fonction appliquée. Utilisons une trame de données similaire à celle d'en hautUn dictionnaire mappé des noms de colonne aux fonctions d'agrégation est toujours un excellent moyen d'effectuer une agrégation.
Si vous n'aimez pas ce nom de colonne lambda laid, vous pouvez utiliser une fonction normale et fournir un nom personnalisé à l'
__name__
attribut spécial comme ceci:Utilisation
apply
et retour d'une sérieMaintenant, si vous aviez plusieurs colonnes qui devaient interagir ensemble, vous ne pouvez pas utiliser
agg
, ce qui transmet implicitement une série à la fonction d'agrégation. Lors de l'utilisation deapply
l'ensemble du groupe en tant que DataFrame est passé dans la fonction.Je recommande de créer une seule fonction personnalisée qui renvoie une série de toutes les agrégations. Utilisez l'index des séries comme étiquettes pour les nouvelles colonnes:
Si vous êtes amoureux de MultiIndexes, vous pouvez toujours retourner une série avec une comme celle-ci:
la source
a
intérieur du groupe,0
ne devrait-ce pas être le cas0.418500 + 0.446069 = 0.864569
? Il en va de même pour les autres cellules, les chiffres ne semblent pas s'additionner. Serait-ce un cadre de données sous-jacent légèrement différent qui a été utilisé dans les exemples suivants?Pour la première partie, vous pouvez passer un dict de noms de colonnes pour les clés et une liste de fonctions pour les valeurs:
MISE À JOUR 1:
Étant donné que la fonction d'agrégation fonctionne sur Series, les références aux autres noms de colonne sont perdues. Pour contourner ce problème, vous pouvez référencer la trame de données complète et l'indexer à l'aide des indices de groupe dans la fonction lambda.
Voici une solution de contournement hacky:
Ici, la colonne «D» résultante est constituée des valeurs «E» sommées.
MISE À JOUR 2:
Voici une méthode qui, je pense, fera tout ce que vous demandez. Créez d'abord une fonction lambda personnalisée. Ci-dessous, g fait référence au groupe. Lors de l'agrégation, g sera une série. Passer
g.index
àdf.ix[]
sélectionne le groupe actuel dans df. Je teste ensuite si la colonne C est inférieure à 0,5. La série booléenne retournée est transmise àg[]
laquelle ne sélectionne que les lignes répondant aux critères.la source
{funcname: func}
valeurs as au lieu de listes pour conserver mes noms personnalisés. Mais dans les deux cas, je ne peux pas passer unlambda
qui utilise d'autres colonnes (commelambda x: x['D'][x['C'] < 3].sum()
ci-dessus: "KeyError: 'D'"). Une idée si c'est possible?KeyError: 'D'
df['A'].ix[g.index][df['C'] < 0].sum()
. Cela commence à devenir assez compliqué, cependant - je pense que pour la lisibilité, le bouclage manuel peut être préférable, et je ne suis pas sûr qu'il existe un moyen de lui donner mon nom préféré dans l'agg
argument (au lieu de<lambda>
). J'espère que quelqu'un saura d'une manière plus simple ...{'D': {'my name':lambda function}}
et cela fera de la clé de dict interne le nom de la colonne.Comme alternative (principalement sur l'esthétique) à la réponse de Ted Petrou, j'ai trouvé que je préférais une liste légèrement plus compacte. S'il vous plaît ne pensez pas à l'accepter, c'est juste un commentaire beaucoup plus détaillé sur la réponse de Ted, plus le code / les données. Python / pandas n'est pas mon premier / meilleur, mais j'ai trouvé cela bien lu:
Je le trouve plus proche des
dplyr
pipes etdata.table
des commandes chaînées. Pour ne pas dire qu'ils sont meilleurs, juste plus familiers pour moi. (Je reconnais certainement le pouvoir et, pour beaucoup, la préférence d'utiliser des fonctions plus formellesdef
pour ces types d'opérations. C'est juste une alternative, pas nécessairement meilleure.)J'ai généré des données de la même manière que Ted, je vais ajouter une graine pour la reproductibilité.
la source
Pandas >= 0.25.0
, agrégations nomméesDepuis la version pandas
0.25.0
ou supérieure, nous nous éloignons de l'agrégation et du renommage basés sur le dictionnaire, et nous nous dirigeons vers des agrégations nommées qui acceptent atuple
. Maintenant, nous pouvons simultanément agréger + renommer en un nom de colonne plus informatif:Exemple :
Appliquer
GroupBy.agg
avec l'agrégation nommée:la source
Nouveau dans la version 0.25.0.
Pour prendre en charge l'agrégation spécifique aux colonnes avec un contrôle sur les noms des colonnes de sortie, pandas accepte la syntaxe spéciale dans GroupBy.agg () , appelée «agrégation nommée» , où
pandas.NamedAgg est juste un tuple nommé. Les tuples simples sont également autorisés.
Les arguments de mots clés supplémentaires ne sont pas transmis aux fonctions d'agrégation. Seules les paires de (colonne, aggfunc) doivent être passées en tant que ** kwargs. Si vos fonctions d'agrégation nécessitent des arguments supplémentaires, appliquez-les partiellement avec functools.partial ().
L'agrégation nommée est également valide pour les agrégations Groupby de séries. Dans ce cas, il n'y a pas de sélection de colonne, donc les valeurs ne sont que les fonctions.
la source
La réponse de Ted est incroyable. J'ai fini par en utiliser une version plus petite au cas où quelqu'un serait intéressé. Utile lorsque vous recherchez une agrégation qui dépend des valeurs de plusieurs colonnes:
créer une trame de données
regroupement et agrégation avec Apply (en utilisant plusieurs colonnes)
regroupement et agrégation avec agrégat (en utilisant plusieurs colonnes)
J'aime cette approche car je peux toujours utiliser des agrégats. Peut-être que les gens me diront pourquoi appliquer est nécessaire pour accéder à plusieurs colonnes lors de l'agrégation de groupes.
Cela semble évident maintenant, mais tant que vous ne sélectionnez pas la colonne d'intérêt directement après le groupby , vous aurez accès à toutes les colonnes de la trame de données depuis votre fonction d'agrégation.
accéder uniquement à la colonne sélectionnée
l'accès à toutes les colonnes puisque la sélection est après tout la magie
ou similaire
J'espère que ça aide.
la source