Pandas apply - Maîtrisez l'outil, évitez les pièges

Étienne Lambert .

26 février 2026

Interface de programmation pour l'analyse de données avec pandas. Chargement, manipulation et visualisation de données.

La méthode pandas apply devient utile dès qu’une transformation ne rentre plus proprement dans une opération vectorisée. Elle permet d’exécuter une fonction personnalisée sur chaque ligne ou chaque colonne d’un DataFrame, ce qui est très pratique quand la logique métier dépend de plusieurs champs à la fois. Je vais montrer comment la paramétrer correctement, comment lire ce que reçoit la fonction, quand renvoyer une seule valeur ou plusieurs, et surtout dans quels cas je préfère une autre approche.

Les points essentiels à garder en tête

  • `apply` sert surtout pour une logique personnalisée sur des lignes ou des colonnes, pas pour du calcul simple.
  • `axis=0` travaille colonne par colonne, tandis que `axis=1` travaille ligne par ligne.
  • `raw=True` transmet un tableau NumPy au lieu d’une `Series`, ce qui peut accélérer certaines fonctions numériques.
  • Si une fonction renvoie plusieurs valeurs, il faut penser à la forme du résultat et, au besoin, à `result_type="expand"`.
  • Pour une transformation élément par élément, `map` ou une expression vectorisée est souvent plus lisible et plus rapide.
  • Sur de gros volumes, `apply` devient vite le mauvais réflexe si une alternative native existe.

Quand `apply` est le bon outil

Je réserve `apply` aux cas où une seule expression vectorisée ne suffit pas. Concrètement, cela couvre les règles métier qui combinent plusieurs colonnes, les conditions imbriquées, les calculs qui changent selon le contexte, ou les transformations dont la logique serait pénible à écrire en une seule ligne.

  • catégoriser une ligne selon plusieurs champs
  • extraire ou reformater une valeur à partir de plusieurs colonnes
  • produire un score, un libellé, ou plusieurs indicateurs à partir d’une règle maison

En revanche, si je peux écrire la même chose avec une opération sur colonnes, je le fais presque toujours. La suite logique, c’est donc de comprendre précisément ce que Pandas envoie à la fonction selon l’axe choisi.

Explication de la fonction `apply()` de Pandas DataFrame pour appliquer des fonctions. Installation via `$ pip install pandas`.

Comprendre ce que la fonction reçoit selon l’axe

Le point qui piège le plus souvent, c’est l’axe. Avec `axis=0`, Pandas applique la fonction à chaque colonne ; avec `axis=1`, il passe ligne par ligne. Dans les deux cas, l’objet reçu est en général une `Series`, sauf si l’on active `raw=True`, auquel cas on reçoit un tableau NumPy plus brut.

Paramètre Ce que cela change Quand je l’utilise
`axis=0` La fonction reçoit chaque colonne Réductions, statistiques, nettoyage colonne par colonne
`axis=1` La fonction reçoit chaque ligne Règles métier qui combinent plusieurs champs
`raw=True` La fonction reçoit un `ndarray` au lieu d’une `Series` Calculs numériques simples où les labels ne servent pas
`result_type="expand"` Les retours de type liste deviennent des colonnes Sorties multiples avec `axis=1`
`result_type="broadcast"` Le résultat garde la forme d’origine Quand chaque ligne doit produire une structure de même taille
`by_row="compat"` Pandas essaie de traduire certaines fonctions vers ses méthodes natives Quand on passe une liste ou un dictionnaire de fonctions

Une fois ce cadrage clair, l’écriture des fonctions devient beaucoup plus simple, y compris quand on veut produire une colonne entière à partir d’une règle plus riche.

Appliquer une logique aux lignes sans se tromper

Quand je traite les lignes, je nomme systématiquement le paramètre `row` pour ne pas me tromper sur le sens de lecture. C’est surtout utile quand la règle dépend de deux ou trois colonnes, par exemple pour calculer un prix net, attribuer un segment client ou valider un statut.

