Accéder au contenu principal

Pandas .apply() : Son fonctionnement, quand il est utile et alternatives plus rapides

Découvrez ce qu'est Python pandas .apply et comment l'utiliser pour les DataFrame. Découvrez dès aujourd'hui comment itérer sur des DataFrames à l'aide de la fonction .apply() !
Actualisé 7 oct. 2025  · 5 min de lecture

De nombreuses personnes se tournent vers .apply() pour « éviter les boucles » et s'attendent à ce que ce soit rapide et simple. En pratique, l'.apply(axis=1) e ligne par ligne reste une boucle au niveau Python. Il peut être lent avec des données volumineuses et renvoie parfois des formes inattendues. La solution est simple : utilisez les opérations vectorisées pandas/NumPy pour les tâches courantes et réservez l' .apply() e pour la logique qui nécessite réellement plusieurs colonnes.

Ce guide explique comment .apply() fonctionne aujourd'hui, met en évidence les pièges courants et fournit des modèles prêts à l'emploi plus rapides et plus clairs.

Qu'est-ce que DataFrame.apply() et Series.apply() ?

DataFrame.apply(func, axis=0) appelle par défautfunc sur chaque colonne. Avec` axis=1`, il appelle ` func ` sur chaque ligne. `Series.apply(func) ` appelle `func ` sur chaque élément (ou sur l'ensemble ` Series`, selon les signatures dans les versions récentes).

  • Par ligne ou par colonne : axis=1 signifie « par ligne ». axis=0 (par défaut) signifie « par colonne ».
  • Règles de forme de retour (pandas ≥0,23) : Si votre fonction renvoie un scalaire par ligne/colonne, vous obtenez une erreur de type « Series ». Si elle renvoie un Series ou un dict, pandas développe ces clés en un DataFrame. Si la fonction renvoie une liste/un tableau, vous obtiendrez une série de listes, à moins que vous ne définissiez result_type='expand'.
  • Erreurs plus strictes (pandas ≥2.0) : Les longueurs de listes incompatibles génèrent désormais des erreurs au lieu de produire silencieusement des résultats incohérents.

Premier choix recommandé : Opérations vectorisées

La plupart des tâches impliquant la combinaison ou la transformation de colonnes sont plus rapides et plus claires avec des expressions vectorisées ou des méthodes intégrées. L'exemple suivant calcule la différence de points d'une équipe de baseball sans utiliser d' .apply().

import pandas as pd

team_stats = pd.DataFrame({
    "Team": ["ARI", "ATL", "BAL"],
    "League": ["NL", "NL", "AL"],
    "Year": [2012, 2012, 2012],
    "RunsScored": [734, 700, 712],
    "RunsAllowed": [688, 600, 705],
    "Wins": [81, 94, 93],
    "Games": [162, 162, 162],
    "Playoffs": [0, 1, 1],
})

# Vectorized: fast and idiomatic
team_stats["RunDiff"] = team_stats["RunsScored"] - team_stats["RunsAllowed"]
print(team_stats[["Team", "RunsScored", "RunsAllowed", "RunDiff"]])

Utilisation de .apply() ligne par ligne lorsque cela est nécessaire

Utilisez cette méthode lorsque votre logique s'étend réellement sur plusieurs .apply(axis=1) lorsque votre logique s'étend réellement sur plusieurs colonnes et n'est pas facilement vectorisable (par exemple, des règles conditionnelles qui dépendent de plusieurs champs).

calculer une valeur dérivée à partir de plusieurs colonnes

Ce modèle calcule une valeur par ligne à l'aide de plusieurs entrées. L'approche vectorisée ci-dessus reste préférable, mais celle-ci montre l'utilisation correcte ligne par ligne et les options qui affectent la vitesse et la sortie.

def compute_run_diff(row):
    # Treat the row as read-only; return a scalar
    return row["RunsScored"] - row["RunsAllowed"]

# Row-wise apply (Python-level loop; can be slow on large data)
team_stats["RunDiff_apply"] = team_stats.apply(compute_run_diff, axis=1)

Lorsque la fonction est numérique et ne nécessite que des tableaux bruts, le fait de passer raw=True permet d'éviter une partie de la surcharge de pandas en fournissant un tableau NumPy à votre fonction.

import numpy as np

def compute_run_diff_raw(values):
    # values is a NumPy array when raw=True
    # Order matches the column order we select
    rs, ra = values
    return rs - ra

team_stats["RunDiff_raw"] = team_stats[["RunsScored", "RunsAllowed"]].apply(
    compute_run_diff_raw, axis=1, raw=True
)

Veuillez vérifier une fois la saisie de la fonction.

Lorsque je connecte une nouvelle fonction de ligne, j'imprime une ligne une fois pour vérifier ce qui est transmis.

def debug_row(row):
    # Print the first row only
    if row.name == team_stats.index[0]:
        print("Example row:", row.to_dict())
    return 0

_ = team_stats.apply(debug_row, axis=1)

Étude de cas : Sommes, totaux saisonniers et indicateurs textuels

Compte tenu des statistiques annuelles de Rays, privilégiez les méthodes intégrées et les outils élémentaires lorsque cela est possible. .apply() dans la mesure du possible.

rays_by_year = pd.DataFrame(
    {
        "Year": [2012, 2011, 2010, 2009, 2008],
        "RunsScored": [697, 707, 802, 803, 774],
        "RunsAllowed": [577, 614, 649, 754, 671],
        "Wins": [90, 91, 96, 84, 97],
        "Playoffs": [0, 1, 1, 0, 1],
    }
).set_index("Year")

obtenir efficacement les sommes des colonnes

Veuillez utiliser DataFrame.sum() au lieu de .apply(sum). C'est plus rapide et plus clair.

# Preferred
totals = rays_by_year.sum(axis=0)
print(totals)

# If you must use apply (not recommended here)
totals_apply = rays_by_year.apply(sum, axis=0)

calculer le nombre total de points marqués au cours d'une saison

Utilisez l'arithmétique vectorisée sur les colonnes ; aucune .apply() nécessaire.

rays_by_year["TotalRuns"] = rays_by_year["RunsScored"] + rays_by_year["RunsAllowed"]
print(rays_by_year[["RunsScored", "RunsAllowed", "TotalRuns"]].head())

convertir un indicateur 0/1 en texte

Veuillez privilégier Series.map() ou replace() pour les transformations élémentaires sur une colonne.

# Using map with a dict
rays_by_year["PlayoffsText"] = rays_by_year["Playoffs"].map({0: "No", 1: "Yes"})

# Equivalent with replace
rays_by_year["PlayoffsText2"] = rays_by_year["Playoffs"].replace({0: "No", 1: "Yes"})

Contrôler la forme de sortie à partir de .apply()

Lorsque votre fonction renvoie plusieurs valeurs par ligne, veuillez indiquer explicitement la forme. Cela permet d'éviter les surprises et les problèmes de compatibilité avec les versions futures.

renvoyer une liste et la développer en colonnes

Utilisez result_type='expand' pour diviser une liste/un tableau en plusieurs colonnes.

def wins_losses(row):
    # Derive wins and losses as two outputs
    wins = row["Wins"]
    losses = row["Games"] - row["Wins"] if "Games" in row else np.nan
    return [wins, losses]

# Example using team_stats, which has "Wins" and "Games"
expanded = team_stats.apply(wins_losses, axis=1, result_type="expand")
expanded.columns = ["WinsOut", "LossesOut"]
team_stats = pd.concat([team_stats, expanded], axis=1)

Renvoyer une série ou un dictionnaire pour nommer automatiquement les colonnes

Retourner un Series ou dict de chaque ligne produit un DataFrame avec des étiquettes de colonnes correspondantes.

def summary_row(row):
    return pd.Series(
        {
            "IsWinningSeason": row["Wins"] >= 90,
            "RunRatio": (row["RunsScored"] / row["RunsAllowed"]),
        }
    )

summary = team_stats.apply(summary_row, axis=1)
team_stats = pd.concat([team_stats, summary], axis=1)

Conseils de performance pertinents

Le traitement ligne par ligne est pratique, mais peut être lent sur les grands cadres, car .apply(axis=1) est pratique mais peut être lent sur les grands cadres car il appelle votre fonction Python une fois par ligne. Ces modèles permettent d'éviter ce goulot d'étranglement.

  • Veuillez privilégier les opérations vectorisées pandas/NumPy et les méthodes intégrées telles que sum, mean, clip, where, astype, et les méthodes de chaîne/accesseur.
  • Pour les opérations numériques sur les lignes/colonnes qui acceptent les tableaux, veuillez transmettre raw=True pour obtenir un tableau NumPy et réduire la surcharge pandas.
  • Pour effectuer des opérations élémentaires sur une seule colonne, veuillez utiliser les méthodes Series.map() ou des méthodes vectorisées à la place de DataFrame.apply(axis=1).
  • Veuillez éviter de modifier la ligne/colonne fournie dans votre fonction ; veuillez plutôt renvoyer une nouvelle valeur.

Notes importantes concernant la version (pandas 2.x)

Les versions récentes de pandas ont renforcé le comportement autour de .apply() afin que les résultats soient plus prévisibles.

  • Rétournements de type liste : Dans la version 2.0 et les versions ultérieures, les longueurs de liste incompatibles génèrent une erreur. Veuillez utiliser des longueurs cohérentes et définir l' result_type='expand' lorsque vous souhaitez plusieurs colonnes.
  • Augmentation de la production : Le renvoi d'un objet Series ou dict se développe en un DataFrame avec ces clés comme colonnes (stable depuis la version 0.23).
  • Series.apply() Modifications : L'argument d'convert_dtype est obsolète. Si vous avez besoin de types mixtes, effectuez d'abord une conversion vers object (par exemple, s.astype("object").apply(fn)). Les nouvelles signatures permettent de contrôler si fn reçoit des scalaires ou une série dans davantage de contextes (par exemple, by_row).

.apply() par rapport à .map() par rapport à .applymap() par rapport à .agg()

Veuillez sélectionner l'API qui correspond à la forme de votre transformation.

  • Series.map(func_or_dict): Transformation élémentaire sur une colonne. Idéal pour les recherches ou les fonctions simples.
  • DataFrame.apply(func, axis=1): Logique par ligne nécessitant plusieurs colonnes.
  • DataFrame.apply(func, axis=0): Logique par colonne (chaque entrée est une série représentant une colonne).
  • DataFrame.applymap(func): Élément par élément sur chaque cellule. Veuillez l'utiliser avec modération ; les méthodes vectorisées sont plus rapides.
  • .agg()/.transform(): Agrégations et transformations par groupe ; privilégiez ces dernières dans les pipelines groupby.

Erreurs courantes et solutions rapides

Ce sont les problèmes qui entraînent le plus souvent des résultats incorrects ou des ralentissements, avec les moyens de les corriger.

  • Oublier axis=1 pour la logique par ligne : Si votre fonction reçoit soudainement des colonnes au lieu de lignes, veuillez ajouter axis=1.
  • Série inattendue de listes : Lorsque vous renvoyez une liste/un tableau à partir de chaque ligne, définissez result_type='expand' pour diviser en colonnes.
  • Code lent ligne par ligne : Veuillez remplacer par des expressions vectorisées ou des fonctions intégrées ; si cela n'est pas possible, envisagez l'utilisation de l' raw=True e afin de réduire la charge.
  • Modification de la ligne d'entrée : Traitez les entrées comme étant en lecture seule et renvoyez de nouvelles valeurs.
  • Déviation du type de données : Si votre fonction renvoie parfois des valeurs non entières, les colonnes entières peuvent être converties en flottantes ou en objets. Veuillez ensuite couler si nécessaire. astype si nécessaire.

Conclusion

.apply() est un outil flexible, mais ce n'est pas un raccourci vers la performance. Utilisez des opérations vectorisées pour les transformations arithmétiques, d'agrégation et élémentaires sur une seule colonne. N'utilisez l'DataFrame.apply(axis=1) que lorsque votre logique nécessite réellement plusieurs colonnes par ligne. Lorsque vous l'utilisez, contrôlez la forme de la sortie avec result_type, envisagez raw=True pour les fonctions numériques et surveillez dtypes. Ces modèles produisent des résultats prévisibles sur les pandas modernes et s'adaptent mieux à mesure que vos données augmentent.

Sujets

En savoir plus sur Python et pandas

Cours

Python intermédiaire

4 h
1.3M
Mettez à niveau vos compétences en science des données en créant des visualisations à l'aide de Matplotlib et en manipulant des DataFrame avec pandas.
Afficher les détailsRight Arrow
Commencer le cours
Voir plusRight Arrow
Apparenté

Didacticiel

Tutoriel sur les boucles « for » en Python

Apprenez à implémenter des boucles « for » en Python pour itérer une séquence ou les lignes et colonnes d'un DataFrame pandas.
Aditya Sharma's photo

Aditya Sharma

Didacticiel

Fonctions lambda Python : Guide pour débutants

Découvrez les fonctions lambda Python, leur utilité et quand les utiliser. Comprend des exemples pratiques et des bonnes pratiques pour une mise en œuvre efficace.
Mark Pedigo's photo

Mark Pedigo

Didacticiel

Tutoriel sur les méthodes .append() et .extend() de Python

Apprenez à utiliser les méthodes .append() et .extend() pour ajouter des éléments à une liste.
DataCamp Team's photo

DataCamp Team

Didacticiel

Méthode index() de Python expliquée à l'aide d'exemples

Découvrez comment utiliser la fonction index() de Python pour trouver la position d'éléments dans des listes.
Sejal Jaiswal's photo

Sejal Jaiswal

Didacticiel

Tutoriel et exemples sur les fonctions et méthodes des listes Python

Découvrez les fonctions et méthodes des listes Python. Veuillez suivre les exemples de code pour list() et d'autres fonctions et méthodes Python dès maintenant.
Abid Ali Awan's photo

Abid Ali Awan

Didacticiel

Séquence de Fibonacci en Python : Apprenez et explorez les techniques de codage

Veuillez découvrir le fonctionnement de la suite de Fibonacci. Veuillez explorer ses propriétés mathématiques et ses applications concrètes.
Laiba Siddiqui's photo

Laiba Siddiqui

Voir plusVoir plus