Tu veux entraîner un modèle, brancher un LLM sur tes fichiers, ou simplement comprendre ce que contiennent tes données ? Avant toute chose, il faudra passer par la case nettoyage. Et pour ça, il y a un outil incontournable : Pandas. Cette bibliothèque Python est le couteau suisse de la manipulation de données : elle te permet de charger un tableau, de l'explorer, de le nettoyer et de le transformer, le tout en quelques lignes de code. Dans ce tutoriel, on va partir d'un mini-dataset volontairement sale — valeurs manquantes, doublons, types incohérents — et le transformer en données propres et exploitables, en une vingtaine de minutes chrono.
Pourquoi Pandas plutôt qu'Excel
Excel est pratique pour une poignée de lignes et des calculs ponctuels. Mais dès que tes données grossissent, que tes traitements deviennent répétitifs ou que tu dois enchaîner plusieurs étapes, le tableur montre ses limites : difficile de rejouer un traitement, de le versionner, de l'automatiser. Pandas, lui, te donne un objet central — le DataFrame — sur lequel tu enchaînes des opérations lisibles et reproductibles.
Un DataFrame, c'est un tableau à deux dimensions, comme une feuille de calcul : des lignes et des colonnes, chaque colonne ayant un type. Sur ce tableau, tu peux sélectionner, filtrer, agréger, joindre, pivoter. Et surtout, le code que tu écris est un véritable script : tu peux le relancer sur un nouveau fichier en changeant une seule ligne. C'est ce qui rend Pandas indispensable dans tout projet de data science, et c'est aussi le format de données que consomment la plupart des bibliothèques de machine learning.
Concrètement, la différence se sent dès le premier nettoyage : ce qui te prendrait dix minutes de clics dans un tableur — supprimer les doublons, combler les trous, convertir les types — se résume à trois lignes de Python, rejouables à l'infini et documentées par le code lui-même.
Prérequis : installer Pandas
L'installation tient en une commande. Pandas s'appuie sur NumPy, qui sera installé automatiquement comme dépendance.
pip install pandasTu peux vérifier que tout est en place avec un import et un affichage de version. On utilisera aussi, plus loin, pyarrow pour exporter en Parquet — mais c'est optionnel.
import pandas as pd
print(pd.__version__)Charger des données dans un DataFrame
Dans la vraie vie, tu chargeras un CSV, un fichier Excel ou une table de base de données. Pour rester autonome ici, on construit le dataset directement en Python : c'est aussi un bon moyen de voir la structure d'un DataFrame.
import pandas as pd
donnees = {
"client": ["Alice", "Bob", "Alice", None, "Clara", "Bob", "David"],
"age": [34, "28", 34, 45, None, 28, "inconnu"],
"montant": [120.5, 80, 120.5, 55, 200, 80, 150],
"pays": ["FR", "BE", "FR", "US", "FR", "BE", "US"],
"date": ["2024-01-05", "2024-01-06", "2024-01-05", "2024-01-07",
"2024-01-08", "2024-01-06", "2024-01-09"],
}
df = pd.DataFrame(donnees)
print(df)Observe bien ce tableau : la ligne 3 n'a pas de client, la colonne age mélange des nombres et des chaînes (dont un « inconnu » et une valeur manquante), la ligne 2 est un doublon de la ligne 0, et la colonne date est stockée sous forme de texte. C'est un condensé de tout ce qu'on croise dans des données réelles. Le chargement depuis un fichier est aussi simple qu'un appel :
# Charger un CSV (le séparateur par défaut est la virgule)
df = pd.read_csv("commandes.csv")
# Charger un fichier Excel
df = pd.read_excel("commandes.xlsx")Explorer avant de corriger
Avant de nettoyer, on regarde. Trois commandes suffisent pour prendre la température d'un DataFrame :
df.shape # (7, 5) : 7 lignes, 5 colonnes
df.info() # le type de chaque colonne et le compte des valeurs non nulles
df.describe() # les statistiques des colonnes numériques (moyenne, min, max...)shape te donne les dimensions du tableau. info() est la commande la plus utile : elle liste chaque colonne avec son type (object pour du texte, int64 pour des entiers...) et révèle d'un coup d'oeil les colonnes qui contiennent des valeurs manquantes. describe() calcule les statistiques de base sur les colonnes numériques. Complète le tout avec head() pour afficher les premières lignes, et value_counts() pour compter les valeurs d'une colonne :
df.head() # les 5 premières lignes
df["pays"].value_counts() # combien de lignes par paysCe tour d'horizon n'est jamais une perte de temps : il t'évite de nettoyer à l'aveugle. Tu repars avec une idée claire de ce qui est propre, de ce qui est sale, et de l'ordre dans lequel attaquer les problèmes.
Sélectionner des lignes et des colonnes
Avant de nettoyer en profondeur, il faut savoir naviguer dans un DataFrame. Deux familles d'outils se partagent le travail : les crochets pour sélectionner par nom, et loc/iloc pour des sélections plus fines.
# Sélectionner une colonne -> une Series
df["montant"]
# Sélectionner plusieurs colonnes -> un DataFrame
df[["client", "montant"]]
# Filtrer les lignes selon une condition
df[df["montant"] > 100]
# Sélectionner par position (iloc) ou par étiquette (loc)
df.iloc[0] # la première ligne
df.loc[0:2, "client"] # lignes 0 à 2, colonne clientRetiens la distinction : iloc travaille par position (l'index numérique), loc par étiquette. Dans la pratique, tu utiliseras surtout la sélection par condition — df[df["montant"] > 100] — car c'est elle qui fait le tri dans tes données.
Nettoyer les valeurs manquantes et les doublons
Place au grand ménage. On enchaîne les corrections en quelques lignes : suppression des lignes sans client, élimination des doublons, conversion de la colonne age en numérique (les valeurs invalides deviennent des valeurs manquantes), puis comblement de ces trous.
df = df.dropna(subset=["client"]) # vire les lignes sans client
df = df.drop_duplicates() # supprime les doublons
df["age"] = pd.to_numeric(df["age"], errors="coerce") # "inconnu" devient NaN
df["age"] = df["age"].fillna(df["age"].median()) # comble avec la médiane
df["date"] = pd.to_datetime(df["date"]) # force le type dateDétaillons le raisonnement. dropna supprime les lignes où la colonne client est vide : pas de commande sans client, c'est une règle métier. drop_duplicates vire les lignes strictement identiques. Pour l'âge, to_numeric avec errors="coerce" remplace tout ce qui n'est pas un nombre par NaN (Not a Number, la valeur manquante de Pandas). Enfin, fillna comble ces NaN : on choisit la médiane, plus robuste que la moyenne face aux valeurs extrêmes.
Quelle stratégie face aux valeurs manquantes ?
Il n'y a pas de règle universelle, et c'est souvent là que se joue la qualité d'un projet. Le choix dépend du contexte :
- Supprimer la ligne : quand la donnée manquante est essentielle et qu'il y a peu de lignes concernées.
- Compléter avec une constante : utile quand l'absence a une signification (exemple : pays inconnu).
- Compléter avec une statistique (moyenne, médiane) : pour une variable numérique continue.
- Laisser vide : si l'algorithme en aval sait gérer les valeurs manquantes.
Transformer et enrichir les données
Des données propres, c'est bien. Des données exploitables, c'est mieux. On crée de nouvelles colonnes dérivées et on agrège par groupe. groupby().transform() calcule le panier moyen par client et le recopie sur chaque ligne, ce qui évite de casser la granularité du tableau.
df["panier_moyen"] = df.groupby("client")["montant"].transform("mean")
df["est_vip"] = df["panier_moyen"] > 100
top_pays = df.groupby("pays")["montant"].sum().sort_values(ascending=False)
print(top_pays)La colonne est_vip est un booléen : True si le client dépense en moyenne plus de 100, False sinon. Ce genre de variable dérivée est exactement ce que les modèles de machine learning adorent consommer. Le groupby par pays, lui, te dit en une ligne où se concentre ton chiffre d'affaires.
La nuance entre transform() et agg() mérite qu'on s'y attarde, car elle piège souvent les débutants. agg() réduit chaque groupe à une seule ligne (une ligne par client), tandis que transform() recopie la valeur calculée sur toutes les lignes du groupe, en conservant la forme du tableau d'origine. Quand tu veux ajouter une colonne sans changer le nombre de lignes, c'est transform() qu'il te faut.
Filtrer et trier
Deux opérations que tu feras en boucle : sélectionner des lignes selon une condition, et trier le résultat. La syntaxe est proche de l'anglais, ce qui la rend très lisible :
# Les commandes des clients VIP, triées du plus gros montant au plus petit
vip = df[df["est_vip"] == True]
vip = vip.sort_values("montant", ascending=False)
print(vip[["client", "montant", "pays"]])Fusionner des tables avec merge
Les données réelles vivent rarement dans un seul tableau : les clients dans un fichier, les commandes dans un autre. merge() permet de les joindre sur une colonne commune, exactement comme un JOIN en SQL. C'est une des opérations les plus puissantes de Pandas.
clients = pd.DataFrame({
"client": ["Alice", "Bob", "Clara", "David"],
"ville": ["Lyon", "Paris", "Marseille", "Lille"],
})
# Jointure gauche : on garde toutes les commandes, on ajoute la ville du client
fusion = df.merge(clients, on="client", how="left")
print(fusion.head())Le paramètre how contrôle le type de jointure : left pour garder toutes les lignes du tableau de gauche, inner pour ne garder que les lignes présentes des deux côtés, outer pour tout conserver. left est le choix le plus courant quand ton tableau principal est celui des commandes et que tu veux l'enrichir avec des informations clients.
Travailler avec les dates
Une fois la colonne date convertie en vrai type datetime, Pandas ouvre une boîte à outils complète : extraire l'année, le mois ou le jour de la semaine, filtrer sur une période, ou calculer des écarts. C'est indispensable dès que tu analyses des séries temporelles.
# Extraire des composantes de la date
df["annee"] = df["date"].dt.year
df["mois"] = df["date"].dt.month
df["jour_semaine"] = df["date"].dt.day_name()
# Filtrer les commandes d'une période donnée
de_janvier = df[df["date"] >= "2024-01-01"]
# Regrouper par mois et sommer les montants
par_mois = df.groupby(df["date"].dt.to_period("M"))["montant"].sum()
print(par_mois)L'attribut .dt débloque ces opérations sur une colonne datetime. Le regroupement par période (ici, par mois via to_period) est un classique des rapports : il transforme une liste de commandes en une courbe de chiffre d'affaires mensuel, prête à être tracée.
Exporter le résultat
Une fois le travail fait, on sauvegarde le résultat. Le CSV reste le format d'échange universel ; le Parquet, plus compact et plus rapide à relire, est idéal pour des données intermédiaires.
df.to_csv("commandes_propres.csv", index=False)
# Optionnel : le Parquet préserve les types (nécessite pip install pyarrow)
df.to_parquet("commandes.parquet")Le paramètre index=False évite d'écrire l'index dans le fichier : sans lui, tu te retrouverais avec une colonne fantôme à la relecture. Pour relire ces fichiers, c'est l'inverse de l'écriture : read_csv() et read_parquet().
Aller plus loin : apply et pivot_table
Tu as maintenant les bases. Deux briques supplémentaires couvrent l'essentiel des besoins réels :
- apply() : appliquer une fonction personnalisée à une colonne ou à chaque ligne.
- pivot_table() : restructurer les données en tableau croisé dynamique, comme dans un tableur.
# Appliquer une fonction à une colonne
df["montant_arrondi"] = df["montant"].apply(lambda x: round(x))
# Tableau croisé : somme des montants par pays
pivot = df.pivot_table(values="montant", index="pays", aggfunc="sum")
print(pivot)Pandas ne fait pas d'intelligence artificielle. Mais sans lui, ton IA ne fera rien de bon : la qualité d'un modèle dépend d'abord de la qualité des données qu'on lui fournit. Nettoyer, explorer, transformer — c'est là que se joue l'essentiel d'un projet, et c'est désormais à ta portée.
Nettoyer les chaînes de caractères
Les colonnes de texte cachent souvent des incohérences : espaces superflus, casses mélangées, formats hétérogènes. Pandas propose une syntaxe dédiée, accessible via l'attribut .str, pour nettoyer ces chaînes en masse.
# Exemple : une colonne avec des espaces et des casses incohérentes
df["client"] = df["client"].str.strip() # retire les espaces en début/fin
df["client"] = df["client"].str.title() # "alice dupont" -> "Alice Dupont"
df["pays"] = df["pays"].str.upper() # "fr" -> "FR"
# Remplacer une valeur par une autre
df["pays"] = df["pays"].str.replace("FRANCE", "FR")L'attribut .str s'applique à toute la colonne d'un coup, sans boucle. C'est bien plus rapide et plus lisible qu'une boucle for, et c'est le réflexe à adopter dès que tu touches à du texte. Attention toutefois : si la colonne contient des valeurs manquantes, .str les transforme en NaN proprement, ce qui est un comportement bienvenu.
Visualiser rapidement ses données
Avant d'aller plus loin, un coup d'oeil visuel vaut souvent mille statistiques. Pandas s'appuie sur matplotlib pour tracer des graphiques directement depuis un DataFrame, sans passer par un outil externe.
import matplotlib.pyplot as plt
# Un histogramme de la colonne montant
df["montant"].hist(bins=20)
plt.title("Répartition des montants")
plt.show()
# Un graphique en barres du chiffre d'affaires par pays
df.groupby("pays")["montant"].sum().plot(kind="bar")
plt.title("Chiffre d'affaires par pays")
plt.show()Ces deux lignes te donnent, en quelques secondes, une intuition que les nombres seuls ne donnent pas : où se concentrent les montants, quel pays domine, si la distribution est déséquilibrée. C'est le complément naturel de describe(), et ça fait partie du réflexe d'exploration systématique.
Les bonnes pratiques à retenir
Pour finir, quelques réflexes qui te feront gagner du temps sur le long terme :
- Explore toujours avant de corriger : shape, info, describe, head et value_counts d'abord.
- Travaille sur une copie : df_clean = df.copy() évite de modifier accidentellement la source.
- Documente tes choix de nettoyage en commentaire : la médiane plutôt que la moyenne, pourquoi cette suppression.
- Vérifie le résultat après chaque étape : un print de la forme et des premières lignes suffit souvent.
Ces règles semblent triviales, mais c'est en les appliquant systématiquement que tu éviteras les erreurs les plus coûteuses — celles qui se glissent silencieusement dans les données et faussent tout le reste en aval.
Conclusion
En une vingtaine de minutes, tu as chargé un jeu de données, exploré sa structure, appris à sélectionner lignes et colonnes, corrigé les valeurs manquantes et les doublons, normalisé les types, créé des colonnes dérivées, agrégé par groupe, fusionné des tables et exporté le résultat. C'est le cycle de vie complet de la donnée, et il tient dans une poignée de méthodes que tu vas réutiliser toute ta carrière.
Le meilleur réflexe pour progresser : prends un vrai fichier CSV (il y en a partout, des données publiques aux exports de tes outils), et applique la même recette — shape, info, describe, nettoyage, transformation, export. Tu verras que les problèmes réels sont toujours une variante de ceux qu'on vient de traiter.
Un dernier mot sur la montée en charge : Pandas tient confortablement jusqu'à quelques millions de lignes en mémoire. Au-delà, tu pourras te tourner vers des outils complémentaires comme Polars ou Dask, qui reprennent la même philosophie avec une exécution plus performante. Mais la logique que tu viens d'acquérir restera identique : c'est elle, la vraie compétence.