import pandas as pd

df = pd.DataFrame({
    "produit": ["A", "B", "C"],
    "prix_ht": [120, 80, 200],
    "remise_pct": [10, 0, 15],
})

def prix_net(row):
    remise = row["prix_ht"] * row["remise_pct"] / 100
    return row["prix_ht"] - remise

df["prix_net"] = df.apply(prix_net, axis=1)

Ici, `apply` est pertinent parce que le calcul combine plusieurs colonnes et une petite règle métier. Si je devais faire exactement la même chose sur un million de lignes avec une formule simple, je chercherais d’abord une version vectorisée.

Retourner plusieurs valeurs sans bricoler

Une autre force de cette méthode, c’est qu’elle peut renvoyer plus qu’un simple scalaire. Si la fonction produit plusieurs indicateurs, je peux retourner une `Series` et laisser Pandas créer plusieurs colonnes d’un coup, ce qui garde le code lisible et évite des passages répétés sur le même DataFrame.

df = pd.DataFrame({
    "produit": ["A", "B", "C"],
    "prix_ht": [120, 80, 200],
    "remise_pct": [10, 0, 15],
    "cout": [70, 55, 140],
})

def indicateurs(row):
    ca_net = row["prix_ht"] * (1 - row["remise_pct"] / 100)
    marge = ca_net - row["cout"]
    return pd.Series({
        "ca_net": ca_net,
        "marge": marge,
    })

df[["ca_net", "marge"]] = df.apply(indicateurs, axis=1)

Quand la fonction renvoie une liste ou un tuple, `result_type="expand"` devient utile si l’on veut transformer ces valeurs en colonnes. En pratique, j’utilise cette option quand la sortie a une forme stable et que je veux éviter du post-traitement manuel.

Ce que j’utilise à la place quand c’est plus simple

Dans beaucoup de cas, `apply` n’est pas l’outil le plus direct. Je compare rapidement l’intention de départ avec le bon niveau d’abstraction, et je choisis la méthode la plus lisible avant même de penser à la performance.

Situation Méthode à privilégier Pourquoi
Une opération mathématique ou logique sur une colonne entière Expression vectorisée / NumPy Plus lisible, plus rapide, souvent une seule ligne
Une transformation cellule par cellule sur une `Series` `Series.map` Plus explicite qu’un `apply` si l’entrée et la sortie sont scalaires
Une transformation cellule par cellule sur tout le DataFrame `DataFrame.map` La méthode élément par élément remplace l’ancien usage de `applymap`
Une agrégation `agg` Conçu pour réduire les données, pas pour parcourir ligne par ligne
Une transformation qui doit garder la même forme `transform` Utile quand chaque valeur doit être remplacée sans changer la structure
Une logique métier qui dépend de plusieurs colonnes `apply(axis=1)` Flexible, mais à réserver aux cas où les alternatives sont moins claires

Je garde aussi en tête que `DataFrame.applymap` n’est plus le bon nom à retenir : la méthode élément par élément s’appelle maintenant `DataFrame.map`. Ce détail compte, parce qu’il évite des habitudes héritées d’anciennes versions et force à choisir l’outil qui correspond vraiment à la tâche.

Les erreurs qui coûtent le plus de temps

La plupart des problèmes que je vois autour de `apply` ne viennent pas de la syntaxe, mais d’un mauvais cadrage du besoin. Les erreurs suivantes reviennent souvent, et elles peuvent faire perdre beaucoup de temps sur un pipeline pourtant simple.

  • Oublier `axis=1` quand on veut traiter des lignes, puis se retrouver avec une logique appliquée colonne par colonne.
  • Muter l’objet reçu dans la fonction : Pandas ne garantit pas un comportement fiable si la fonction modifie la `Series` passée en argument.
  • Retourner des types incohérents selon les lignes, ce qui conduit à des colonnes en `object` difficiles à exploiter ensuite.
  • Utiliser `apply` pour une formule triviale alors qu’une expression vectorisée ferait le travail plus vite et plus clairement.
  • Passer `raw=True` sans adapter la fonction : si la fonction attend des noms de colonnes, elle cassera, car elle reçoit alors un tableau brut.
  • Appeler une API ou une base de données ligne par ligne : dans ce cas, le problème n’est plus Pandas mais l’architecture du traitement.

