Je montre 8 techniques Python (pandas) pour nettoyer vos données rapidement, réduire les erreurs et accélérer l’analyse — utile car les data scientists consacrent ≈80% de leur temps à la préparation des données (CrowdFlower, 2016). Parcourez les exemples prêts à l’emploi.
Comment normaliser les noms de colonnes
Je normalise systématiquement les noms de colonnes pour réduire les bugs, garantir la compatibilité avec des pipelines (ETL, modèles, tests) et faciliter la recherche et la réutilisation du code.
Les bénéfices principaux sont :
- Réduction des erreurs : Les comparaisons de noms deviennent déterministes, évitant les erreurs liées aux espaces ou aux majuscules.
- Compatibilité : Les frameworks et outils attendent souvent des noms simples (par exemple, certains systèmes n’acceptent pas d’espaces ou de caractères non ASCII).
- Maintenabilité : Une convention claire (snake_case) facilite la lecture et la documentation du schéma.
# import pandas as pd
# df.columns = (df.columns
# .str.strip()
# .str.lower()
# .str.replace(‘\s+’, ‘_’, regex=True)
# .str.replace(‘[^0-9a-z_]’, », regex=True))
La première opération .str.strip() supprime les espaces en début et fin de chaîne, évitant des colonnes invisiblement différentes. La seconde .str.lower() force les noms en minuscules pour éliminer les différences de casse. La première .str.replace(‘\s+’, ‘_’, regex=True) remplace une ou plusieurs occurrences d’espaces (regex : \s+) par un underscore afin d’obtenir un séparateur unique. La seconde .str.replace(‘[^0-9a-z_]’, », regex=True) enlève tous les caractères qui ne sont pas des chiffres, des lettres minuscules ou des underscores.
La bonne pratique consiste à conserver des noms simples en snake_case (lettres minuscules + underscores) et à éviter les espaces, les majuscules et les caractères spéciaux. Le terme regex signifie « expression régulière », c’est un langage compact pour décrire des motifs de texte.
Pour garder une hiérarchie comme parent.child, autoriser le point en adaptant la regex : .str.replace(‘[^0-9a-z_.]’, », regex=True). Pour renommer conditionnellement certaines colonnes, utiliser df.rename(mapping, axis=1) où mapping est un dict, par exemple : df.rename({‘Old Name’:’old_name’, ‘Total$’:’total’}, axis=1).
| Opération pandas | Rôle | Exemple concret |
| str.strip() | Supprime espaces en début/fin | » Total » → « Total » |
| str.lower() | Uniformise la casse | « UserID » → « userid » |
| str.replace(regex) | Remplace motifs (espaces → _, suppression caractères) | « First Name » → « first_name » ; « €price » → « price » |
| df.rename(mapping, axis=1) | Renommage ciblé et explicite | {‘Old’:’new_name’} |
Comment supprimer les espaces et convertir les chaînes numériques
Nettoyer les chaînes et convertir les champs numériques évite des erreurs sournoises en aval du pipeline. Commencez par détecter les colonnes texte pour enlever les espaces invisibles sans toucher aux colonnes numériques.
Pour détecter les colonnes texte :
text_cols = df.select_dtypes(include=['object','string']).columns
Pour supprimer les espaces en début/fin sur chaque colonne texte :
for col in text_cols:
df[col] = df[col].str.strip()
Alternative vectorisée quand vous préférez appliquer sur tout le DataFrame en préservant les numériques :
df = df.apply(lambda s: s.str.strip() if s.dtype == 'object' else s)
Il est important de préserver les colonnes numériques pour éviter de forcer des conversions inconsistantes (par exemple des zéros à gauche ou des formats locaux). Ensuite, convertir en sécurité les textes contenant des nombres en types numériques :
# df[‘price’] = pd.to_numeric(df[‘price’], errors=’coerce’)
# df[‘qty’] = pd.to_numeric(df[‘qty’].str.replace(‘,’,’.’), errors=’coerce’)
Utiliser pd.to_numeric(…, errors=’coerce’) force les valeurs non convertibles à NaN (Not a Number). Cette méthode est plus sûre qu’un astype(float) direct qui lèvera une exception si une seule valeur est malformée.
Pour gérer les séparateurs de milliers ou décimaux (ex. ‘1 234’ ou ‘1,234’), normaliser d’abord les chaînes avant conversion :
# Enlever espaces de milliers
df['amount'] = df['amount'].str.replace(' ', '')
# Remplacer la virgule décimale par un point si besoin
df['amount'] = df['amount'].str.replace(',', '.')
df['amount'] = pd.to_numeric(df['amount'], errors='coerce')
Liste d’erreurs courantes et tests rapides :
- Colonnes texte contenant des espaces invisibles : exécuter value_counts() sur un échantillon pour détecter les variantes.
- Formats mixtes (‘,’ vs ‘.’) pour décimales : vérifier avec df[‘col’].unique() ou regex.
- Valeurs non numériques transformées en NaN : contrôler avec df[‘col’].isna().sum() après conversion.
- Conversion forcée par astype(float) qui plante : préférer pd.to_numeric(errors=’coerce’).
- Separateurs de milliers persistants : nettoyer avec str.replace avant conversion.
Comment parser les dates et imputer les valeurs manquantes
J’aborde ici deux opérations fréquentes en prétraitement : convertir des chaînes en dates et imputer les valeurs manquantes de façon sûre. Ces étapes évitent les erreurs downstream et améliorent la qualité des features avant modélisation.
# df[‘date’] = pd.to_datetime(df[‘date_string’], errors=’coerce’)
# df[‘date2’] = pd.to_datetime(df[‘date2′], format=’%d/%m/%Y’, errors=’coerce’)
J’utilise pd.to_datetime pour convertir en datetime pandas. Le paramètre dayfirst=False (par défaut) suppose que le mois vient avant le jour (MM/DD/YYYY).
Le passage dayfirst=True s’impose lorsque vos dates sont au format jour/mois/année (DD/MM/YYYY).
Préciser format=’%d/%m/%Y’ accélère considérablement la conversion car pandas n’essaie pas plusieurs formats (voir documentation pandas pour les détails).
Enfin errors=’coerce’ convertit les valeurs non valides en NaT (Not a Time), évitant d’échouer l’opération et permettant une gestion ultérieure.
Pour l’imputation je privilégie des méthodes simples et robustes : la médiane pour les numériques et le mode pour les catégorielles.
# df['age'] = df['age'].fillna(df['age'].median())
# df['city'] = df['city'].fillna(df['city'].mode().iloc[0])
La médiane est robuste aux outliers contrairement à la moyenne, ce qui évite de biaiser les distributions. Le mode (valeur la plus fréquente) est naturel pour les variables nominales.
Pour respecter l’hétérogénéité des segments, j’impute souvent par groupe : par exemple la médiane d’âge par région. Cela conserve les différences entre clusters et réduit le risque d’introduire un biais global.
# df['age'] = df.groupby('region')['age'].transform(lambda x: x.fillna(x.median()))
Résumé synthétique des méthodes et risques :
| Méthode | Quand l’utiliser | Risque associé |
| Médiane | Colonnes numériques avec outliers | Perte d’information si distribution multi-modale |
| Mode | Colonnes catégorielles | Peut renforcer la catégorie majoritaire |
| Médiane par groupe (groupby+transform) | Imputation segmentée (ex. région, cohortes) | Si groupes petits → estimations instables |
Comment standardiser les catégories et gérer les doublons
Dans ce chapitre, je montre comment normaliser des catégories textuelles et gérer les doublons de manière contrôlée avec pandas, en combinant des opérations simples (.str, map, fillna) et drop_duplicates pour choisir quel enregistrement conserver.
# mapping = {‘new york’:’NYC’, ‘nyc’:’NYC’, ‘ny’:’NYC’}
# df[‘city_clean’] = df[‘city’].str.lower().str.strip().map(mapping).fillna(df[‘city’])
La méthode .str.lower().str.strip() normalise la casse et supprime les espaces superflus pour réduire les variantes. La table de mapping (dictionnaire) unifie les alias vers une même étiquette, ici ‘NYC’. La fonction map applique cette correspondance et retourne NaN pour les valeurs non trouvées.
La fonction fillna prend ces NaN et les remplace par la valeur originale (df[‘city’]), ce qui préserve les valeurs non mappées au lieu de les perdre. Convertir ensuite la colonne finale en dtype ‘category’ réduit la mémoire et accélère les opérations de groupby/aggregation quand le nombre de catégories distinctes est faible comparé au nombre de lignes.
Pour les doublons, il est fréquent de vouloir conserver le dernier événement ou l’enregistrement le plus récent. Trier d’abord permet de définir la priorité, puis drop_duplicates supprime les doublons selon la clé choisie.
# df = df.sort_values(['updated_at']).drop_duplicates(subset=['user_id'], keep='last')
L’argument subset spécifie les colonnes à considérer pour détecter les doublons et keep contrôle lequel garder (‘first’, ‘last’ ou False pour ne rien garder). Pour marquer les doublons sans supprimer, duplicated(keep=False) retourne True pour toutes les lignes ayant au moins une autre occurrence.
Cas d’usage : conserver le dernier événement par utilisateur, marquer toutes les occurrences pour examen manuel, ou fusionner des enregistrements via record linkage ou fuzzy matching pour rapprochement de données — ces techniques avancées nécessitent des librairies dédiées (recordlinkage, rapidfuzz, etc.).
| Méthode | Paramètre | Effet |
| drop_duplicates | keep=’first’ | Conserve la première occurrence, supprime les suivantes |
| drop_duplicates | keep=’last’ | Conserve la dernière occurrence après tri |
| drop_duplicates | keep=False | Supprime toutes les occurrences dupliquées |
| duplicated | keep=’first’ / keep=’last’ | Marque True pour les duplicates sauf la première/dernière |
| duplicated | keep=False | Marque True pour toutes les lignes ayant des doublons |
Comment optimiser les types et réduire la mémoire
Optimiser les types de colonnes réduit significativement la mémoire et accélère les opérations sur DataFrame.
Mesurer la mémoire avant/après avec Pandas est la première étape essentielle :
df.info(memory_usage='deep')
Règles simples et efficaces :
- Convertir les colonnes de type object en category quand le nombre de modalités est faible (≈50 uniques) ou quand le ratio unique/len est bas. La colonne category stocke des codes entiers et une table de niveaux, ce qui peut réduire la mémoire drastiquement si beaucoup de valeurs se répètent.
- Réduire la précision numérique : float64 → float32 et int64 → int32/uint32 quand la plage de valeurs le permet. Les floats en float32 utilisent 4 octets au lieu de 8, les int32 utilisent la moitié de la mémoire des int64.
- Utiliser pd.to_numeric(…, downcast=’unsigned’|’integer’|’float’) pour convertir automatiquement vers le plus petit dtype possible sans perte, quand c’est applicable.
Exemples :
# df[‘col’] = df[‘col’].astype(‘category’)
# df[‘small_int’] = pd.to_numeric(df[‘small_int’], downcast=’unsigned’)
Explications et précautions :
- Le downcast demande à Pandas d’essayer des dtypes plus petits; il échoue s’il y a overflow. Les floats peuvent perdre en précision — vérifier à l’aide d’écarts relatifs.
- Les entiers avec NaN ne peuvent pas devenir int32 natifs sans perte, car les dtypes int natifs ne supportent pas NaN. Utiliser alors les dtypes entiers « nullable » de Pandas (ex. Int32) ou laisser en float.
- Les catégories ont un overhead pour la table des niveaux; elles sont efficaces quand il y a répétition importante.
Pseudo-code :
Pseudo-code : def suggest_dtypes(df): for col in df.columns: if df[col].dtype==’object’ and df[col].nunique()‘category’; elif is_integer_like(col) and no_NaN: suggest downcast integer; elif is_integer_like(col) and has_NaN: suggest ‘Int32’ nullable; elif is_float(col) and range fits: suggest downcast float;
| Type d’origine | Conversion recommandée | Bénéfice mémoire attendu | Précaution |
| object (catégories répétées) | category | Fort (par ex. 5–90%) | Overhead niveaux ; vérifier cardinalité |
| float64 | float32 | ≈50% | Perte de précision possible |
| int64 | int32 / unsigned / Int32 (nullable) | ≈50% ou plus | Overflow ; NaN non supporté par int natif |
Prêt à appliquer ces 8 astuces pour obtenir des données exploitables et fiables ?
Ces 8 astuces Python (normalisation des colonnes, suppression des espaces, conversion sécurisée, parsing des dates, imputations intelligentes, standardisation des catégories, déduplication contrôlée et optimisation des types) forment une boîte à outils pratique. En appliquant ces techniques vous réduisez les erreurs, facilitez la reproductibilité et gagnez du temps — bénéfice direct : analyses plus rapides et modèles plus fiables.
FAQ
-
Faut-il toujours convertir les colonnes texte en category ?
Pas systématiquement. Convertissez en ‘category’ quand le nombre de modalités est nettement inférieur au nombre de lignes (par ex. -
Pourquoi utiliser errors=’coerce’ avec pd.to_numeric ou pd.to_datetime ?
errors=’coerce’ transforme les valeurs non convertibles en NaN/NaT au lieu de provoquer une exception, ce qui permet d’identifier et d’imputer proprement les erreurs sans interrompre le pipeline. -
Comment choisir entre médiane et moyenne pour imputer ?
La médiane est préférable en présence d’outliers car elle est robuste. La moyenne peut être utilisée si la distribution est proche d’une loi normale et que les outliers sont rares. -
Que faire pour des doublons partiels ou proches mais non identiques ?
Pour les doublons approximatifs, utilisez du fuzzy matching ou des librairies de record linkage (par ex. python-record-linkage). Commencez par standardiser les champs (trim, lower, mapping) avant d’appliquer des méthodes floues. -
Quel ordre suivre pour un pipeline de prétraitement ?
Ordre recommandé : 1) normaliser noms de colonnes, 2) nettoyer chaînes (strip, lower), 3) convertir types (numeric/date), 4) gérer valeurs manquantes, 5) standardiser catégories, 6) déduplication, 7) optimiser dtypes. Cela minimise les erreurs de conversion.
A propos de l’auteur
Franck Scandolera — expert & formateur en Tracking avancé server-side, Analytics Engineering, Automatisation No/Low Code (n8n) et intégration de l’IA. Responsable de l’agence webAnalyste et de l’organisme de formation « Formations Analytics ». Références clients : Logis Hôtel, Yelloh Village, BazarChic, Fédération Française de Football, Texdecor. Disponible pour aider les entreprises : contactez-moi.
⭐ Analytics engineer, Data Analyst et Automatisation IA indépendant ⭐
- Ref clients : Logis Hôtel, Yelloh Village, BazarChic, Fédération Football Français, Texdecor…
Mon terrain de jeu :
- Data Analyst & Analytics engineering : tracking avancé (GTM server, e-commerce, CAPI, RGPD), entrepôt de données (BigQuery, Snowflake, PostgreSQL, ClickHouse), modèles (Airflow, dbt, Dataform), dashboards décisionnels (Looker, Power BI, Metabase, SQL, Python).
- Automatisation IA des taches Data, Marketing, RH, compta etc : conception de workflows intelligents robustes (n8n, App Script, scraping) connectés aux API de vos outils et LLM (OpenAI, Mistral, Claude…).
- Engineering IA pour créer des applications et agent IA sur mesure : intégration de LLM (OpenAI, Mistral…), RAG, assistants métier, génération de documents complexes, APIs, backends Node.js/Python.






