Python Data Science : les 9 étapes clés pour passer de zéro à opérationnel

Python Data Science : l'essentiel en un article — vrai code, schémas et étapes concrètes, extraits d'un cours de 36 leçons.

Python Data Science : les 9 étapes clés pour passer de zéro à opérationnel

Tout le monde peut apprendre Python Data Science — à condition de suivre les étapes dans le bon ordre. On a condensé un cours complet de 36 leçons en un parcours clair, avec les extraits de code les plus utiles.

tl;dr
  • Introduction et Installation
  • NumPy essentiel
  • Pandas Series et DataFrames
  • Lecture et ecriture de donnees
  • Nettoyage de donnees
~$ cat ./parcours.md # Python Data Science — 10 chapitres
01
Introduction et Installation
→ Présentation du cours→ Installer l’environnement Data Science+ 1 autres leçons
02
NumPy essentiel
→ Arrays NumPy vs listes Python→ Opérations vectorisées+ 1 autres leçons
03
Pandas Series et DataFrames
→ Créer une Series→ Créer un DataFrame+ 2 autres leçons
04
Lecture et écriture de données
→ CSV avec read_csv et to_csv→ Excel, JSON et Parquet+ 1 autres leçons
05
Nettoyage de données
→ Valeurs manquantes (NaN)→ Doublons et incohérences+ 1 autres leçons
06
Agrégations et groupby
→ groupby de base→ agg sur plusieurs colonnes+ 1 autres leçons
07
Jointures et fusions
→ merge comme en SQL→ concat vs merge+ 1 autres leçons
08
Visualisations rapides
→ plot Pandas direct→ Matplotlib pour DS+ 1 autres leçons
🏁
Projet final (+ 2 chapitres en chemin)
→ Tu repars avec un projet concret et démontrable

Doublons et incohérences

NOTEObjectif — Apprendre à repérer et éliminer les doublons exacts ou approximatifs, et à uniformiser les chaînes de caractères (majuscules, espaces, accents) qui empoisonnent silencieusement vos analyses.

Objectifs pédagogiques

TIPÀ l’issue de ce module — Vous saurez détecter des lignes dupliquées, décider quelle copie garder, normaliser des colonnes texte, et corriger les fameuses incohérences du type « Paris », « paris », « PARIS ».

Pourquoi les doublons sont dangereux

Un doublon, c’est une même réalité comptée deux fois. Conséquences : chiffres d’affaires gonflés, moyennes biaisées, modèles surentraînés. Un doublon peut venir d’un import répété, d’une jointure mal faite, d’un formulaire soumis deux fois…

WARNINGHistoire vraie — Une entreprise calculait son CA à partir d’un fichier Excel concaténé chaque mois… sans dropper les doublons. Son CA était surestimé de 12 %% depuis deux ans.

Détecter les doublons

output
import pandas as pd

df = pd.DataFrame({
    "id": [1, 2, 3, 2, 4, 1],
    "nom": ["Alice", "Bob", "Chloe", "Bob", "David", "Alice"],
    "ville": ["Paris", "Lyon", "Nice", "Lyon", "Lille", "Paris"]
})

# Masque booléen : True si la ligne est un doublon
df.duplicated()

# Combien de doublons au total ?
df.duplicated().sum()

# Afficher uniquement les doublons
df[df.duplicated()]

# Doublons en se basant uniquement sur certaines colonnes
df.duplicated(subset=["id"])
df.duplicated(subset=["nom", "ville"])
NOTEPar défautduplicated() marque True à partir de la 2ème occurrence. Le premier exemplaire est considéré comme l’original.

Supprimer les doublons

output
# Garder la première occurrence (par défaut)
df.drop_duplicates()

# Garder la dernière occurrence
df.drop_duplicates(keep="last")

# Supprimer toutes les occurrences dupliquées
df.drop_duplicates(keep=False)

# Sur certaines colonnes seulement (utile si une col est un timestamp)
df.drop_duplicates(subset=["id"])

# Inplace pour modifier le DataFrame directement
df.drop_duplicates(inplace=True)
TIPChoisir keep"first" pour garder le plus ancien enregistrement, "last" pour le plus récent (souvent le bon choix si la donnée a été mise à jour), False pour tout supprimer et enquêter.

Le piège des doublons approximatifs

« Paris » et « paris » sont différents pour Pandas, même si pour vous c’est la même ville. Avant de chercher les doublons, normalisez.

