Skip to content

Pandas GroupBy : Aggregation, Transform, Apply (Guide 2025)

Updated on

Le modèle split-apply-combine est le point fort de Pandas. Problème : difficile de choisir entre agg, transform ou apply, et on se heurte vite au tri implicite, aux groupes manquants ou aux effets de SettingWithCopy.

Cadre PAS :

  • Problème : Les calculs groupés semblent opaques et lents quand on ne veut que des totaux ou des ratios par ligne.
  • Agiter : Un apply excessif ou l’oubli de as_index=False produit des formes inattendues, des colonnes dupliquées et du code lent.
  • Solution : Quelques recettes suffisent—agg pour les résumés, transform pour les features par ligne, apply seulement si nécessaire—avec des options de tri et de gestion des groupes manquants.

Référence rapide : quand utiliser chaque méthode

MéthodeForme renvoyéeIdéal pourExemple
agg / aggregateUne ligne par groupeRésumés et multi-métriquesdf.groupby("team").agg(avg_score=("score","mean"))
transformMême longueurFeatures par ligne dépendant du groupedf["z"] = df.groupby("team")["score"].transform("zscore")
applyFlexibleReshapes complexes quand agg/transform ne suffisent pasdf.groupby("team").apply(custom_fn)

Données d’exemple

import pandas as pd
 
data = {
    "team": ["A", "A", "B", "B", "B", "C"],
    "player": ["x1", "x2", "y1", "y2", "y3", "z1"],
    "score": [9, 7, 8, 6, 10, 3],
    "minutes": [30, 25, 28, 32, 20, 15],
}
df = pd.DataFrame(data)

Modèles d’agrégation (agg)

summary = (
    df.groupby("team", as_index=False)
      .agg(
          avg_score=("score", "mean"),
          max_score=("score", "max"),
          minutes_played=("minutes", "sum"),
      )
)
  • Utilisez la named aggregation pour garder des noms propres.
  • as_index=False conserve team en colonne (utile pour merges/plots).
  • sort=False garde l’ordre d’entrée si nécessaire.

Multi-agrégation sur une colonne

df.groupby("team", as_index=False).agg(
    score_mean=("score", "mean"),
    score_std=("score", "std"),
    score_count=("score", "size"),
)

Features diffusées (transform)

transform garde la forme originale et ajoute les métriques de groupe à chaque ligne.

df["score_pct_of_team"] = (
    df["score"] / df.groupby("team")["score"].transform("sum")
)

Z-score par équipe :

df["score_z"] = (
    df.groupby("team")["score"]
      .transform(lambda s: (s - s.mean()) / s.std(ddof=0))
)

Utilisez transform pour :

  • Ratios par rapport aux totaux de groupe
  • Scores normalisés
  • Flags de groupe (ex. rank, cumcount)

Quand apply vaut le coup

apply est flexible mais plus lent ; réservez-le quand agg/transform ne suffisent pas.

def top_n(group, n=2):
    return group.nlargest(n, "score")
 
top_players = df.groupby("team").apply(top_n, n=1).reset_index(drop=True)

Préférez agg/transform; utilisez apply si :

  • vous devez renvoyer un nombre variable de lignes par groupe ;
  • la logique nécessite du Python non vectorisé.

Groupes manquants et tri

result = (
    df.groupby("team", dropna=False, sort=False)
      .agg(avg_score=("score", "mean"))
)
  • dropna=False conserve les étiquettes NaN.
  • sort=False évite le réordonnancement—utile si l’ordre a du sens.

GroupBy avec plusieurs clés et index

multi = (
    df.groupby(["team", "player"], as_index=False)
      .agg(score_mean=("score", "mean"))
)

Groupement par niveaux d’index :

df2 = df.set_index(["team", "player"])
df2.groupby(level="team")["score"].mean()

Pièges fréquents

ProblèmeCorrection
Formes inattendues (Series vs DataFrame)Mettez as_index=False ou ensuite reset_index().
Noms de colonnes dupliqués après mergeUtilisez la named aggregation pour définir les noms.
Lenteur due à applyRemplacez par agg/transform ou des méthodes vectorisées.
Catégories manquantes en sortieLaissez observed=False (défaut) ou assurez les catégories ; dropna=False pour NaN.

Conseils export et visualisation

  • Après agrégation, triez pour présenter : summary.sort_values("avg_score", ascending=False).
  • Pour des graphiques, pivotez le résumé : summary.pivot(index="team", values="avg_score").

Guides liés


À retenir

  • agg pour les résumés, transform pour les features par ligne, apply avec parcimonie.
  • Contrôlez la forme avec as_index et reset_index.
  • Gérez l’ordre et les labels manquants avec sort et dropna.
  • Priorisez les méthodes vectorisées pour garder des pipelines rapides.