La documentation officielle de Pandas montre un exemple parlant : sur une petite comparaison, une version vectorisée prend 0,0043 seconde contre 5,6435 secondes pour une UDF avec `apply`. Le chiffre n’est pas universel, mais le message est constant : dès qu’une opération peut être poussée dans NumPy, elle gagne presque toujours. Pour certaines fonctions numériques stables, `engine="numba"` peut aider, mais seulement si le code reste compatible et les types ne changent pas en cours de route.

Une fois ces pièges écartés, la méthode redevient un outil utile plutôt qu’un réflexe par défaut.

Le réflexe que j’applique avant de garder `apply`

Avant de valider une transformation, je me pose trois questions simples : est-ce que je peux écrire la même logique en vectorisé, est-ce qu’une version `map`, `agg` ou `transform` ferait le travail, et ai-je vraiment besoin d’une fonction personnalisée ligne par ligne ? Si la réponse à la première question est oui, je n’hésite pas longtemps.

Quand la réponse est non, `apply` reste un bon outil pour clarifier une règle métier ou construire plusieurs colonnes à partir d’une même logique. Je l’utilise alors avec une fonction courte, un axe explicite, et une vérification rapide sur un petit échantillon avant de l’envoyer sur de gros volumes.

Questions fréquentes

Utilisez `apply` pour une logique métier complexe impliquant plusieurs colonnes ou des conditions imbriquées. Pour les calculs simples sur une seule colonne, les opérations vectorisées (NumPy) sont plus performantes et lisibles.
`axis=0` applique la fonction colonne par colonne, recevant chaque colonne comme une Series. `axis=1` applique la fonction ligne par ligne, recevant chaque ligne comme une Series. C'est crucial pour la logique métier dépendant de plusieurs champs.
Votre fonction peut retourner une `pd.Series` pour créer plusieurs nouvelles colonnes à la fois. Si elle retourne une liste ou un tuple, utilisez `result_type="expand"` avec `axis=1` pour les transformer en colonnes distinctes.
Évitez `apply` pour des transformations cellule par cellule (`map` est mieux), des agrégations (`agg`), ou si une expression vectorisée est possible. Sur de grands DataFrames, `apply` peut être très lent comparé aux alternatives optimisées de Pandas ou NumPy.

Évaluer l'article

Moyenne: 0.0 / 5 · 0 évaluations

Tags

pandas apply pandas apply axis 1 pandas apply plusieurs colonnes pandas apply retour multiple pandas apply vs vectorisé pandas apply performance
Autor Étienne Lambert
Étienne Lambert
Je m'appelle Étienne Lambert et j'ai 13 ans d'expérience dans le développement web, avec un accent particulier sur JavaScript, le backend, NoSQL et la sécurité. Mon parcours dans ce domaine a commencé par une curiosité insatiable pour la technologie et la manière dont elle façonne notre monde. J'aime partager mes connaissances et aider les lecteurs à naviguer dans les complexités du développement web, en rendant des sujets parfois ardus plus accessibles. Je m'efforce toujours de fournir des informations utiles, précises et à jour, en vérifiant mes sources et en comparant les différentes perspectives. J'écris sur des sujets variés qui vont des meilleures pratiques en matière de sécurité aux tendances émergentes dans le développement. Mon objectif est de simplifier des concepts techniques et d'organiser les connaissances de manière claire, afin que chacun puisse en tirer profit et se sentir confiant dans ses compétences en développement web.

Commentaires (0)

Ajouter un commentaire