output
df = pd.DataFrame({
    "email": ["Alice@MAIL.com", " alice@mail.com ", "bob@mail.com"],
    "ville": ["Paris", "PARIS", "Lyon"]
})

# Normaliser les emails (espaces + minuscules)
df["email"] = df["email"].str.strip().str.lower()
df["ville"] = df["ville"].str.strip().str.title()

# MAINTENANT on peut détecter les vrais doublons
df.duplicated(subset=["email"])
print(df)

Boîte à outils .str

L’accesseur .str donne accès à toutes les méthodes de chaînes Python, vectorisées :

output
s = pd.Series(["  Alice DUPONT  ", "bob martin", "CHLOE.LEROY"])

s.str.strip()                  # enleve espaces
s.str.lower()                  # minuscules
s.str.upper()                  # MAJUSCULES
s.str.title()                  # Mot À Mot Capitalisé
s.str.replace(".", " ")      # remplacement
s.str.contains("alice", case=False)  # filtre
s.str.startswith("A")
s.str.len()                    # nombre de caractères
s.str.split(" ", expand=True)  # séparer en colonnes
NOTEAstuce accents — Pour normaliser les accents (é → e), passez par unicodedata ou la bibliothèque unidecode : df["ville"].apply(unidecode).

Incohérences catégorielles

Souvent on saisit la même catégorie de façons différentes : « H », « Homme », « M », « Masculin »… Pandas y voit 4 catégories distinctes.

output
df = pd.DataFrame({
    "sexe": ["H", "Homme", "M", "Masculin", "F", "Femme", "f"]
})

# Avant : voir les valeurs uniques
print(df["sexe"].value_counts())

# Stratégie : dictionnaire de mapping
mapping = {
    "H": "Homme", "M": "Homme", "Masculin": "Homme",
    "F": "Femme", "f": "Femme", "Femme": "Femme"
}
df["sexe"] = df["sexe"].map(mapping)

print(df["sexe"].value_counts())
TIPRéflexe d’or — Avant toute analyse catégorielle, exécutez df["col"].value_counts(). Les incohérences sautent immédiatement aux yeux.

Mini-projet : nettoyer une base employés

output
import pandas as pd

df = pd.DataFrame({
    "id":    [1, 2, 3, 2, 4, 5],
    "nom":   ["Alice", " Bob ", "Chloe", "BOB", "David", "emma"],
    "poste": ["Dev", "DEV", "PM", "dev", "Pm", "Designer"],
    "ville": ["Paris", "paris", "Lyon", "PARIS", "Lille", "Lyon"]
})

# 1. Normaliser les chaînes
for col in ["nom", "poste", "ville"]:
    df[col] = df[col].str.strip().str.title()

# 2. Détecter les doublons sur id
print("Doublons :", df.duplicated(subset=["id"]).sum())

# 3. Garder le dernier enregistrement (le plus à jour)
df = df.drop_duplicates(subset=["id"], keep="last")

# 4. Vérifier
print(df)
print(df["poste"].value_counts())

Valeurs manquantes (NaN)

NOTEObjectif — Comprendre ce qu’est une valeur manquante en Pandas, comment la détecter, comment l’analyser, et choisir la bonne stratégie : supprimer ou imputer (remplir). Aucune analyse propre ne se fait sans cette étape.

Objectifs pédagogiques

TIPÀ l’issue de ce module — Vous saurez compter les NaN par colonne, supprimer les lignes incomplètes, ou les remplir intelligemment (moyenne, médiane, valeur fixe, propagation). Vous saurez aussi quand chaque stratégie est appropriée.

Qu’est-ce qu’un NaN ?

NaN = « Not a Number ». C’est la façon dont Pandas (hérité de NumPy) représente une valeur manquante dans une colonne numérique. Pour les dates, c’est NaT ; pour les objets génériques, None. Pandas les traite tous trois de manière unifiée via isnull().

output
import pandas as pd
import numpy as np

df = pd.DataFrame({
    "nom": ["Alice", "Bob", None, "David"],
    "age": [30, np.nan, 25, 35],
    "date": pd.to_datetime(["2025-01-01", None, "2025-01-03", "2025-01-04"])
})
print(df)
WARNINGPiège classiqueNaN != NaN en Python pur (c’est volontaire). Donc x == np.nan est toujours faux. Utilisez toujours isnull() ou isna() pour tester.

Détecter les valeurs manquantes

