Pandas fillna() : Gérer les valeurs manquantes dans les DataFrames
Updated on
Les valeurs manquantes sont le saboteur silencieux de l'analyse de données. Un seul NaN caché dans une colonne critique peut faire qu'une agrégation renvoie NaN, qu'un modèle de machine learning lance une erreur lors de l'entraînement, ou qu'un graphique de tableau de bord affiche un espace vide là où devrait se trouver une ligne de tendance. Les jeux de données du monde réel contiennent presque toujours des lacunes -- les relevés de capteurs s'interrompent, les répondants à des enquêtes sautent des questions, les réponses d'API renvoient des champs nuls, et les exports CSV arrivent avec des cellules vides. La question n'est jamais de savoir si vous rencontrerez des données manquantes, mais comment vous les gérerez.
La méthode fillna() de pandas est l'outil principal pour remplacer les valeurs manquantes par quelque chose de significatif. Ce guide couvre chaque paramètre, démontre les stratégies de remplissage courantes (scalaire, dictionnaire, forward fill, backward fill, moyenne/médiane/mode), compare fillna() à dropna() et interpolate(), et montre comment chaîner ces opérations dans un pipeline de données propre. Chaque exemple de code est prêt à copier avec la sortie attendue.
Détecter les valeurs manquantes avant de les remplir
Avant de remplir quoi que ce soit, vous devez savoir où se trouvent les lacunes. Pandas fournit trois fonctions de détection :
import pandas as pd
import numpy as np
df = pd.DataFrame({
'name': ['Alice', 'Bob', None, 'Diana', 'Eve'],
'age': [28, np.nan, 35, np.nan, 42],
'salary': [55000, 62000, np.nan, 48000, np.nan]
})
# isna() renvoie True pour les valeurs manquantes (alias : isnull())
print(df.isna())Sortie :
name age salary
0 False False False
1 False True False
2 True False True
3 False True False
4 False False TrueRésumé rapide des comptages de valeurs manquantes
# Compter les valeurs manquantes par colonne
print(df.isna().sum())Sortie :
name 1
age 2
salary 2
dtype: int64notna() pour la vérification inverse
# notna() renvoie True pour les valeurs non manquantes
print(df.notna().sum())Sortie :
name 4
age 3
salary 3
dtype: int64| Fonction | Renvoie True quand | Alias |
|---|---|---|
isna() | La valeur est NaN, None ou NaT | isnull() |
notna() | La valeur n'est pas manquante | notnull() |
Ces fonctions fonctionnent aussi bien sur les DataFrames que sur les Series individuelles. Utilisez-les pour auditer vos données avant de décider d'une stratégie de remplissage.
fillna() basique avec une valeur scalaire
L'utilisation la plus simple de fillna() remplace chaque NaN du DataFrame par une seule valeur :
import pandas as pd
import numpy as np
df = pd.DataFrame({
'product': ['Widget', 'Gadget', 'Gizmo'],
'price': [19.99, np.nan, 29.99],
'stock': [100, 50, np.nan]
})
print("Avant :")
print(df)
df_filled = df.fillna(0)
print("\nAprès fillna(0) :")
print(df_filled)Sortie :
Avant :
product price stock
0 Widget 19.99 100.0
1 Gadget NaN 50.0
2 Gizmo 29.99 NaN
Après fillna(0) :
product price stock
0 Widget 19.99 100.0
1 Gadget 0.00 50.0
2 Gizmo 29.99 0.0Cela fonctionne, mais remplir une colonne de prix avec 0 est trompeur -- cela suggère que le produit est gratuit. Pour les colonnes de texte, vous pourriez remplir avec "Inconnu". La clé est de choisir une valeur de remplissage qui a un sens sémantique pour chaque colonne.
Signature complète de la méthode
DataFrame.fillna(value=None, method=None, axis=None, inplace=False, limit=None)| Paramètre | Type | Défaut | Description |
|---|---|---|---|
value | scalaire, dict, Series ou DataFrame | None | La valeur pour remplir les entrées manquantes |
method | 'ffill', 'bfill' ou None | None | Méthode de propagation pour remplir les lacunes |
axis | 0 ou 1 | None | Remplir le long des lignes (0) ou des colonnes (1) |
inplace | bool | False | Si True, modifie le DataFrame sur place |
limit | int | None | Nombre maximum de NaN consécutifs à remplir |
fillna() avec un dictionnaire : Différentes valeurs par colonne
Dans la plupart des jeux de données réels, chaque colonne représente un type de mesure différent, et une seule valeur de remplissage n'a pas de sens partout. Passez un dictionnaire à fillna() pour spécifier les valeurs de remplissage par colonne :
import pandas as pd
import numpy as np
df = pd.DataFrame({
'name': ['Alice', None, 'Charlie', 'Diana'],
'age': [28, 34, np.nan, 45],
'department': ['Engineering', 'Sales', None, 'Marketing'],
'salary': [75000, np.nan, 68000, np.nan]
})
fill_values = {
'name': 'Unknown',
'age': df['age'].median(),
'department': 'Unassigned',
'salary': df['salary'].mean()
}
df_filled = df.fillna(fill_values)
print(df_filled)Sortie :
name age department salary
0 Alice 28.0 Engineering 75000.0
1 Unknown 34.0 Sales 71500.0
2 Charlie 34.0 Unassigned 68000.0
3 Diana 45.0 Marketing 71500.0C'est l'approche recommandée pour les pipelines de données en production car elle vous donne un contrôle explicite sur ce que chaque colonne reçoit.
Forward Fill (ffill) et Backward Fill (bfill)
Les données de séries temporelles et les jeux de données ordonnés bénéficient souvent d'un remplissage basé sur la propagation. Le forward fill transmet la dernière valeur connue vers l'avant ; le backward fill prend la prochaine valeur connue vers l'arrière.
import pandas as pd
import numpy as np
df = pd.DataFrame({
'date': pd.date_range('2026-01-01', periods=7, freq='D'),
'temperature': [22.1, np.nan, np.nan, 24.5, np.nan, 26.0, np.nan]
})
print("Original :")
print(df)
print("\nForward fill (ffill) :")
print(df.fillna(method='ffill'))
print("\nBackward fill (bfill) :")
print(df.fillna(method='bfill'))Sortie :
Original :
date temperature
0 2026-01-01 22.1
1 2026-01-02 NaN
2 2026-01-03 NaN
3 2026-01-04 24.5
4 2026-01-05 NaN
5 2026-01-06 26.0
6 2026-01-07 NaN
Forward fill (ffill) :
date temperature
0 2026-01-01 22.1
1 2026-01-02 22.1
2 2026-01-03 22.1
3 2026-01-04 24.5
4 2026-01-05 24.5
5 2026-01-06 26.0
6 2026-01-07 26.0
Backward fill (bfill) :
date temperature
0 2026-01-01 22.1
1 2026-01-02 24.5
2 2026-01-03 24.5
3 2026-01-04 24.5
4 2026-01-05 26.0
5 2026-01-06 26.0
6 2026-01-07 NaNRemarquez que le backward fill laisse la dernière ligne comme NaN car il n'y a pas de valeur suivante à extraire. Vous pouvez combiner les deux méthodes pour combler toutes les lacunes :
df_filled = df.fillna(method='ffill').fillna(method='bfill')
print(df_filled)À partir de pandas 2.1, vous pouvez également utiliser directement les méthodes autonomes df.ffill() et df.bfill(), qui sont des raccourcis pour fillna(method='ffill') et fillna(method='bfill').
Limiter la propagation avec limit
Quand un capteur tombe en panne pendant des jours, le forward fill indéfini peut masquer de véritables lacunes dans les données. Le paramètre limit plafonne le nombre de NaN consécutifs qui sont remplis :
import pandas as pd
import numpy as np
s = pd.Series([1.0, np.nan, np.nan, np.nan, 5.0])
print("limit=1 :")
print(s.fillna(method='ffill', limit=1))
print("\nlimit=2 :")
print(s.fillna(method='ffill', limit=2))Sortie :
limit=1 :
0 1.0
1 1.0
2 NaN
3 NaN
4 5.0
dtype: float64
limit=2 :
0 1.0
1 1.0
2 1.0
3 NaN
4 5.0
dtype: float64C'est essentiel pour les données de séries temporelles où vous voulez combler les petites lacunes mais signaler les pannes plus longues pour une révision manuelle.
fillna() avec moyenne, médiane et mode
L'imputation statistique remplace les valeurs manquantes par une statistique résumée calculée à partir des valeurs non manquantes de cette colonne. C'est la stratégie la plus courante pour les caractéristiques numériques avant d'alimenter un modèle en données :
import pandas as pd
import numpy as np
df = pd.DataFrame({
'math_score': [85, np.nan, 92, 78, np.nan, 88],
'reading_score': [np.nan, 76, 81, np.nan, 90, 85],
'grade': ['A', 'B', 'A', np.nan, 'B', np.nan]
})
# Remplir les colonnes numériques avec leur moyenne de colonne
df['math_score'] = df['math_score'].fillna(df['math_score'].mean())
df['reading_score'] = df['reading_score'].fillna(df['reading_score'].median())
# Remplir la colonne catégorielle avec le mode (valeur la plus fréquente)
df['grade'] = df['grade'].fillna(df['grade'].mode()[0])
print(df)Sortie :
math_score reading_score grade
0 85.00 83.00 A
1 85.75 76.00 B
2 92.00 81.00 A
3 78.00 83.00 A
4 85.75 90.00 B
5 88.00 85.00 A| Stratégie | Idéal pour | Notes |
|---|---|---|
mean() | Données numériques avec des distributions approximativement symétriques | Sensible aux valeurs aberrantes |
median() | Données numériques avec des distributions asymétriques ou des valeurs aberrantes | Plus robuste que la moyenne |
mode() | Données catégorielles ou valeurs numériques discrètes | Renvoie la valeur la plus courante ; mode()[0] prend la première en cas d'égalité |
Pour les pipelines de machine learning, envisagez d'utiliser sklearn.impute.SimpleImputer qui s'intègre aux pipelines scikit-learn et gère correctement l'imputation dans la séparation train/test.
interpolate() pour les données numériques
Quand les données suivent une tendance (prix des actions, relevés de capteurs, métriques de croissance), interpolate() estime les valeurs manquantes en se basant sur les points de données environnants plutôt qu'en utilisant un remplissage plat :
import pandas as pd
import numpy as np
df = pd.DataFrame({
'day': range(1, 8),
'revenue': [1000, np.nan, np.nan, 1600, np.nan, 2000, np.nan]
})
df['fillna_ffill'] = df['revenue'].fillna(method='ffill')
df['interpolated'] = df['revenue'].interpolate(method='linear')
print(df)Sortie :
day revenue fillna_ffill interpolated
0 1 1000.0 1000.0 1000.0
1 2 NaN 1000.0 1200.0
2 3 NaN 1000.0 1400.0
3 4 1600.0 1600.0 1600.0
4 5 NaN 1600.0 1800.0
5 6 2000.0 2000.0 2000.0
6 7 NaN 2000.0 2000.0Remarquez comment interpolate() produit une progression linéaire lisse (1000, 1200, 1400, 1600, 1800, 2000) tandis que ffill crée des plateaux plats. Pandas prend en charge plusieurs méthodes d'interpolation :
| Méthode | Description |
|---|---|
'linear' | Par défaut. Trace une ligne droite entre les points connus. |
'time' | Interpolation linéaire pondérée par l'index temporel. |
'index' | Utilise les valeurs numériques réelles de l'index. |
'polynomial' | Ajuste un polynôme de l'ordre spécifié. |
'spline' | Ajuste une spline de l'ordre spécifié pour des courbes lisses. |
Utilisez interpolate() quand les données ont un ordre naturel et une tendance. Utilisez fillna() quand vous avez une valeur de remplacement connue ou avez besoin d'un remplissage basé sur la propagation.
Le paramètre inplace
Comme la plupart des méthodes pandas, fillna() renvoie un nouveau DataFrame par défaut. Définir inplace=True modifie l'original :
import pandas as pd
import numpy as np
df = pd.DataFrame({'a': [1, np.nan, 3], 'b': [np.nan, 5, 6]})
# Méthode 1 : assignation (recommandé)
df_new = df.fillna(0)
print(f"Original inchangé : {df.isna().sum().sum()} NaNs")
print(f"Nouvelle copie : {df_new.isna().sum().sum()} NaNs")
# Méthode 2 : inplace (modifie l'original)
df.fillna(0, inplace=True)
print(f"Après inplace : {df.isna().sum().sum()} NaNs")Sortie :
Original inchangé : 2 NaNs
Nouvelle copie : 0 NaNs
Après inplace : 0 NaNsLa bonne pratique moderne de pandas favorise l'assignation plutôt que inplace=True car l'assignation fonctionne naturellement dans les chaînes de méthodes et rend le flux de données explicite.
Comparaison : fillna() vs dropna() vs interpolate()
Le choix de la bonne stratégie pour les données manquantes dépend de votre jeu de données, du schéma de données manquantes et de votre cas d'utilisation en aval. Voici une comparaison côte à côte :
| Aspect | fillna() | dropna() | interpolate() |
|---|---|---|---|
| Ce que ça fait | Remplace NaN par une valeur spécifiée | Supprime les lignes ou colonnes contenant NaN | Estime NaN à partir des valeurs environnantes |
| Nombre de lignes | Préservé | Réduit | Préservé |
| Idéal pour | Valeurs de remplacement connues, données catégorielles, imputation statistique | Petit pourcentage de lignes manquantes, ou quand l'imputation fausserait l'analyse | Données numériques ordonnées/séries temporelles avec tendance naturelle |
| Risque | Introduit un biais si la valeur de remplissage est mal choisie | Perd des données ; peut biaiser les résultats si les données ne manquent pas aléatoirement | Suppose un schéma sous-jacent lisse qui peut ne pas exister |
| Cas d'utilisation typique | Remplir les réponses d'enquête manquantes avec "Pas de réponse", remplir les prix avec la moyenne de la colonne | Supprimer les lignes sans variable cible avant l'entraînement du modèle | Combler les lacunes dans les prix quotidiens d'actions ou les relevés de température |
| Gère les données catégorielles | Oui | Oui (par suppression) | Non (numérique uniquement) |
| Compatible avec le chaînage | Oui | Oui | Oui |
Règle empirique pour la décision :
- Si moins de 5% des lignes manquent et que les données manquent complètement au hasard,
dropna()est sûr. - Si vous avez une valeur par défaut significative ou pouvez calculer une statistique raisonnable, utilisez
fillna(). - Si les données sont ordonnées et numériques avec une tendance, utilisez
interpolate().
fillna() sur des colonnes spécifiques
Vous ne voulez pas toujours remplir l'ensemble du DataFrame. Appliquez fillna() à des colonnes individuelles ou à un sous-ensemble :
import pandas as pd
import numpy as np
df = pd.DataFrame({
'city': ['NYC', None, 'LA', None, 'Chicago'],
'temperature': [32.1, np.nan, 75.3, np.nan, 28.5],
'humidity': [45, 60, np.nan, np.nan, 55]
})
# Remplir uniquement la colonne ville
df['city'] = df['city'].fillna('Unknown')
# Remplir uniquement la colonne température avec sa moyenne
df['temperature'] = df['temperature'].fillna(df['temperature'].mean())
# Laisser les NaN d'humidité intacts pour l'instant
print(df)Sortie :
city temperature humidity
0 NYC 32.100000 45.0
1 Unknown 45.300000 60.0
2 LA 75.300000 NaN
3 Unknown 45.300000 NaN
4 Chicago 28.500000 55.0Cette approche sélective est importante quand différentes colonnes nécessitent un traitement différent -- ou quand certaines valeurs manquantes sont intentionnelles (par exemple, l'humidité pourrait ne pas s'appliquer aux mesures intérieures).
Chaîner fillna() avec d'autres opérations
Le chaînage de méthodes pandas permet de construire des pipelines de données lisibles. fillna() s'intègre naturellement dans ces chaînes :
import pandas as pd
import numpy as np
raw = pd.DataFrame({
'customer_id': [101, 102, 101, 103, 102, 104],
'purchase': [25.0, np.nan, 30.0, np.nan, 15.0, np.nan],
'channel': ['web', 'store', None, 'web', None, 'store']
})
result = (
raw
.fillna({'purchase': 0, 'channel': 'unknown'})
.drop_duplicates(subset=['customer_id'], keep='first')
.sort_values('customer_id')
.reset_index(drop=True)
)
print(result)Sortie :
customer_id purchase channel
0 101 25.0 web
1 102 0.0 store
2 103 0.0 web
3 104 0.0 storeCe pipeline remplit les valeurs manquantes, déduplique par identifiant client, trie et réinitialise l'index en une seule expression lisible.
Pipeline concret : Nettoyage des données de ventes
Voici une chaîne plus réaliste qui combine plusieurs étapes de nettoyage :
import pandas as pd
import numpy as np
sales = pd.DataFrame({
'date': ['2026-01-01', '2026-01-02', '2026-01-03', '2026-01-04', '2026-01-05'],
'product': ['Widget', None, 'Widget', 'Gadget', None],
'units': [10, np.nan, 15, np.nan, 8],
'unit_price': [9.99, 9.99, np.nan, 14.99, np.nan],
'region': ['East', 'East', None, 'West', 'West']
})
clean = (
sales
.assign(date=lambda d: pd.to_datetime(d['date']))
.fillna({
'product': 'Unknown',
'region': 'Unassigned',
'units': sales['units'].median(),
'unit_price': sales['unit_price'].median()
})
.assign(total=lambda d: d['units'] * d['unit_price'])
.sort_values('date')
.reset_index(drop=True)
)
print(clean)Sortie :
date product units unit_price region total
0 2026-01-01 Widget 10.0 9.99 East 99.90
1 2026-01-02 Unknown 10.0 9.99 East 99.90
2 2026-01-03 Widget 15.0 9.99 Unassigned 149.85
3 2026-01-04 Gadget 10.0 14.99 West 149.90
4 2026-01-05 Unknown 8.0 9.99 West 79.92Les appels assign() créent ou transforment des colonnes, fillna() gère les lacunes, et la chaîne s'écoule de haut en bas dans un ordre logique.
Visualiser les patterns de données manquantes avec PyGWalker
Avant de choisir une stratégie de remplissage, il est utile de voir où les valeurs manquantes sont concentrées. Sont-elles dispersées aléatoirement, regroupées dans certaines colonnes, ou corrélées avec des périodes spécifiques ? L'inspection visuelle révèle souvent des patterns que les statistiques résumées manquent.
PyGWalker (opens in a new tab) est une bibliothèque Python open source qui transforme n'importe quel DataFrame pandas en une interface de visualisation interactive de type Tableau directement dans Jupyter Notebook. Vous pouvez glisser-déposer des colonnes sur les axes, changer les types de graphiques et filtrer les données par clics au lieu d'écrire du code matplotlib répétitif.
import pandas as pd
import pygwalker as pyg
# Chargez vos données et marquez les patterns manquants
df = pd.read_csv('your_data.csv')
# Ajouter une colonne comptant les valeurs manquantes par ligne
df['missing_count'] = df.isna().sum(axis=1)
# Lancer l'explorateur interactif
walker = pyg.walk(df)Dans l'interface PyGWalker, vous pouvez créer des diagrammes en barres montrant le comptage des valeurs manquantes par colonne, des cartes de chaleur révélant quelles lignes ont le plus de lacunes, et des nuages de points pour vérifier si les données manquantes sont corrélées avec d'autres variables. Ce type d'audit visuel change souvent la stratégie de remplissage que vous choisissez.
Installez PyGWalker avec
pip install pygwalkerou essayez-le dans Google Colab (opens in a new tab).
FAQ
Quelle est la différence entre fillna() et dropna() ?
fillna() remplace les valeurs manquantes par une valeur que vous spécifiez, en conservant toutes les lignes intactes. dropna() supprime les lignes entières (ou colonnes) qui contiennent des valeurs manquantes. Utilisez fillna() quand vous avez une valeur de remplacement raisonnable et voulez préserver votre nombre de lignes. Utilisez dropna() quand les lignes manquantes sont peu nombreuses et que l'imputation introduirait un biais inacceptable.
Puis-je remplir les valeurs NaN avec la moyenne d'une colonne ?
Oui. Utilisez df['column'] = df['column'].fillna(df['column'].mean()). Cela calcule la moyenne à partir des valeurs non manquantes et remplit chaque NaN dans cette colonne avec le résultat. Pour des données asymétriques, median() est souvent un meilleur choix car elle est moins affectée par les valeurs aberrantes extrêmes.
Que fait le paramètre limit dans fillna() ?
Le paramètre limit plafonne le nombre maximum de valeurs NaN consécutives qui sont remplies. Par exemple, df.fillna(method='ffill', limit=2) fera un forward fill d'au maximum 2 lacunes consécutives. Toute séquence plus longue de valeurs manquantes ne sera que partiellement remplie, laissant les lacunes restantes comme NaN. C'est utile pour les données de séries temporelles où vous voulez combler les petites lacunes mais signaler les pannes prolongées.
Comment remplir NaN avec différentes valeurs pour différentes colonnes ?
Passez un dictionnaire à fillna() où les clés sont les noms de colonnes et les valeurs sont les valeurs de remplissage : df.fillna({'age': 0, 'name': 'Unknown', 'salary': df['salary'].median()}). Chaque colonne reçoit sa propre valeur de remplissage, et les colonnes non listées dans le dictionnaire restent inchangées.
fillna() modifie-t-il le DataFrame original ?
Non, par défaut fillna() renvoie un nouveau DataFrame et l'original reste inchangé. Pour modifier l'original, utilisez soit l'assignation (df = df.fillna(0)) soit passez inplace=True. L'approche par assignation est recommandée car elle fonctionne avec le chaînage de méthodes et rend le flux de données explicite.
Conclusion
Les valeurs manquantes sont inévitables dans les données du monde réel. La méthode fillna() de pandas vous donne un contrôle précis sur la façon de les gérer :
- Utilisez le fillna scalaire pour des remplacements simples et uniformes dans tout le DataFrame.
- Utilisez le fillna avec dictionnaire pour appliquer différentes stratégies de remplissage par colonne -- le pattern le plus courant dans le code de production.
- Utilisez le forward fill (ffill) et le backward fill (bfill) pour les données ordonnées et les séries temporelles où la propagation des valeurs connues a du sens.
- Utilisez la moyenne, la médiane ou le mode pour l'imputation statistique des colonnes numériques et catégorielles.
- Utilisez interpolate() quand les données suivent une tendance naturelle et que vous voulez des valeurs estimées lisses plutôt que des remplissages plats.
- Utilisez le paramètre limit pour empêcher les méthodes basées sur la propagation de remplir des lacunes excessivement longues.
- Préférez l'assignation à inplace=True pour un code plus propre et plus lisible.
- Détectez et auditez toujours les valeurs manquantes avec
isna()etnotna()avant de choisir une stratégie de remplissage.
Une fois vos valeurs manquantes traitées, des outils comme PyGWalker (opens in a new tab) vous permettent d'explorer interactivement les données nettoyées sans écrire de code de graphiques -- vous aidant à vérifier que votre logique de remplissage a produit des résultats sensés et à passer directement à l'analyse.