output
# Masque booléen cellule par cellule
df.isnull()                # True si NaN
df.notna()                 # inverse

# Compter par colonne
df.isnull().sum()

# Pourcentage de NaN par colonne
(df.isnull().sum() / len(df) * 100).round(2)

# Total dans tout le DataFrame
df.isnull().sum().sum()

# Lignes ayant au moins un NaN
df[df.isnull().any(axis=1)]
TIPRéflexe d’or — Dès qu’un dataset arrive, exécutez df.isnull().sum(). C’est en 2 secondes votre tableau de bord de la qualité des données.

Stratégie 1 — Supprimer (dropna)

Quand les NaN sont rares ou que l’analyse exige des données complètes :

output
# Supprimer toute ligne contenant au moins 1 NaN
df.dropna()

# Supprimer seulement si TOUTES les valeurs sont NaN
df.dropna(how="all")

# Supprimer si NaN dans une colonne précise
df.dropna(subset=["age"])

# Garder une ligne si elle a au moins 3 valeurs non-NaN
df.dropna(thresh=3)

# Supprimer une colonne entière trop incomplète
df.dropna(axis=1, thresh=100)   # colonnes < 100 valeurs supprimées
WARNINGQuand éviter dropna ? — Sur un dataset de 100 000 lignes où chaque colonne a quelques %% de NaN, dropna peut tout supprimer ! Vérifiez avant : df.dropna().shape vs df.shape.

Stratégie 2 — Remplir (fillna)

Avec une valeur fixe

output
df["age"].fillna(0)
df["ville"].fillna("Inconnu")

# Sur tout le DataFrame avec un dict par colonne
df.fillna({"age": 0, "ville": "Inconnu", "salaire": 2000})

Avec une statistique de la colonne

output
df["age"].fillna(df["age"].mean())     # moyenne
df["age"].fillna(df["age"].median())   # médiane (robuste)
df["ville"].fillna(df["ville"].mode()[0])  # valeur la plus fréquente

Par propagation (utile pour séries temporelles)

output
# Remplir avec la valeur précédente (forward fill)
df["prix"].ffill()

# Avec la valeur suivante (backward fill)
df["prix"].bfill()

# Limiter le nombre de remplissages consécutifs
df["prix"].ffill(limit=3)

Types de données et conversion

NOTEObjectif — Comprendre les types de Pandas (int, float, object, datetime, category, bool), pourquoi ils comptent énormément, et comment convertir proprement sans crasher sur des valeurs sales.

Objectifs pédagogiques

TIPÀ l’issue de ce module — Vous saurez inspecter dtypes, convertir en nombre/date/catégorie, utiliser errors="coerce" pour les valeurs sales, et réduire l’empreinte mémoire d’un DataFrame en passant objectcategory.

Pourquoi le type importe

Un « 42 » stocké comme texte (object) ne peut pas être sommé, ni comparé numériquement. Une date stockée comme texte ne permet pas .dt.year. Mauvais type = bugs silencieux ou perte de fonctionnalités.

output
import pandas as pd

df = pd.DataFrame({
    "prix": ["12.50", "8.99", "15.00"],
    "date": ["2025-01-01", "2025-02-15", "2025-03-10"]
})

print(df.dtypes)
# prix    object  <-- texte !
# date    object  <-- texte !

df["prix"].sum()   # concaténe « 12.508.9915.00 » !
WARNINGPiège classiqueobject = « n’importe quoi », le plus souvent du texte. Si vous voyez object sur une colonne censée être numérique, il y a un problème à résoudre avant toute analyse.

Les types Pandas en bref

DtypeUsageExemple
int64EntierAges, quantités
float64RéelPrix, températures
boolVrai/FauxActif, payant
objectGénérique (souvent str)Noms, emails
datetime64[ns]Date/heureCommande, naissance
timedelta64DuréeDifférence entre 2 dates
categoryCatégories répétéesSexe, ville, statut

Conversion avec astype

output
# Conversion simple, échoue si une valeur ne convient pas
df["age"] = df["age"].astype(int)
df["prix"] = df["prix"].astype(float)
df["actif"] = df["actif"].astype(bool)
df["sexe"] = df["sexe"].astype("category")

# Sur plusieurs colonnes à la fois
df = df.astype({"age": int, "prix": float, "ville": "category"})
WARNINGLimiteastype(int) plante dès qu’une valeur ne se convertit pas (ex : "12 EUR"). Pour gérer ces cas, utilisez pd.to_numeric.

pd.to_numeric — le tolérant

output
s = pd.Series(["12.5", "8.99", "oops", "15"])

# Mode strict : crash si une valeur n’est pas numérique
pd.to_numeric(s)   # ValueError

# Mode tolérant : valeurs sales -> NaN
pd.to_numeric(s, errors="coerce")
# 0    12.50
# 1     8.99
# 2      NaN  <-- "oops" devient NaN
# 3    15.00

# Choisir le sous-type pour gagner de la mémoire
pd.to_numeric(s, errors="coerce", downcast="float")
pd.to_numeric(s, errors="coerce", downcast="integer")
TIPWorkflow propreerrors="coerce" → comptez les NaN générés → décidez quoi faire (imputer, supprimer, signaler).

pd.to_datetime — toutes les dates

output
# Reconnaît la plupart des formats automatiquement
pd.to_datetime(["2025-01-15", "15/01/2025", "Jan 15, 2025"])

# Format explicite (plus rapide, plus sûr)
pd.to_datetime(df["date"], format="%%d/%%m/%%Y")

# Tolérant aux valeurs sales
pd.to_datetime(df["date"], errors="coerce")

# Une fois en datetime, on accède aux composants
df["date"] = pd.to_datetime(df["date"])
df["annee"]    = df["date"].dt.year
df["mois"]     = df["date"].dt.month
df["jour_sem"] = df["date"].dt.day_name()
NOTEFormat explicite — Sur de gros volumes, spécifier format= peut multiplier la vitesse par 100. Pandas n’a plus à deviner.

Type category : la magie mémoire

Pour une colonne « ville » répétée 1 million de fois, stocker chaque chaîne est une perte de place. category stocke chaque valeur unique une fois, et référence un index entier.

output
import pandas as pd

df = pd.DataFrame({
    "ville": ["Paris", "Lyon", "Paris"] * 1_000_000
})

print(df.memory_usage(deep=True).sum() / 1e6, "Mo")
# Environ 200 Mo

df["ville"] = df["ville"].astype("category")
print(df.memory_usage(deep=True).sum() / 1e6, "Mo")
# Environ 8 Mo -- gain x25 !
TIPQuand utiliser category ? — Quand le nombre de valeurs uniques est petit par rapport au nombre total de lignes (typiquement < 5 %%). Sinon, peu de gain.

Mini-projet : nettoyer une exportation comptable

output
import pandas as pd

df = pd.DataFrame({
    "montant":    ["125,50", "99,00", "N/D", "42,75"],
    "date":       ["01/03/2025", "02/03/2025", "oops", "04/03/2025"],
    "categorie":  ["Achat", "Vente", "Achat", "Vente"],
    "paye":       ["Oui", "Non", "Oui", "Oui"]
})

# 1. Montant : virgule -> point, puis numérique
df["montant"] = df["montant"].str.replace(",", ".")
df["montant"] = pd.to_numeric(df["montant"], errors="coerce")

# 2. Date au format jj/mm/aaaa
df["date"] = pd.to_datetime(df["date"], format="%%d/%%m/%%Y", errors="coerce")

# 3. Categorie -> type category
df["categorie"] = df["categorie"].astype("category")

# 4. Oui/Non -> bool
df["paye"] = df["paye"].map({"Oui": True, "Non": False})

print(df.dtypes)
print(df)
va-plus-loin

Cet article couvre les extraits les plus utiles — le cours complet Python Data Science (11 chapitres, 36 leçons, exercices corrigés et projet final) t'emmène jusqu'au bout.

./acceder-au-cours-complet cours gratuit : Maîtriser Claude Code

FAQ

Combien de temps pour apprendre Python Data Science ?
Avec une progression structurée (11 chapitres, 36 leçons courtes et pratiques), on atteint un niveau opérationnel en quelques semaines à raison de 30 à 60 minutes par jour. L'important est de pratiquer chaque notion immédiatement.
Faut-il des prérequis ?
Des bases en informatique suffisent. Si tu sais utiliser un terminal et lire du code simple, tu es prêt.
Par où commencer concrètement ?
Reproduis les commandes de cet article, puis suis le cours complet Python Data Science : il enchaîne les 36 leçons dans l'ordre, avec exercices et projet final.

📬 Tu veux recevoir ce type de guide chaque semaine ? Abonne-toi gratuitement — code réel, zéro blabla.