Python
pour la Data Science
De zéro à l’analyse de données réelles
Licence 2–3 / BTS — Informatique & Data Science
Volume horaire : 30h CM · 30h TP · 20h Projet
Prérequis : Algorithmique de base, notions de maths/statistiques
Outils : Python 3.x · Jupyter Notebook · NumPy · Pandas · Matplotlib ·
Scikit-learn
Ibrahima SY
Enseignant-Chercheur
2025–2026
Cours complet avec travaux pratiques sur données réelles
Table des matières
I Fondamentaux Python 6
1 Introduction à Python pour la Data Science 7
1.1 Bienvenue dans le monde de la Data Science . . . . . . . . . . . . . . . . . 7
1.2 Pourquoi Python pour la Data Science ? . . . . . . . . . . . . . . . . . . . 7
1.3 Installation de l’environnement de travail . . . . . . . . . . . . . . . . . . 8
1.3.1 Option recommandée : Anaconda . . . . . . . . . . . . . . . . . . 8
1.3.2 Option alternative : Python + pip . . . . . . . . . . . . . . . . . . . 9
1.3.3 Vérifier que tout est installé . . . . . . . . . . . . . . . . . . . . . 9
1.4 Jupyter Notebook : votre laboratoire numérique . . . . . . . . . . . . . . . 10
1.4.1 Comprendre les cellules . . . . . . . . . . . . . . . . . . . . . . . 10
1.4.2 Les raccourcis indispensables . . . . . . . . . . . . . . . . . . . . 11
1.4.3 Les commandes magiques . . . . . . . . . . . . . . . . . . . . . . 11
1.5 Premier programme Python . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.5.1 Variables : des étiquettes sur des boîtes . . . . . . . . . . . . . . . 12
1.5.2 L’instruction print() et les f-strings . . . . . . . . . . . . . . . . . . 13
1.5.3 Le dataset fil rouge : [Link] . . . . . . . . . . . . . . . . . . 13
1.6 Récapitulatif . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2 Bases du langage Python 16
2.1 Les types de données fondamentaux . . . . . . . . . . . . . . . . . . . . . 16
2.1.1 Les entiers (int) et décimaux (float) . . . . . . . . . . . . . . . . 16
2.1.2 Les chaînes de caractères (str) . . . . . . . . . . . . . . . . . . . 17
2.1.3 Les booléens (bool) . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.1.4 Conversions de types . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.2 Structures de contrôle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.2.1 La condition : if / elif / else . . . . . . . . . . . . . . . . . 19
2.2.2 La boucle for : répéter sur une séquence . . . . . . . . . . . . . . 20
2.2.3 La boucle while : répéter tant qu’une condition est vraie . . . . . . 21
2.3 Les fonctions : encapsuler et réutiliser . . . . . . . . . . . . . . . . . . . . 21
2.3.1 Définir et appeler une fonction . . . . . . . . . . . . . . . . . . . . 22
2.3.2 Paramètres par défaut et arguments nommés . . . . . . . . . . . . . 22
2.3.3 Les fonctions lambda : des fonctions express . . . . . . . . . . . . 23
2.3.4 La portée des variables : local vs global . . . . . . . . . . . . . . . 24
2.4 Récapitulatif . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
2
TABLE DES MATIÈRES 3
3 Structures de données Python 26
3.1 La liste : la séquence universelle . . . . . . . . . . . . . . . . . . . . . . . 26
3.1.1 Créer une liste et accéder aux éléments . . . . . . . . . . . . . . . 26
3.1.2 Modifier une liste . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
3.2 Le tuple : la séquence immuable . . . . . . . . . . . . . . . . . . . . . . . 28
3.3 Le dictionnaire : les paires clé-valeur . . . . . . . . . . . . . . . . . . . . . 29
3.3.1 Cas pratique : compter des fréquences . . . . . . . . . . . . . . . . 30
3.4 L’ensemble : l’unicité garantie . . . . . . . . . . . . . . . . . . . . . . . . 30
3.5 Les compréhensions : construire des collections élégamment . . . . . . . . 31
3.6 Quelle structure choisir ? . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
3.7 Récapitulatif . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
II Bibliothèques Data Science 33
4 NumPy — Le moteur du calcul scientifique 34
4.1 Pourquoi NumPy ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
4.2 Créer des tableaux NumPy . . . . . . . . . . . . . . . . . . . . . . . . . . 35
4.3 Opérations vectorisées : travailler sans boucles . . . . . . . . . . . . . . . . 36
4.4 Indexation avancée . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
4.4.1 Indexation classique et slicing . . . . . . . . . . . . . . . . . . . . 37
4.4.2 Indexation booléenne : filtrer avec des masques . . . . . . . . . . . 37
4.5 Broadcasting : des opérations intelligentes entre formes différentes . . . . . 38
4.6 Récapitulatif . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
5 Pandas — L’outil central du Data Scientist 40
5.1 Les deux structures de base . . . . . . . . . . . . . . . . . . . . . . . . . . 40
5.1.1 La Series : une colonne avec étiquettes . . . . . . . . . . . . . . . . 40
5.1.2 Le DataFrame : la table de données . . . . . . . . . . . . . . . . . 41
5.2 Lire et écrire des fichiers . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
5.2.1 Accéder aux données . . . . . . . . . . . . . . . . . . . . . . . . . 42
5.3 Nettoyage des données . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
5.3.1 Valeurs manquantes (NaN) . . . . . . . . . . . . . . . . . . . . . . 43
5.3.2 Doublons et types de données . . . . . . . . . . . . . . . . . . . . 44
5.4 Filtrer, trier et transformer . . . . . . . . . . . . . . . . . . . . . . . . . . 44
5.5 Groupby : agréger des données par groupe . . . . . . . . . . . . . . . . . . 45
5.6 Récapitulatif . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
6 Analyse Exploratoire des Données (EDA) 47
6.1 Les statistiques descriptives : résumer un dataset en quelques chiffres . . . . 47
6.1.1 La commande describe() : votre premier réflexe . . . . . . . . . 47
6.1.2 Interpréter les indicateurs clés . . . . . . . . . . . . . . . . . . . . 48
6.2 Analyser les distributions . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
6.3 La corrélation : mesurer les relations entre variables . . . . . . . . . . . . . 49
6.4 Détection et traitement des outliers . . . . . . . . . . . . . . . . . . . . . . 51
6.4.1 Méthode 1 : la règle de l’IQR . . . . . . . . . . . . . . . . . . . . 51
6.4.2 Méthode 2 : le Z-score . . . . . . . . . . . . . . . . . . . . . . . . 51
6.4.3 Que faire avec les outliers ? . . . . . . . . . . . . . . . . . . . . . . 52
6.5 Récapitulatif . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
Python pour la Data Science — Ibrahima SY
4 TABLE DES MATIÈRES
7 Visualisation de données 53
7.1 Matplotlib : la fondation de la visualisation Python . . . . . . . . . . . . . 53
7.1.1 La métaphore de la toile et du cadre . . . . . . . . . . . . . . . . . 53
7.1.2 Créer un graphique : la syntaxe de base . . . . . . . . . . . . . . . 54
7.2 Les graphiques fondamentaux . . . . . . . . . . . . . . . . . . . . . . . . 55
7.2.1 L’histogramme — voir la forme d’une distribution . . . . . . . . . 55
7.2.2 Le diagramme en barres — comparer des catégories . . . . . . . . 56
7.2.3 Le scatter plot — révéler les relations entre variables . . . . . . . . 57
7.2.4 Le boxplot — comparer les distributions en un coup d’œil . . . . . 58
7.3 Seaborn : la visualisation statistique simplifiée . . . . . . . . . . . . . . . . 59
7.4 Quel graphique pour quelle question ? . . . . . . . . . . . . . . . . . . . . 61
7.5 Récapitulatif . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
III Vers le Machine Learning 63
8 Préparation des données pour le Machine Learning 64
8.1 La séparation train / test : la règle fondamentale . . . . . . . . . . . . . . . 64
8.2 La mise à l’échelle : pourquoi et comment . . . . . . . . . . . . . . . . . . 66
8.3 L’encodage des variables catégorielles . . . . . . . . . . . . . . . . . . . . 68
8.3.1 L’encodage ordinal (Label Encoding) . . . . . . . . . . . . . . . . 68
8.3.2 L’encodage One-Hot (variables nominales) . . . . . . . . . . . . . 69
8.4 Le pipeline de préparation complet . . . . . . . . . . . . . . . . . . . . . . 69
8.5 Récapitulatif . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
9 Introduction aux pipelines de Data Science 72
9.1 Le workflow d’un projet Data Science . . . . . . . . . . . . . . . . . . . . 72
9.2 Scikit-learn : l’interface unifiée . . . . . . . . . . . . . . . . . . . . . . . . 73
9.3 Le Pipeline Scikit-learn : enchaîner les étapes en toute sécurité . . . . . . . 74
9.4 La validation croisée : une évaluation robuste . . . . . . . . . . . . . . . . 76
9.5 Comparer plusieurs modèles équitablement . . . . . . . . . . . . . . . . . 77
9.6 Récapitulatif . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
10 Projet Final — Étude de cas complète 79
10.1 La structure d’un notebook professionnel . . . . . . . . . . . . . . . . . . 79
10.2 Étape 1 — Chargement et exploration initiale . . . . . . . . . . . . . . . . 80
10.3 Étape 2 — Nettoyage systématique . . . . . . . . . . . . . . . . . . . . . . 81
10.4 Étape 3 — Feature Engineering . . . . . . . . . . . . . . . . . . . . . . . . 82
10.5 Étape 4 — Analyse exploratoire et visualisations . . . . . . . . . . . . . . 83
10.6 Étape 5 — Modélisation et évaluation . . . . . . . . . . . . . . . . . . . . 85
10.7 Étape 6 — Conclusions et recommandations . . . . . . . . . . . . . . . . . 86
10.8 Les critères d’un livrable professionnel . . . . . . . . . . . . . . . . . . . . 87
10.9 Récapitulatif du cours . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
IV Travaux Pratiques 89
TP 1 — Installation et premier notebook 90
Python pour la Data Science — Ibrahima SY
TABLE DES MATIÈRES 5
TP 2 — Bases du langage Python 93
TP 3 — Structures de données 96
TP 4 — NumPy 99
TP 5 — Pandas 102
TP 6 — EDA 105
TP 7 — Visualisation 108
TP 8 — Préparation ML 111
TP 9 — Pipelines et modèle 114
TP 10 — Projet Final 117
Python pour la Data Science — Ibrahima SY
Première partie
Fondamentaux Python
6
Chapitre 1
Introduction à Python pour la Data Science
◎ Objectifs du chapitre
— Comprendre pourquoi Python domine la Data Science
— Installer et configurer un environnement de travail
— Maîtriser l’interface Jupyter Notebook
— Écrire et exécuter un premier programme Python
1.1 Bienvenue dans le monde de la Data Science
Imaginez la situation suivante : le directeur d’un hôpital vous remet un fichier Excel conte-
nant les données de 50 000 patients — âge, diagnostic, durée d’hospitalisation, médicaments
prescrits, coût de séjour. Il vous pose une question simple : quels sont les facteurs qui font
qu’un patient est réhospitalisé dans les 30 jours ?
Répondre à cette question à la main prendrait des mois. Avec Python et les bons outils,
cela prend quelques heures. C’est précisément la promesse de la Data Science : transformer
des données brutes en décisions éclairées.
BOOK Concept : Data Science
La Data Science (science des données) est une discipline qui combine la statistique,
l’informatique et la connaissance métier pour extraire de la valeur à partir de données.
Elle s’articule autour d’un cycle : collecter les données → les nettoyer → les explorer
→ construire des modèles → interpréter les résultats → prendre des décisions.
Python est aujourd’hui l’outil central de cette discipline. Mais pourquoi Python plutôt
qu’un autre langage ?
1.2 Pourquoi Python pour la Data Science ?
En 2005, la question ne se posait même pas : les statisticiens utilisaient R, les ingénieurs
utilisaient MATLAB, les informaticiens utilisaient Java ou C++. Python était un petit langage
de scripting sympathique, pas vraiment sérieux.
Tout a changé avec l’émergence des bibliothèques NumPy (2006), Pandas (2008), scikit-
learn (2007) et ensuite TensorFlow et PyTorch. Ces bibliothèques ont transformé Python en
7
8 CHAPITRE 1. INTRODUCTION À PYTHON POUR LA DATA SCIENCE
un environnement de calcul scientifique de classe mondiale. Aujourd’hui, en 2024, voici la
réalité :
— Google, Meta, Netflix, Spotify utilisent Python pour leurs algorithmes de recommanda-
tion et d’analyse.
— Les chercheurs en médecine l’utilisent pour analyser des images médicales et prédire
les maladies.
— Les banques l’utilisent pour la détection de fraudes.
— Les gouvernements l’utilisent pour modéliser la propagation des épidémies (COVID-19).
Atout de Python Ce que cela signifie concrètement
Syntaxe lisible On lit le code comme du pseudo-code en anglais
Bibliothèques DS NumPy, Pandas, Matplotlib, Scikit-learn, PyTorch…
Communauté Des millions de développeurs, des réponses partout
Polyvalence Data Science + web + automatisation + IoT
Gratuit Pas de licence, utilisable partout
Jupyter Notebook Mélange code, graphiques et texte dans un même document
INFO-CIRCLE Note
Python vs R : R est excellent pour la statistique pure et la publication scientifique.
Python est meilleur pour la mise en production, l’automatisation et le Machine Lear-
ning. En entreprise, Python est dominant (85% des offres d’emploi en Data Science
demandent Python). Ce cours vous prépare à cette réalité.
1.3 Installation de l’environnement de travail
Avant d’écrire la moindre ligne de code, il faut installer les bons outils. Pensez à cette
étape comme à la préparation d’un laboratoire avant une expérience : sans le bon équipement,
rien ne fonctionne.
1.3.1 Option recommandée : Anaconda
Anaconda est une distribution Python spécialement conçue pour la Data Science. En une
seule installation, vous obtenez :
— Python 3.x
— Plus de 250 bibliothèques scientifiques préinstallées
— Jupyter Notebook
— Un gestionnaire d’environnements (conda)
Python pour la Data Science — Ibrahima SY
1.3. INSTALLATION DE L’ENVIRONNEMENT DE TRAVAIL 9
1 # Après avoir télécharg é Anaconda sur anaconda .com :
2
3 # Créer un environnement isolé pour ce cours (très recommand é)
4 conda create -n python_ds python =3.11
5 conda activate python_ds
6
7 # Installer les biblioth èques du cours
8 conda install numpy pandas matplotlib seaborn scikit - learn jupyter
9
10 # Lancer Jupyter Notebook
11 jupyter notebook
LIGHTBULB Astuce
Pourquoi créer un environnement isolé ? Imaginez que votre ordinateur est un ap-
partement et que chaque projet est une pièce. Un environnement virtuel (conda env)
isole chaque projet avec ses propres bibliothèques. Ainsi, deux projets peuvent utiliser
des versions différentes de Pandas sans se gêner. C’est une pratique professionnelle
indispensable.
1.3.2 Option alternative : Python + pip
1 # Télé charger Python 3.x sur python .org
2 # Puis dans le terminal :
3 pip install numpy pandas matplotlib seaborn scikit - learn jupyter
4
5 # Créer un environnement virtuel Python pur
6 python -m venv env_ds
7 source env_ds /bin/ activate # Linux /Mac
8 env_ds \ Scripts \ activate # Windows
9
10 # Lancer Jupyter
11 jupyter notebook
1.3.3 Vérifier que tout est installé
La première chose à faire après l’installation est de vérifier que tout fonctionne correcte-
ment. Ouvrez Jupyter et exécutez ce code :
1 # Ce script vérifie que toutes les biblioth èques sont bien
install ées
2 import sys
3 import numpy as np
4 import pandas as pd
5 import matplotlib
6 import seaborn as sns
7 import sklearn
8
Python pour la Data Science — Ibrahima SY
10 CHAPITRE 1. INTRODUCTION À PYTHON POUR LA DATA SCIENCE
9 # Afficher les versions install ées
10 bibliotheques = {
11 " Python ": sys. version . split () [0] ,
12 " NumPy": np. __version__ ,
13 " Pandas ": pd. __version__ ,
14 " Matplotlib ": matplotlib . __version__ ,
15 " Seaborn ": sns. __version__ ,
16 "Scikit -learn ": sklearn . __version__ ,
17 }
18
19 print ("=== Vé rification de l'installation ===")
20 for nom , version in bibliotheques . items ():
21 print (f" {nom :15} : { version }")
22 print ("\nTout est prêt !")
1 === Vé rification de l'installation ===
2 Python : 3.11.5
3 NumPy : 1.26.0
4 Pandas : 2.1.1
5 Matplotlib : 3.8.0
6 Seaborn : 0.13.0
7 Scikit - learn : 1.3.1
8
9 Tout est prêt !
Si vous voyez ce résultat (les versions exactes peuvent différer), votre environnement est
correctement configuré. Passons à l’outil avec lequel vous travaillerez tous les jours.
1.4 Jupyter Notebook : votre laboratoire numérique
BOOK Concept : Jupyter Notebook
Un Jupyter Notebook (extension .ipynb) est un document interactif qui mélange
dans un même fichier :
— Du code Python exécutable
— Du texte formaté (titres, listes, formules mathématiques)
— Des graphiques et tableaux générés par le code
Pensez à lui comme à un cahier de laboratoire électronique : vous expérimentez, vous
notez vos observations, vous produisez des graphiques — tout dans le même endroit.
1.4.1 Comprendre les cellules
Un notebook est composé de cellules. Il en existe deux types principaux :
Python pour la Data Science — Ibrahima SY
1.4. JUPYTER NOTEBOOK : VOTRE LABORATOIRE NUMÉRIQUE 11
Type Contenu Utilisation
Cellule Code Python exécutable Calculs, graphiques, manipulations
Cellule Markdown Texte formaté Titres, explications, formules
Pour exécuter une cellule : appuyez sur Shift + Entrée. Le résultat s’affiche immédia-
tement en dessous.
1.4.2 Les raccourcis indispensables
Jupyter a deux modes : le mode édition (vous tapez dans une cellule, le bord est vert)
et le mode commande (vous naviguez entre cellules, le bord est bleu). Appuyez sur Échap
pour passer en mode commande.
Raccourci Mode Action
Shift + Entrée Édition Exécuter et aller à la suivante
Ctrl + Entrée Édition Exécuter sans bouger
A Commande Insérer une cellule au-dessus
B Commande Insérer une cellule en-dessous
DD Commande Supprimer la cellule
M Commande Convertir en cellule Markdown
Y Commande Convertir en cellule Code
Ctrl + S Édition Sauvegarder le notebook
0, 0 Commande Redémarrer le noyau
1.4.3 Les commandes magiques
Jupyter dispose de commandes spéciales préfixées par % (une ligne) ou %% (toute la cellule).
Ce sont des outils très pratiques pour la Data Science :
1 # Afficher les graphiques directement dans le notebook
2 # ( toujours mettre cette ligne en premier )
3 % matplotlib inline
4
5 # Mesurer le temps d'exé cution d'une cellule compl ète
6 %% time
7 import pandas as pd
8 df = pd. read_csv (" donnees .csv")
9 print (df. shape )
10
11 # Mesurer avec pré cision le temps d'une expression
12 % timeit sum(range (1000) )
13
14 # Lister toutes les variables actuellement en mémoire
Python pour la Data Science — Ibrahima SY
12 CHAPITRE 1. INTRODUCTION À PYTHON POUR LA DATA SCIENCE
15 %whos
16
17 # Exé cuter un fichier Python externe
18 %run mon_script .py
19
20 # Afficher la documentation d'une fonction
21 ?pd. read_csv
INFO-CIRCLE Note
Bonne habitude numéro 1 : Commencez toujours votre notebook avec une cellule
qui importe toutes vos bibliothèques et définit les paramètres globaux. Cela garantit que
votre code reste reproductible — un autre Data Scientist peut reprendre votre notebook
et le réexécuter de A à Z.
1.5 Premier programme Python
1.5.1 Variables : des étiquettes sur des boîtes
La meilleure façon de comprendre ce qu’est une variable, c’est l’analogie de la boîte :
imaginez des boîtes numérotées dans un entrepôt. Chaque boîte a une étiquette (le nom de la
variable) et contient une valeur. En Python, vous créez une boîte simplement en lui donnant
un nom et une valeur :
1 # Créer une variable , c'est comme coller une é tiquette sur une
boîte
2 nom = " Ibrahima " # la boîte "nom" contient la valeur " Ibrahima "
3 age = 23 # la boîte "age" contient le nombre 23
4 taille = 1.75 # la boîte " taille " contient 1.75
5
6 # On peut lire le contenu de la boîte en é crivant son nom
7 print (nom) # affiche : Ibrahima
8 print (age) # affiche : 23
9
10 # On peut aussi changer le contenu de la boîte
11 age = 24 # l'é tiquette "age" pointe maintenant vers 24
12 print (age) # affiche : 24
13
14 # Python dé tecte automatiquement le type du contenu
15 # Inutile d'é crire " String nom" ou "int age" comme en Java ou C
INFO-CIRCLE Note
Python est dynamiquement typé. Contrairement à C, Java ou C++, Python ne vous
demande pas de déclarer le type d’une variable avant de l’utiliser. Il le détecte auto-
matiquement. Cela rend le code beaucoup plus rapide à écrire — précieux en Data
Science où vous explorez les données en temps réel.
Python pour la Data Science — Ibrahima SY
1.5. PREMIER PROGRAMME PYTHON 13
1.5.2 L’instruction print() et les f-strings
print() est la fonction qui affiche du texte à l’écran. C’est votre première alliée pour
vérifier ce que contient une variable.
1 # print () simple : affiche la valeur brute
2 print (" Bonjour !") # affiche : Bonjour !
3 print (42) # affiche : 42
4 print (3.14) # affiche : 3.14
5
6 # f- string : la façon moderne et élégante d'inclure des variables
7 # dans du texte . Notez le f devant les guillemets .
8 prenom = "Fatou "
9 age = 21
10 note = 17.5
11
12 # La variable est placée entre accolades {}
13 print (f" Bonjour { prenom }, tu as {age} ans.")
14 # affiche : Bonjour Fatou , tu as 21 ans.
15
16 # On peut faire des calculs directement dans les accolades
17 print (f"Dans 5 ans , { prenom } aura {age + 5} ans.")
18 # affiche : Dans 5 ans , Fatou aura 26 ans.
19
20 # Formatage des nombres dé cimaux : :.2f = 2 chiffres après la
virgule
21 print (f"Note obtenue : {note :.2f}/20")
22 # affiche : Note obtenue : 17.50/20
23
24 # Formatage des entiers : :3d = espace pour 3 chiffres
25 for i in range (1, 6):
26 print (f"Rang {i:2d} : {i*i:4d}")
1 Rang 1 : 1
2 Rang 2 : 4
3 Rang 3 : 9
4 Rang 4 : 16
5 Rang 5 : 25
1.5.3 Le dataset fil rouge : [Link]
Tout au long de ce cours, nous allons analyser un même jeu de données — un dataset
fictif d’étudiants d’une université sénégalaise. Ce dataset contient des informations sur 100
étudiants : leurs notes, leur filière, leur âge, et s’ils ont été admis au semestre suivant.
Travailler sur un dataset commun à travers tous les chapitres vous permettra de voir
comment chaque outil apporte une nouvelle couche de compréhension sur les mêmes données.
Python pour la Data Science — Ibrahima SY
14 CHAPITRE 1. INTRODUCTION À PYTHON POUR LA DATA SCIENCE
Colonne Type Description
nom Texte Nom de famille
prenom Texte Prénom
age Entier Âge en années
filiere Texte Filière (Info, Maths, Physique, Chimie)
note_maths Décimal Note en mathématiques (0–20)
note_info Décimal Note en informatique (0–20)
note_anglais Décimal Note en anglais (0–20)
admis Booléen Admis au semestre suivant (True/False)
Voici un avant-goût de ce que vous saurez faire à la fin du cours :
1 # Ce code résume ce que vous maî triserez en fin de cours .
2 # Ne vous inqui étez pas si vous ne le comprenez pas encore .
3 import pandas as pd
4 import matplotlib . pyplot as plt
5 import seaborn as sns
6
7 # Charger les données en une ligne
8 df = pd. read_csv (" eleves .csv")
9
10 # Calculer la moyenne de chaque é tudiant
11 df[" moyenne "] = df [[" note_maths ", " note_info ",
" note_anglais "]]. mean(axis =1)
12
13 # Comparer les filières visuellement
14 plt. figure ( figsize =(10 , 5))
15 sns. boxplot (data=df , x=" filiere ", y=" moyenne ", palette ="muted ")
16 [Link] (" Distribution des moyennes par filière", fontsize =14)
17 plt. xlabel ("Filière")
18 plt. ylabel (" Moyenne générale / 20")
19 plt. axhline (10 , color ="red", linestyle ="--", label ="Seuil
d'admission ")
20 plt. legend ()
21 plt. tight_layout ()
22 [Link] ()
23
24 print (f"\ nTaux d'admission global : {df[' admis ']. mean () :.1%} ")
25 print (df. groupby (" filiere ")[" admis "]. mean (). apply ( lambda x:
f"{x:.1%} "))
Python pour la Data Science — Ibrahima SY
1.6. RÉCAPITULATIF 15
1.6 Récapitulatif
Key À retenir
Ce que vous devez retenir de ce chapitre
— La Data Science transforme des données brutes en décisions. Python en est l’outil
central.
— Anaconda est la distribution la plus simple pour débuter. Créez toujours un envi-
ronnement virtuel dédié.
— Jupyter Notebook est votre espace de travail quotidien : il mélange code, texte et
graphiques.
— Une variable est une étiquette qui pointe vers une valeur en mémoire. Python détecte
le type automatiquement.
— print() affiche des valeurs ; les f-strings (f"texte {variable}") les intègrent
élégamment.
— Tout au long du cours, nous analyserons le dataset [Link].
Python pour la Data Science — Ibrahima SY
Chapitre 2
Bases du langage Python
◎ Objectifs du chapitre
— Maîtriser les types fondamentaux : int, float, str, bool
— Écrire des structures de contrôle : if/elif/else, for, while
— Définir et appeler des fonctions réutilisables
— Comprendre la portée des variables (local vs global)
Apprendre un langage de programmation ressemble à apprendre une langue humaine. On
commence par le vocabulaire (les types de données), puis la grammaire (les structures de
contrôle), puis on compose des phrases complexes (les fonctions). À la fin de ce chapitre,
vous pourrez écrire de vrais programmes pour analyser des données.
2.1 Les types de données fondamentaux
En Python, toute donnée a un type. Le type détermine ce qu’on peut faire avec la donnée :
on peut additionner deux nombres, concaténer deux chaînes, mais on ne peut pas additionner
un nombre à une chaîne. Comprendre les types est fondamental pour éviter les erreurs.
BOOK Concept : Type de données
Le type d’une donnée définit sa nature et les opérations permises. Python détecte le
type automatiquement : c’est le typage dynamique. On peut toujours vérifier le type
d’une variable avec la fonction type().
2.1.1 Les entiers (int) et décimaux (float)
1 # int : nombres entiers , sans limite de taille en Python
2 nb_etudiants = 35 # un entier classique
3 annee = 2024 # une année
4 tres_grand = 10**100 # 10 à la puissance 100 : Python gère !
5
6 # float : nombres avec une partie dé cimale ( virgule flottante )
7 note_moyenne = 14.75 # une note
8 pi = 3.14159 # valeur approch ée de pi
16
2.1. LES TYPES DE DONNÉES FONDAMENTAUX 17
9 taux_reussite = 0.83 # 83% exprim é en décimal
10
11 # Opé rations arithm é tiques
12 print (10 + 3) # 13 -> addition
13 print (10 - 3) # 7 -> soustraction
14 print (10 * 3) # 30 -> multiplication
15 print (10 / 3) # 3.333... -> division ( TOUJOURS un float en
Python 3 !)
16 print (10 // 3) # 3 -> division entière ( quotient )
17 print (10 % 3) # 1 -> modulo (reste de la division )
18 print (2 ** 8) # 256 -> puissance
Exclamation-Triangle Attention
La division est toujours décimale en Python 3. 7 / 2 donne 3.5, pas 3. Si vous
voulez la division entière, utilisez 7 // 2 (résultat : 3). Ce changement entre Python 2
et Python 3 a causé beaucoup de bugs chez ceux qui n’en étaient pas conscients.
2.1.2 Les chaînes de caractères (str)
Une chaîne de caractères représente du texte. En Python, on peut la créer avec des guille-
mets simples ('...'), doubles ("...") ou triples ("""...""") pour les textes multiligne.
1 # Trois façons de créer une chaîne
2 prenom = " Ibrahima " # guillemets doubles
3 nom = 'SY ' # guillemets simples (é quivalent )
4 adresse = """ Rue 12,
5 Dakar , Sénégal """ # chaîne multiligne (avec triple
guillemets )
6
7 # Opé rations sur les chaînes
8 print (" Ibrahima " + " " + "SY") # concat é nation : " Ibrahima SY"
9 print ("ha" * 3) # répé tition : " hahaha "
10 print (len(" Ibrahima ")) # longueur : 8
11
12 # Mé thodes de transformation
13 print (" ibrahima ". upper ()) # " IBRAHIMA "
14 print (" IBRAHIMA ". lower ()) # " ibrahima "
15 print (" bonjour ". strip ()) # " bonjour " ( supprime les
espaces )
16 print ("Dakar ,Thiès, Ziguinchor ". split (",")) # ['Dakar ', 'Thiès',
'Ziguinchor ']
17 print (" Bonjour ". replace ("Bon", "Bel")) # " Beljour "
18
19 # Accéder à un caract ère par sa position (l'index commence à 0)
20 mot = " Python "
21 print (mot [0]) # 'P' -> premier caract ère
22 print (mot [1]) # 'y' -> deuxi ème
23 print (mot [ -1]) # 'n' -> dernier (index négatif : compte depuis
la fin)
Python pour la Data Science — Ibrahima SY
18 CHAPITRE 2. BASES DU LANGAGE PYTHON
24 print (mot [0:3]) # 'Pyt ' -> slice : du rang 0 ( inclus ) au rang 3
( exclus )
INFO-CIRCLE Note
Les chaînes sont immuables. Une fois créée, on ne peut pas modifier un caractère
individuel (mot[0] = 'J' provoque une erreur). Pour modifier une chaîne, on en crée
toujours une nouvelle. C’est important à savoir pour comprendre les erreurs que vous
rencontrerez.
2.1.3 Les booléens (bool)
Un booléen est la réponse à une question oui/non. Il n’a que deux valeurs : True (vrai) ou
False (faux). Les booléens sont omniprésents en programmation : ils contrôlent les conditions
et les boucles.
1 # Deux seules valeurs possibles (avec une majuscule obligatoire )
2 admis = True
3 redouble = False
4
5 # Les opé rateurs de comparaison produisent des booléens
6 note = 14.5
7 print (note >= 10) # True -> 14.5 est -il supérieur ou égal à
10 ?
8 print (note == 20) # False -> est -il égal à 20 ?
9 print (note != 10) # True -> est -il différent de 10 ?
10 print (note < 8) # False -> est -il inférieur à 8 ?
11
12 # Opé rateurs logiques : combiner plusieurs conditions
13 a_une_bonne_note = note >= 14
14 est_majeur = 21 >= 18
15
16 # and : les DEUX conditions doivent être vraies
17 print ( a_une_bonne_note and est_majeur ) # True
18
19 # or : au MOINS UNE condition doit être vraie
20 print (note < 5 or note > 18) # False
21
22 # not : inverser une condition
23 print (not admis ) # False
24
25 # Astuce Python : on peut chaîner les comparaisons (très lisible )
26 print (10 <= note <= 16) # True -> é quivalent à note >= 10 AND
note <= 16
2.1.4 Conversions de types
Souvent, on reçoit des données dans un type non désiré. Un fichier CSV contient tout en
texte (str), mais on veut des nombres. Les fonctions de conversion permettent de passer d’un
type à l’autre.
Python pour la Data Science — Ibrahima SY
2.2. STRUCTURES DE CONTRÔLE 19
1 # Scé nario ré aliste : données lues depuis un fichier CSV
2 note_texte = "16.5" # lu depuis un CSV : c'est un str
3 age_texte = "22"
4
5 # Convertir pour pouvoir faire des calculs
6 note = float( note_texte ) # "16.5" -> 16.5
7 age = int( age_texte ) # "22" -> 22
8
9 print (note + 2) # 18.5 ( possible maintenant )
10 print (type(note)) # <class 'float '>
11
12 # Convertir un nombre en texte (pour l'affichage )
13 note_str = str(note) # 16.5 -> "16.5"
14 message = "Note : " + note_str # Concat é nation possible maintenant
15
16 # ATTENTION : int () tronque , il ne arrondit pas !
17 print (int (15.9) ) # 15, pas 16
18 print (int (15.1) ) # 15
19 # Pour arrondir : utiliser round ()
20 print (round (15.9) ) # 16
21 print (round (15.5) ) # 16
22 print (round (14.67 , 1)) # 14.7 ( arrondi à 1 dé cimale )
2.2 Structures de contrôle
Un programme qui ne fait que des calculs en ligne droite est très limité. Les structures de
contrôle permettent au programme de décider (avec if) ou de répéter (avec for et while).
Ce sont les engrenages qui donnent vie à un programme.
2.2.1 La condition : if / elif / else
La structure if permet d’exécuter du code seulement si une condition est vraie. C’est
l’équivalent de “si... alors... sinon...” en langage naturel.
1 # Exemple : calculer la mention d'un é tudiant
2 note = 15.5
3
4 # Structure compl ète avec plusieurs cas
5 if note >= 16:
6 # Ce bloc s'exécute uniquement si note >= 16
7 mention = "Très Bien"
8 elif note >= 14:
9 # "elif" = "sinon , si" -> testé seulement si le premier if
est faux
10 mention = "Bien"
11 elif note >= 12:
12 mention = " Assez Bien"
13 elif note >= 10:
14 mention = " Passable "
Python pour la Data Science — Ibrahima SY
20 CHAPITRE 2. BASES DU LANGAGE PYTHON
15 else:
16 # "else" = "sinon " -> s'exécute si AUCUNE condition
précédente n'est vraie
17 mention = " Ajourn é"
18
19 print (f"Note : {note }/20 -> Mention : { mention }")
20 # affiche : Note : 15.5/20 -> Mention : Bien
Exclamation-Triangle Attention
L’indentation n’est pas optionnelle en Python ! En Python, l’indentation (le décalage
du texte avec des espaces) définit les blocs de code. Tout ce qui appartient à un if
doit être indenté d’un niveau (4 espaces par convention). Une indentation incorrecte
provoque une IndentationError. C’est différent de langages comme C ou Java qui
utilisent des accolades {}.
2.2.2 La boucle for : répéter sur une séquence
La boucle for parcourt une séquence (liste, chaîne, intervalle...) et exécute le même bloc
de code pour chaque élément. C’est l’outil idéal quand vous savez à l’avance sur quoi vous
itérez.
1 notes = [14.5 , 8.0 , 17.5 , 12.0 , 11.5 , 9.0]
2
3 # Parcourir les élé ments directement
4 print ("=== Ré sultats des é tudiants ===")
5 for note in notes :
6 if note >= 10:
7 statut = "Admis "
8 else:
9 statut = " Ajourn é"
10 print (f" {note :5.1f}/20 -> { statut }")
11
12 # Souvent on a besoin de l'index en plus de la valeur ->
enumerate ()
13 print ("\n=== Avec numé rotation ===")
14 for numero , note in enumerate (notes , start =1):
15 # enumerate () retourne (index , valeur ). start =1 commence à 1
au lieu de 0
16 print (f" Étudiant { numero } : {note }/20")
17
18 # Répéter N fois -> range ()
19 print ("\n=== Table de multiplication de 3 ===")
20 for i in range (1, 11): # range (1, 11) génère 1, 2, 3, ... , 10
21 print (f" 3 × {i:2d} = {3*i:2d}")
Python pour la Data Science — Ibrahima SY
2.3. LES FONCTIONS : ENCAPSULER ET RÉUTILISER 21
INFO-CIRCLE Note
range(debut, fin, pas) génère une suite de nombres.
— range(5) : 0, 1, 2, 3, 4 (fin exclue)
— range(1, 6) : 1, 2, 3, 4, 5
— range(0, 10, 2) : 0, 2, 4, 6, 8 (pas de 2)
— range(10, 0, -1) : 10, 9, 8, ..., 1 (décroissant)
2.2.3 La boucle while : répéter tant qu’une condition est vraie
La boucle while est utilisée quand on ne sait pas à l’avance combien de fois on va répéter.
Elle continue tant que la condition est vraie.
1 # Cas concret : chercher le premier é tudiant admis dans une liste
2 notes = [7.5 , 8.0 , 5.5 , 11.0 , 14.5 , 9.5]
3
4 i = 0
5 while i < len( notes ) and notes [i] < 10:
6 # Cette boucle continue tant que l'é tudiant actuel n'est pas
admis
7 print (f" Étudiant {i+1} non admis : {notes [i]}/20 ")
8 i += 1 # TRÈS IMPORTANT : ne pas oublier d'incré menter !
9
10 if i < len( notes ):
11 print (f"\ nPremier é tudiant admis : é tudiant {i+1} avec
{notes [i]}/20 ")
12 else:
13 print ("\ nAucun é tudiant admis dans la liste !")
14
15 # On peut sortir d'une boucle prématur ément avec "break "
16 for note in notes :
17 if note >= 10:
18 print (f"Premi ère note admissible trouv ée : {note}")
19 break # on sort de la boucle immé diatement
Exclamation-Triangle Attention
La boucle infinie, le piège classique du débutant. Si vous oubliez de modifier la
variable de condition dans un while, la boucle ne s’arrêtera jamais. Dans Jupyter, ap-
puyez sur le bouton Stop (carré noir) ou I, I (deux fois la lettre I en mode commande)
pour interrompre le noyau.
2.3 Les fonctions : encapsuler et réutiliser
Imaginez que vous devez calculer la mention de 100 étudiants. Sans fonction, vous
répéteriez le même bloc if/elif/else 100 fois. Avec une fonction, vous l’écrivez une fois
et l’appelez 100 fois.
Python pour la Data Science — Ibrahima SY
22 CHAPITRE 2. BASES DU LANGAGE PYTHON
BOOK Concept : Fonction
Une fonction est un bloc de code nommé, réutilisable, qui prend des paramètres en
entrée et retourne une valeur. Les fonctions rendent le code plus lisible, plus court et
plus facile à corriger (si on trouve un bug, on le corrige un seul endroit).
2.3.1 Définir et appeler une fonction
1 # Définir une fonction avec "def"
2 def calculer_mention (note):
3 """
4 Retourne la mention correspondant à une note sur 20.
5
6 Cette description entre triple guillemets s'appelle une
" docstring ".
7 Elle documente la fonction et appara ît quand on tape
? calculer_mention
8 dans Jupyter .
9
10 Args:
11 note (float ): la note de l'é tudiant entre 0 et 20
12 Returns :
13 str: la mention correspondante
14 """
15 if note >= 16:
16 return "Très Bien"
17 elif note >= 14:
18 return "Bien"
19 elif note >= 12:
20 return "Assez Bien"
21 elif note >= 10:
22 return " Passable "
23 else:
24 return " Ajourn é"
25
26 # Appeler la fonction : on écrit son nom suivi de ()
27 mention = calculer_mention (15.5) # la valeur 15.5 est passée en
param ètre
28 print ( mention ) # affiche : Bien
29
30 # Appliquer la fonction à chaque é tudiant
31 notes = [14.5 , 8.0 , 17.5 , 12.0 , 11.5]
32 for note in notes :
33 print (f" {note }/20 -> { calculer_mention (note)}")
2.3.2 Paramètres par défaut et arguments nommés
Un grand avantage des fonctions Python est la possibilité de définir des valeurs par
défaut pour certains paramètres. Si l’utilisateur ne fournit pas ce paramètre, la valeur par
défaut est utilisée.
Python pour la Data Science — Ibrahima SY
2.3. LES FONCTIONS : ENCAPSULER ET RÉUTILISER 23
1 def calculer_statistiques (notes , arrondi =2, ignorer_nuls =True):
2 """
3 Calcule les statistiques de base d'une liste de notes .
4
5 Le paramètre 'arrondi ' a une valeur par défaut de 2.
6 Le paramètre 'ignorer_nuls ' a une valeur par défaut de True.
7 Ces deux paramètres sont OPTIONNELS à l'appel .
8 """
9 # Filtrer les valeurs None si demand é
10 if ignorer_nuls :
11 notes_valides = [n for n in notes if n is not None]
12 else:
13 notes_valides = notes
14
15 if len( notes_valides ) == 0:
16 return None
17
18 n = len( notes_valides )
19 total = sum( notes_valides )
20 moyenne = round ( total / n, arrondi )
21
22 return {
23 "n": n,
24 " moyenne ": moyenne ,
25 "min": min( notes_valides ),
26 "max": max( notes_valides )
27 }
28
29 notes = [14.5 , 8.0 , None , 17.5 , 12.0 , None , 11.5]
30
31 # Appel simple : paramètres par défaut utilis és
32 stats = calculer_statistiques ( notes )
33 print (stats )
34 # {'n ': 5, 'moyenne ': 12.7 , 'min ': 8.0 , 'max ': 17.5}
35
36 # Appel avec argument nommé : ordre libre , très lisible
37 stats2 = calculer_statistiques (notes , arrondi =0,
ignorer_nuls =True)
38 print ( stats2 )
39 # {'n ': 5, 'moyenne ': 13.0 , 'min ': 8.0 , 'max ': 17.5}
2.3.3 Les fonctions lambda : des fonctions express
Pour des opérations simples sur une seule ligne, Python offre les fonctions lambda —
des fonctions anonymes rapides à écrire.
1 # Forme : lambda paramètre(s): expression
2 doubler = lambda x: x * 2
3 print ( doubler (5)) # 10
4
Python pour la Data Science — Ibrahima SY
24 CHAPITRE 2. BASES DU LANGAGE PYTHON
5 ajouter = lambda x, y: x + y
6 print ( ajouter (3, 4)) # 7
7
8 # En Data Science , les lambdas sont surtout utiles pour trier
9 # ou filtrer des données sans définir une fonction compl ète.
10
11 notes = [14.5 , 8.0 , 17.5 , 12.0 , 11.5]
12
13 # Trier par ordre dé croissant (key = critère de tri)
14 triees = sorted (notes , key= lambda n: -n)
15 print ( triees ) # [17.5 , 14.5 , 12.0 , 11.5 , 8.0]
16
17 # Filtrer : garder uniquement les admis
18 admis = list( filter ( lambda n: n >= 10, notes ))
19 print (admis ) # [14.5 , 17.5 , 12.0 , 11.5]
20
21 # Appliquer une transformation : bonus de +1 (max 20)
22 avec_bonus = list(map( lambda n: min(n + 1, 20) , notes ))
23 print ( avec_bonus ) # [15.5 , 9.0 , 18.5 , 13.0 , 12.5]
2.3.4 La portée des variables : local vs global
1 # Variable dé finie EN DEHORS d'une fonction = globale
2 seuil_admission = 10 # variable globale
3
4 def est_admis (note):
5 # Variable dé finie À L'INTÉRIEUR d'une fonction = locale
6 # Elle n'existe que le temps de l'exé cution de la fonction
7 resultat = note >= seuil_admission # peut LIRE une
variable globale
8 return resultat
9
10 print ( est_admis (15)) # True
11 print ( est_admis (8)) # False
12 # print ( resultat ) # ERREUR ! " resultat " n'existe plus ici
13
14 # Pour MODIFIER une variable globale depuis une fonction ->
mot -clé global
15 # ( usage rare , à éviter géné ralement )
16 compteur = 0
17 def incrementer ():
18 global compteur # je veux modifier la variable GLOBALE
compteur
19 compteur += 1
20
21 incrementer ()
22 incrementer ()
23 print ( compteur ) # 2
Python pour la Data Science — Ibrahima SY
2.4. RÉCAPITULATIF 25
STAR Bonne pratique
Bonne pratique : évitez les variables globales. Les variables globales rendent le
code difficile à comprendre et à déboguer. Préférez passer les données en paramètre et
retourner le résultat. Une fonction qui ne modifie pas d’état extérieur est dite pure —
c’est la forme la plus fiable et testable.
2.4 Récapitulatif
Key À retenir
Ce que vous devez retenir
— 4 types de base : int (entier), float (décimal), str (texte), bool (vrai/faux).
— Conversion : int(), float(), str(). Attention : int(15.9) = 15, pas 16.
— Conditions : if/elif/else. L’indentation est obligatoire.
— Boucle for : quand on connaît la séquence à parcourir. enumerate() pour avoir
l’index, range() pour répéter N fois.
— Boucle while : quand on ne connaît pas le nombre d’itérations. Toujours s’assurer
que la condition devient fausse un jour.
— Fonctions : def nom(param, option=valeur): puis return. La docstring
(triple guillemets) documente la fonction.
— Lambda : fonctions anonymes pour des expressions simples.
— Portée : les variables locales n’existent que dans leur fonction.
Python pour la Data Science — Ibrahima SY
Chapitre 3
Structures de données Python
◎ Objectifs du chapitre
— Utiliser les quatre conteneurs natifs : liste, tuple, dictionnaire, ensemble
— Maîtriser l’indexation, le slicing et les méthodes essentielles
— Écrire des compréhensions de liste et de dictionnaire
— Choisir la bonne structure selon le contexte
En Data Science, on ne travaille presque jamais avec une seule valeur. On manipule des
collections : les 10 000 notes d’une promotion, les 500 lignes d’un fichier CSV, les paires
(étudiant, note) d’un registre. Python offre quatre structures natives pour organiser ces données,
chacune adaptée à un usage précis.
3.1 La liste : la séquence universelle
BOOK Concept : Liste (list)
Une liste est une collection ordonnée et modifiable d’éléments. Elle est délimitée par
des crochets []. Les éléments peuvent être de types différents et la liste peut grandir
ou rétrécir librement.
La liste est la structure la plus utilisée en Python. Pensez à elle comme à un tableau
d’affichage numéroté : chaque position a un numéro (son index), les éléments peuvent être
modifiés, ajoutés ou retirés.
3.1.1 Créer une liste et accéder aux éléments
1 # Créer une liste
2 notes = [14.5 , 8.0 , 17.5 , 12.0 , 11.5 , 9.0]
3 eleves = [" Fatou", " Ibrahima ", "Amina ", " Seydou "]
4 vide = [] # liste vide (on peut l'alimenter plus tard)
5
6 # Accès par index : TOUJOURS commence à 0 en Python
7 print (notes [0]) # 14.5 -> le PREMIER élément (index 0)
8 print (notes [1]) # 8.0 -> le deuxi ème (index 1)
9 print (notes [ -1]) # 9.0 -> le DERNIER élément (index -1)
26
3.1. LA LISTE : LA SÉQUENCE UNIVERSELLE 27
10 print (notes [ -2]) # 11.5 -> l'avant - dernier (index -2)
11
12 # Slicing [ debut:fin:pas] : extraire une partie de la liste
13 # ATTENTION : le fin est EXCLU (comme range )
14 print (notes [1:4]) # [8.0 , 17.5 , 12.0] -> index 1, 2, 3
15 print (notes [:3]) # [14.5 , 8.0 , 17.5] -> du début jusqu 'à
l'index 2
16 print (notes [3:]) # [12.0 , 11.5 , 9.0] -> de l'index 3 jusqu 'à
la fin
17 print (notes [::2]) # [14.5 , 17.5 , 11.5] -> un élément sur deux
18 print (notes [:: -1]) # [9.0 , 11.5 , 12.0 , 17.5 , 8.0 , 14.5] ->
liste invers ée
INFO-CIRCLE Note
Pourquoi les index commencent à 0 ? C’est une convention historique héritée du
langage C. L’index représente la distance par rapport au premier élément. Le premier
élément est à distance 0 du début, le second à distance 1, etc. Presque tous les langages
de programmation modernes utilisent cette convention.
3.1.2 Modifier une liste
1 notes = [14.5 , 8.0 , 17.5 , 12.0 , 11.5]
2
3 # Modifier un élément existant
4 notes [1] = 10.5 # l'é tudiant 2 avait 8.0 , maintenant 10.5
5 print (notes )
6
7 # Ajouter des élé ments
8 notes. append (16.0) # ajouter À LA FIN (le plus courant )
9 notes. insert (0, 5.0) # insérer À L'INDICE 0 (tous les autres
dé calent )
10
11 # Supprimer des élé ments
12 notes. remove (5.0) # supprimer par VALEUR (premi ère
occurrence )
13 del notes [0] # supprimer par INDICE
14 derniere = notes .pop () # retirer et récupérer le DERNIER élément
15
16 # Opé rations courantes
17 print (len( notes )) # nombre d'éléments
18 print (sum( notes )) # somme de tous les éléments
19 print (min( notes )) # minimum
20 print (max( notes )) # maximum
21
22 # Trier
23 [Link] () # trier sur place ( modifie la liste )
24 [Link]( reverse =True) # tri dé croissant
25 notes_triees = sorted ( notes) # retourne une NOUVELLE liste triée
( original intact )
Python pour la Data Science — Ibrahima SY
28 CHAPITRE 3. STRUCTURES DE DONNÉES PYTHON
26
27 # Chercher
28 print (notes . count (14.5) ) # combien de fois 14.5 appara ît
29 print (14.5 in notes ) # True si 14.5 est dans la liste
30 print (notes . index (14.5) ) # index de la premi ère occurrence
de 14.5
3.2 Le tuple : la séquence immuable
BOOK Concept : Tuple (tuple)
Un tuple est une collection ordonnée et immuable (non modifiable). Il est délimité
par des parenthèses (). Une fois créé, on ne peut ni ajouter, ni retirer, ni modifier ses
éléments.
Si les listes sont des tableaux d’affichage modifiables, les tuples sont des plaques gravées
dans le marbre. On les utilise pour des données qui ne doivent pas changer : coordonnées
GPS, configuration d’un système, résultats d’une mesure, ou pour retourner plusieurs valeurs
depuis une fonction.
1 # Créer un tuple ( parenth èses optionnelles mais recommand ées)
2 coordonnees_dakar = (14.7167 , -17.4677) # latitude , longitude
3 couleur_rouge = (255 , 0, 0) # RGB
4 point = 3, 4 # tuple sans
parenth èses (dé conseill é)
5
6 # Accès identique aux listes
7 print ( coordonnees_dakar [0]) # 14.7167 ( latitude )
8 print ( coordonnees_dakar [ -1]) # -17.4677 ( longitude )
9
10 # DÉSTRUCTURATION ( unpacking ) : la fonctionnalit é star du tuple
11 lat , lon = coordonnees_dakar
12 print (f" Latitude : {lat}, Longitude : {lon}")
13
14 # Très utile pour les fonctions qui retournent plusieurs valeurs
15 def min_max_moyenne ( valeurs ):
16 """ Retourne minimum , maximum et moyenne d'une liste ."""
17 return min( valeurs ), max( valeurs ), sum( valeurs )/len( valeurs )
18
19 mi , ma , moy = min_max_moyenne ([14.5 , 8.0 , 17.5 , 12.0])
20 print (f"Min ={ mi}, Max ={ ma}, Moy ={ moy :.2f}")
21
22 # On peut ignorer certaines valeurs avec _ ( convention )
23 _, maximum , _ = min_max_moyenne ([14.5 , 8.0 , 17.5])
24 print (f"Le maximum est { maximum }")
25
26 # IMMUABILITÉ : tentative de modification -> erreur
27 # coordonnees_dakar [0] = 0.0 # TypeError : 'tuple ' object does
not support item assignment
Python pour la Data Science — Ibrahima SY
3.3. LE DICTIONNAIRE : LES PAIRES CLÉ-VALEUR 29
3.3 Le dictionnaire : les paires clé-valeur
BOOK Concept : Dictionnaire (dict)
Un dictionnaire stocke des paires clé → valeur. Il est délimité par des accolades {}.
L’accès se fait par la clé (pas par l’index). Les clés doivent être uniques et immuables
(str, int, tuple).
Imaginez un vrai dictionnaire : pour trouver la définition d’un mot, vous cherchez le mot
(la clé), pas sa position dans le livre. Les dictionnaires Python fonctionnent exactement pareil.
C’est la structure idéale pour représenter un objet du monde réel — un étudiant, un produit,
une transaction.
1 # Repré senter un é tudiant avec un dictionnaire
2 etudiant = {
3 "nom": "SY",
4 " prenom ": " Ibrahima ",
5 "age": 22,
6 " filiere ": " Informatique ",
7 " notes": { # valeur imbriqu ée : un
autre dictionnaire !
8 " maths": 15.5 ,
9 "info": 17.0 ,
10 " anglais ": 13.0
11 }
12 }
13
14 # Accéder à une valeur par sa clé
15 print ( etudiant ["nom"]) # "SY"
16 print ( etudiant ["notes "]["info"]) # 17.0 (accès imbriqu é)
17
18 # Accès SÉCURISÉ avec .get () : pas d'erreur si la clé n'existe pas
19 print ( etudiant .get("email ")) # None (au lieu de
KeyError )
20 print ( etudiant .get("email ", "Non renseign é")) # valeur par défaut
21
22 # Ajouter ou modifier
23 etudiant ["email "] = " ibrahima@univ .sn" # ajouter une nouvelle
clé
24 etudiant ["age"] = 23 # modifier une valeur
existante
25
26 # Supprimer
27 del etudiant ["email "] # supprimer par clé
28 age = etudiant .pop("age") # supprimer et
récupérer la valeur
29
30 # Itérer sur les éléments
31 print ("\n--- Informations de l'é tudiant ---")
32 for cle , valeur in etudiant . items ():
33 print (f" {cle :10} : { valeur }")
Python pour la Data Science — Ibrahima SY
30 CHAPITRE 3. STRUCTURES DE DONNÉES PYTHON
34
35 # Vé rifier si une clé existe
36 print ("nom" in etudiant ) # True
37 print (" email" in etudiant ) # False (on vient de la supprimer )
3.3.1 Cas pratique : compter des fréquences
Un usage classique et puissant des dictionnaires en Data Science est de compter des
occurrences.
1 filieres = ["Info", " Maths", "Info", " Physique ", "Info", "Maths ",
" Chimie ", "Info"]
2
3 # Méthode classique : .get () avec valeur par défaut 0
4 comptage = {}
5 for filiere in filieres :
6 # Si la clé existe , on retourne sa valeur . Sinon , on retourne
0.
7 comptage [ filiere ] = comptage .get(filiere , 0) + 1
8
9 print ( comptage )
10 # {'Info ': 4, 'Maths ': 2, 'Physique ': 1, 'Chimie ': 1}
11
12 # Méthode professionnelle : Counter ( biblioth èque standard )
13 from collections import Counter
14 resultat = Counter ( filieres )
15 print ( resultat ) # Counter ({' Info ': 4, 'Maths ': 2, 'Physique ':
1, 'Chimie ': 1})
16 print ( resultat . most_common (2)) # les 2 filieres les plus
fré quentes
3.4 L’ensemble : l’unicité garantie
BOOK Concept : Ensemble (set)
Un ensemble est une collection non ordonnée et sans doublons. Il est délimité par des
accolades {} (sans clés). Il est particulièrement efficace pour les tests d’appartenance
et les opérations ensemblistes (union, intersection, différence).
1 # Créer un ensemble (les doublons sont automatiquement supprim és)
2 filieres = {"Info", " Maths", " Physique ", "Info", "Maths "}
3 print ( filieres ) # {'Info ', 'Maths ', 'Physique '} -> ordre non
garanti
4
5 # Supprimer les doublons d'une liste
6 notes_avec_doublons = [14.5 , 8.0 , 14.5 , 17.5 , 8.0 , 12.0]
7 notes_uniques = sorted (set( notes_avec_doublons ))
8 print ( notes_uniques ) # [8.0 , 12.0 , 14.5 , 17.5]
Python pour la Data Science — Ibrahima SY
3.5. LES COMPRÉHENSIONS : CONSTRUIRE DES COLLECTIONS ÉLÉGAMMENT 31
10 # Test d'appartenance : TRÈS RAPIDE (temps constant , O(1))
11 grands_etablissements = {"UCAD", "UADB", "UGB", " USSEIN "}
12 ecole = "UADB"
13 if ecole in grands_etablissements :
14 print (f"{ ecole} est une grande universit é.")
15
16 # Opé rations ensemblistes
17 admis = {"Fatou ", " Ibrahima ", "Amina ", " Cheikh "}
18 boursiers = {" Ibrahima ", " Seydou ", "Amina "}
19
20 print (" Admis ET boursiers :", admis & boursiers ) # intersection
21 print (" Admis OU boursiers :", admis | boursiers ) # union
22 print (" Admis mais PAS boursiers :", admis - boursiers ) #
différence
3.5 Les compréhensions : construire des collections élégam-
ment
BOOK Concept : Compréhension de liste
Une compréhension de liste est une syntaxe concise pour construire une liste en une
seule ligne, à partir d’une séquence existante. Elle est plus lisible et 30 à 50% plus
rapide qu’une boucle for avec .append().
Les compréhensions sont l’une des caractéristiques les plus élégantes de Python. Au lieu
d’écrire une boucle pour remplir une liste progressivement, vous décrivez directement le
résultat que vous voulez.
1 notes = [14.5 , 8.0 , 17.5 , 12.0 , 9.5 , 11.0]
2
3 # �� SANS compr é hension ( boucle classique ) ���������������������
4 avec_bonus_loop = []
5 for note in notes :
6 avec_bonus_loop . append (min(note + 1, 20))
7
8 # �� AVEC compr é hension (même résultat , une seule ligne ) �������
9 avec_bonus = [min(n + 1, 20) for n in notes ]
10 # Se lit : "pour chaque n dans notes , calcule min(n+1, 20)"
11
12 print ( avec_bonus ) # [15.5 , 9.0 , 18.5 , 13.0 , 10.5 , 12.0]
13
14 # �� Avec condition ( filtre ) ������������������������������������
15 # Syntaxe : [ expression for element in iterable IF condition ]
16 admis = [n for n in notes if n >= 10]
17 print (admis ) # [14.5 , 17.5 , 12.0 , 11.0]
18
19 # �� Avec expression conditionnelle ����������������������������
20 statuts = ["Admis " if n >= 10 else " Ajourn é" for n in notes ]
Python pour la Data Science — Ibrahima SY
32 CHAPITRE 3. STRUCTURES DE DONNÉES PYTHON
21 print ( statuts )
22 # [' Admis ', 'Ajourn é', 'Admis ', 'Admis ', 'Ajourn é', 'Admis ']
23
24 # �� Compré hension de dictionnaire ����������������������������
25 noms = [" Fatou", " Ibrahima ", "Amina "]
26 notes_noms = [14.5 , 8.0 , 17.5]
27
28 # Créer un dictionnaire {nom: note} en une ligne
29 eleves = {nom: note for nom , note in zip(noms , notes_noms )}
30 print ( eleves ) # {' Fatou ': 14.5 , 'Ibrahima ': 8.0 , 'Amina ': 17.5}
31
32 # Filtrer : garder seulement les admis
33 admis_dict = {nom: note for nom , note in eleves . items () if note
>= 10}
34 print ( admis_dict ) # {' Fatou ': 14.5 , 'Amina ': 17.5}
3.6 Quelle structure choisir ?
Structure Ordonné Modifiable Doublons Quand l’utiliser
list Oui Oui Oui Suite de valeurs à parcourir/trier
tuple Oui Non Oui Données fixes, retours de fonctions
dict Oui* Oui Clés non Objets avec attributs (étudiant, produit)
set Non Oui Non Unicité, test d’appartenance rapide
*Les dictionnaires préservent l’ordre d’insertion depuis Python 3.7.
3.7 Récapitulatif
Key À retenir
Ce que vous devez retenir
— Liste [] : ordonnée et modifiable. Slicing [i:j:k], méthodes .append(),
.sort(), .pop().
— Tuple () : ordonnée et immuable. Idéale pour les retours de fonctions et la déstruc-
turation.
— Dictionnaire {} : paires clé-valeur. .get() évite les KeyError. Itérer avec
.items().
— Ensemble {val, val} : sans doublons, sans ordre. Test d’appartenance en O(1),
opérations ensemblistes.
— Compréhension : [expr for x in seq if cond]. Plus courte et plus rapide
qu’une boucle for.
Python pour la Data Science — Ibrahima SY
Deuxième partie
Bibliothèques Data Science
33
Chapitre 4
NumPy — Le moteur du calcul scientifique
◎ Objectifs du chapitre
— Comprendre pourquoi NumPy est 100× plus rapide que Python pur
— Créer et manipuler des tableaux multidimensionnels (ndarray)
— Exploiter les opérations vectorisées pour remplacer les boucles
— Maîtriser l’indexation avancée et le broadcasting
Imaginez que vous devez calculer la moyenne de 10 millions de notes. Avec une boucle
Python, cela prend environ 3 secondes. Avec NumPy, 30 millisecondes — soit 100 fois plus
rapide. Ce chapitre explique pourquoi cette différence existe et comment en profiter.
4.1 Pourquoi NumPy ?
Pour comprendre l’avantage de NumPy, il faut d’abord comprendre comment Python
stocke les données en mémoire.
Une liste Python comme [1.0, 2.0, 3.0] est en réalité une liste de pointeurs : chaque
élément pointe vers un objet Python indépendant stocké n’importe où dans la mémoire. Pour
additionner deux listes, Python doit suivre chaque pointeur, vérifier le type de chaque objet,
effectuer le calcul... tout cela, élément par élément.
NumPy change radicalement cette approche :
BOOK Concept : ndarray
Le ndarray (n-dimensional array) est la structure centrale de NumPy. Il stocke tous
ses éléments du même type dans un bloc mémoire contigu — comme un vrai tableau
en C. Cela permet :
— Des opérations vectorisées exécutées en C, sans boucles Python
— Un accès mémoire ultra-rapide (les données sont côte à côte)
— Des opérations sur des millions d’éléments en quelques millisecondes
1 import numpy as np
2 import time
3
4 # Comparaison : liste Python vs tableau NumPy
34
4.2. CRÉER DES TABLEAUX NUMPY 35
5 n = 10 _000_000 # 10 millions d'éléments
6 liste = list( range(n))
7 tableau = np. arange (n, dtype = float )
8
9 # Calculer la somme des carrés
10 debut = [Link] ()
11 total_liste = sum(x**2 for x in liste )
12 print (f" Boucle Python : {[Link] () -debut :.2f}s") # ~3.5s
13
14 debut = [Link] ()
15 total_numpy = [Link]( tableau **2)
16 print (f"NumPy : {[Link] () -debut :.3f}s") # ~0.03 s
17 print (f" Facteur d'accélé ration : x {3.5/0.03:.0 f}") # ~x100
4.2 Créer des tableaux NumPy
1 import numpy as np
2
3 # �� Depuis une liste Python ����������������������������������
4 notes = np. array ([14.5 , 8.0, 17.5 , 12.0 , 11.5])
5 print (notes ) # [14.5 8. 17.5 12. 11.5]
6 print (notes . dtype ) # float64 -> type de données
7 print (notes . shape ) # (5 ,) -> forme : 5 éléments , 1
dimension
8 print (notes .ndim) # 1 -> nombre de dimensions
9 print (notes .size) # 5 -> nombre total d'éléments
10
11 # �� Tableau 2D : matrice ( lignes = étudiants , colonnes =
matières) ��
12 resultats = np. array ([
13 [14.5 , 17.0 , 13.0] , # é tudiant 0 : maths , info , anglais
14 [ 8.0 , 10.5 , 9.5] , # é tudiant 1
15 [17.5 , 19.0 , 15.0] , # é tudiant 2
16 [12.0 , 14.0 , 11.0] , # é tudiant 3
17 ])
18 print ( resultats . shape ) # (4, 3) -> 4 lignes , 3 colonnes
19 print ( resultats .ndim) # 2 -> deux dimensions
20
21 # �� Fonctions de création ������������������������������������
22 zeros = np. zeros ((3 , 4)) # matrice 3x4 de zéros
23 uns = [Link] ((2 , 5)) # matrice 2x5 de uns
24 identite = [Link] (3) # matrice identit é 3x3
25 suite = np. arange (0, 20, 2) # [0, 2, 4, ... , 18]
26 regulier = np. linspace (0, 1, 6) # 6 valeurs entre 0 et
1 inclus
27
28 # Données alé atoires (très utile pour les tests )
29 np. random .seed (42) # graine pour la reproductibilit é
30 aleatoire = np. random .rand (4, 3) # valeurs uniformes
entre 0 et 1
Python pour la Data Science — Ibrahima SY
36 CHAPITRE 4. NUMPY — LE MOTEUR DU CALCUL SCIENTIFIQUE
31 notes_sim = np. random . normal (13 , 3, (100 , 3)) # 100 étudiants , 3
matières
4.3 Opérations vectorisées : travailler sans boucles
Le principe fondamental de NumPy : au lieu de dire “pour chaque élément, fais ceci”, on
dit “fais ceci à tout le tableau”. C’est ce qu’on appelle la vectorisation.
1 notes = np. array ([14.5 , 8.0, 17.5 , 12.0 , 11.5])
2
3 # �� Opé rations scalaires : s'appliquent à CHAQUE élément ����
4 print (notes + 1) # [15.5 9. 18.5 13. 12.5] -> bonus
d '1 point
5 print (notes * 5) # sur 100 ( multiplier par 5)
6 print (notes / 20 * 100) # convertir en pourcentage
7 print (notes . round (0)) # arrondir à l'entier
8
9 # �� Statistiques globales ������������������������������������
10 print (f" Moyenne : { [Link] () :.2f}")
11 print (f"Médiane : {np. median (notes ):.2f}")
12 print (f"Ecart -type: { [Link] () :.2f}")
13 print (f"Min / Max : { [Link] ()} / {notes .max ()}")
14 print (f"Somme : { [Link] () :.1f}")
15
16 # �� Sur une matrice 2D : axis =0 agit par COLONNE , axis =1 par
LIGNE ��
17 resultats =
[Link] ([[14.5 ,17. ,13.] ,[8. ,10.5 ,9.5] ,[17.5 ,19. ,15.] ,[12. ,14. ,11.]])
18
19 # Moyenne par MATIÈRE (une valeur par colonne = axis =0)
20 moy_matieres = resultats .mean(axis =0)
21 print (f"Moy. maths ={ moy_matieres [0]:.1 f},
info ={ moy_matieres [1]:.1 f}, "
22 f" anglais ={ moy_matieres [2]:.1 f}")
23 # Moy. maths =13.0 , info =15.1 , anglais =12.1
24
25 # Moyenne par ÉTUDIANT (une valeur par ligne = axis =1)
26 moy_eleves = resultats .mean(axis =1)
27 print (" Moyennes par é tudiant :", moy_eleves . round (1))
28 # Moyennes par é tudiant : [14.8 9.3 17.2 12.3]
LIGHTBULB Astuce
Le moyen mnémotechnique pour axis : axis=0 : on effondre les lignes (résultat = une
valeur par colonne). axis=1 : on effondre les colonnes (résultat = une valeur par ligne).
Imaginez que axis=0 “écrase” verticalement, axis=1 “écrase” horizontalement.
Python pour la Data Science — Ibrahima SY
4.4. INDEXATION AVANCÉE 37
4.4 Indexation avancée
4.4.1 Indexation classique et slicing
1 notes = np. array ([14.5 , 8.0, 17.5 , 12.0 , 11.5])
2 resultats =
[Link] ([[14.5 ,17. ,13.] ,[8. ,10.5 ,9.5] ,[17.5 ,19. ,15.] ,[12. ,14. ,11.]])
3
4 # �� Tableau 1D : identique aux listes Python �����������������
5 print (notes [2]) # 17.5 -> troisi ème élément
6 print (notes [1:4]) # [8. 17.5 12.]
7 print (notes [:: -1]) # invers é
8
9 # �� Tableau 2D : [ligne , colonne ] ����������������������������
10 print ( resultats [0, 1]) # 17.0 -> ligne 0, colonne 1 (note
info de l'é tudiant 0)
11 print ( resultats [2, :]) # [17.5 19. 15.] -> toute la ligne 2
12 print ( resultats [:, 0]) # [14.5 8. 17.5 12.] -> toute la
colonne 0 (maths )
13 print ( resultats [1:3 , 0:2]) # sous - matrice : lignes 1-2,
colonnes 0-1
4.4.2 Indexation booléenne : filtrer avec des masques
L’indexation booléenne est l’une des fonctionnalités les plus puissantes de NumPy. Elle
permet de sélectionner des éléments selon une condition, sans boucle.
1 notes = np. array ([14.5 , 8.0, 17.5 , 12.0 , 9.5 , 11.0])
2
3 # Étape 1 : créer un masque booléen ( tableau de True/False )
4 masque_admis = notes >= 10
5 print ( masque_admis )
6 # [ True False True True False True]
7
8 # Étape 2 : utiliser le masque pour sé lectionner
9 print (notes [ masque_admis ]) # [14.5 17.5 12. 11. ]
10
11 # En une seule ligne (le plus courant )
12 print (notes [ notes >= 10]) # [14.5 17.5 12. 11. ]
13 print (notes [ notes < 10]) # [8. 9.5]
14
15 # Compter les élé ments satisfaisant la condition
16 n_admis = ( notes >= 10).sum () # True est compt é comme 1
17 print (f"Admis : { n_admis }/{ len(notes )}") # Admis : 4/6
18
19 # Modifier les éléments qui satisfont une condition
20 notes_corrigees = notes .copy () # toujours copier
d'abord !
21 notes_corrigees [ notes_corrigees < 10] = 10.0 # relever les notes
à 10
Python pour la Data Science — Ibrahima SY
38 CHAPITRE 4. NUMPY — LE MOTEUR DU CALCUL SCIENTIFIQUE
22 print ( notes_corrigees ) # [14.5 10. 17.5 12. 10. 11. ]
23
24 # np. where : opé rateur ternaire vectoris é
25 # np. where(condition , valeur_si_vrai , valeur_si_faux )
26 statuts = np. where ( notes >= 10, "Admis ", " Ajourn é")
27 print ( statuts ) # [' Admis ' 'Ajourn é' 'Admis ' 'Admis ' 'Ajourn é'
'Admis ']
4.5 Broadcasting : des opérations intelligentes entre formes
différentes
BOOK Concept : Broadcasting
Le broadcasting est le mécanisme par lequel NumPy applique automatiquement des
opérations entre des tableaux de formes différentes, sans jamais copier les données. Il
économise de la mémoire et du temps.
Prenons un exemple concret : vous avez les notes de 4 étudiants dans 3 matières, et vous
voulez calculer la moyenne pondérée de chacun. Au lieu d’écrire une boucle, NumPy “étire”
automatiquement le vecteur des poids.
1 # 4 étudiants , 3 matières
2 resultats = np. array ([
3 [14.5 , 17.0 , 13.0] ,
4 [ 8.0 , 10.5 , 9.5] ,
5 [17.5 , 19.0 , 15.0] ,
6 [12.0 , 14.0 , 11.0] ,
7 ]) # shape : (4, 3)
8
9 # Coefficients des matières : maths =4, info =4, anglais =2
10 poids = np. array ([4 , 4, 2]) # shape : (3 ,)
11 poids_normalises = poids / poids .sum () # [0.4 , 0.4 , 0.2]
12
13 # Broadcasting : resultats (4 ,3) * poids_normalises (3 ,) = (4 ,3)
14 # NumPy "répète" poids_normalises pour chaque ligne de resultats
15 notes_ponderees = resultats * poids_normalises
16 moyennes = notes_ponderees .sum(axis =1) # sommer par ligne
17 print (" Moyennes pondérées :", moyennes . round (2))
18 # [15.1 9.06 17.55 12.45]
19
20 # Centrer les données ( soustraire la moyenne de chaque colonne )
21 moyennes_col = resultats .mean(axis =0) # shape (3 ,)
22 centrees = resultats - moyennes_col # broadcasting : (4 ,3) -
(3,)
23 print ("Données centrées :")
24 print ( centrees . round (2))
25 # Chaque colonne a maintenant une moyenne de 0
26 print ("Vé rification ( doivent être ~0) :",
centrees .mean(axis =0). round (10))
Python pour la Data Science — Ibrahima SY
4.6. RÉCAPITULATIF 39
4.6 Récapitulatif
Key À retenir
Ce que vous devez retenir
— NumPy est 100× plus rapide que Python pur grâce à la mémoire contiguë et aux
opérations vectorisées en C.
— [Link]() crée un tableau ; .shape, .dtype, .ndim l’inspectent.
— Les opérations mathématiques s’appliquent à tout le tableau sans boucle.
— axis=0 : opération par colonne ; axis=1 : opération par ligne.
— L’indexation booléenne a[a > 10] filtre les éléments sans boucle.
— [Link](cond, vrai, faux) est le ternaire vectorisé.
— Le broadcasting applique automatiquement les opérations entre tableaux de formes
compatibles, sans copier les données.
Python pour la Data Science — Ibrahima SY
Chapitre 5
Pandas — L’outil central du Data Scientist
◎ Objectifs du chapitre
— Comprendre les structures Series et DataFrame
— Charger des données depuis des fichiers CSV, Excel, JSON
— Nettoyer les données : valeurs manquantes, doublons, types incorrects
— Filtrer, trier, grouper et agréger des données avec Pandas
NumPy est puissant, mais il a deux limites importantes pour la Data Science : il ne gère
que des données du même type (pas de mélange texte/nombres), et il n’a pas de noms de
colonnes. En pratique, un fichier CSV contient des chaînes, des entiers, des décimaux et des
valeurs manquantes — tout mélangé. Pandas est né pour résoudre exactement ce problème.
5.1 Les deux structures de base
5.1.1 La Series : une colonne avec étiquettes
BOOK Concept : Series
Une Series est un tableau 1D de Pandas. La différence fondamentale avec NumPy :
chaque élément a une étiquette (son index). L’index peut être des entiers (0, 1, 2...) ou
des chaînes (noms des étudiants, dates, pays...).
1 import pandas as pd
2 import numpy as np
3
4 # Créer une Series avec des é tiquettes personnalis ées
5 notes_maths = pd. Series (
6 [14.5 , 8.0 , 17.5 , 12.0 , [Link]], # [Link] = valeur
manquante
7 index =["Fatou ", " Ibrahima ", "Amina ", " Seydou ", " Moussa "],
8 name=" note_maths "
9 )
10 print ( notes_maths )
40
5.1. LES DEUX STRUCTURES DE BASE 41
1 Fatou 14.5
2 Ibrahima 8.0
3 Amina 17.5
4 Seydou 12.0
5 Moussa NaN
6 Name: note_maths , dtype : float64
1 # Accéder aux élé ments : par é tiquette ou par position
2 print ( notes_maths [" Fatou"]) # 14.5 -> par é tiquette
( recommand é)
3 print ( notes_maths .iloc [0]) # 14.5 -> par position entière
( utiliser .iloc , jamais [0] directement )
4
5 # Statistiques directement disponibles
6 print (f" Moyenne (sans NaN) : { notes_maths .mean () :.2f}") # NaN
ignor é automatiquement
7 print (f" Valeurs manquantes : { notes_maths .isna ().sum ()}")
5.1.2 Le DataFrame : la table de données
BOOK Concept : DataFrame
Un DataFrame est un tableau 2D avec un index (lignes) et des noms de colonnes.
C’est la structure centrale de Pandas — l’équivalent d’un fichier Excel, d’une table
SQL ou d’un tableau R. Chaque colonne est une Series.
1 # Créer un DataFrame depuis un dictionnaire
2 # Chaque clé = nom de colonne , chaque valeur = liste des données
3 data = {
4 "nom": ["SY", " DIALLO ", " NDIAYE ", "FALL", "BA"],
5 " prenom ": [" Ibrahima ", "Fatou ", "Amina ", " Seydou ",
" Moussa "],
6 "age": [22 , 21, 23, 22, 24] ,
7 " filiere ": ["Info", "Maths ", "Info", " Physique ", "Maths "],
8 " note_maths ": [14.5 , 17.0 , 8.0 , 12.0 , [Link]],
9 " note_info ": [17.0 , 13.5 , 10.5 , 14.0 , 11.0] ,
10 " note_anglais ": [13.0 , 15.0 , 9.5 , 11.0 , 14.0] ,
11 " admis": [True , True , False , True , True]
12 }
13 df = pd. DataFrame (data)
14
15 # �� Explorer le DataFrame �������������������������������������
16 print (f"Forme : {[Link] }") # (5, 8) -> 5 lignes , 8
colonnes
17 [Link] () # types et valeurs manquantes
18 print ([Link] (3)) # 3 premi ères lignes
19 print (df. describe ()) # statistiques des colonnes
numé riques
Python pour la Data Science — Ibrahima SY
42 CHAPITRE 5. PANDAS — L’OUTIL CENTRAL DU DATA SCIENTIST
5.2 Lire et écrire des fichiers
Dans un projet réel, les données ne sont jamais saisies à la main. Elles viennent de fichiers
CSV, d’exports Excel, de bases de données ou d’APIs. Pandas peut lire et écrire tous ces
formats en une seule ligne.
1 # �� Lire un fichier CSV ��������������������������������������
2 df = pd. read_csv (" eleves .csv")
3
4 # Options utiles selon la source du fichier
5 df = pd. read_csv (" eleves .csv",
6 sep=";", # sé parateur point - virgule
( export Excel )
7 encoding ="utf -8", # encodage (évite les
probl èmes de caract ères)
8 decimal =",", # pour les nombres
europ éens (12 ,5 au lieu de 12.5)
9 na_values =["N/A", "-", ""], # valeurs à
traiter comme NaN
10 index_col ="id") # utiliser la colonne 'id '
comme index
11
12 # �� Lire un fichier Excel ������������������������������������
13 df = pd. read_excel (" eleves .xlsx", sheet_name =" Promotion2024 ")
14
15 # �� Lire du JSON ���������������������������������������������
16 df = pd. read_json (" eleves .json")
17
18 # �� Écrire un fichier CSV �������������������������������������
19 # index =False évite d'é crire l'index numérique comme une colonne
suppl é mentaire
20 df. to_csv (" eleves_nettoyes .csv", index =False , encoding ="utf -8")
21
22 # �� Écrire un fichier Excel �����������������������������������
23 df. to_excel (" rapport .xlsx", sheet_name ="Ré sultats ", index = False )
5.2.1 Accéder aux données
1 # �� Sé lectionner des colonnes ���������������������������������
2 df["nom"] # une colonne -> retourne une Series
3 df[["nom", " prenom "]] # plusieurs colonnes -> retourne un
DataFrame
4
5 # �� Sé lectionner des lignes : .loc [] et .iloc [] ���������������
6 # .loc [] : accès par ÉTIQUETTE (nom de l'index ou condition )
7 [Link] [0] # ligne d'index 0
8 [Link] [0:2] # lignes d'index 0 à 2 (FIN INCLUSE
avec .loc !)
9 [Link] [0, " note_maths "] # valeur unique : ligne 0, colonne
" note_maths "
Python pour la Data Science — Ibrahima SY
5.3. NETTOYAGE DES DONNÉES 43
10 [Link] [:, " note_maths "] # toute la colonne (é quivalent à
df [" note_maths "])
11
12 # .iloc [] : accès par POSITION (entier , comme NumPy )
13 [Link] [0] # premi ère ligne
14 [Link] [0:3] # lignes 0, 1, 2 (FIN EXCLUE avec
.iloc)
15 [Link] [0, 4] # valeur : ligne 0, colonne 4
16 [Link] [:, 4:] # toutes les lignes , colonnes à partir
de la 4e
INFO-CIRCLE Note
.loc vs .iloc : la différence clé. .loc fonctionne avec les étiquettes (noms des colonnes,
valeurs d’index). .iloc fonctionne avec les positions (entiers, comme NumPy). Quand
l’index est 0, 1, 2, 3... les deux semblent identiques, mais ils divergent dès que l’index
est réindexé ou non-numérique. Dans le doute, utilisez .iloc pour la position et .loc
pour les étiquettes.
5.3 Nettoyage des données
Les données réelles sont rarement propres. Un Data Scientist passe en réalité 60 à 80% de
son temps à nettoyer les données. Maîtriser ce processus est aussi important que de connaître
les algorithmes ML.
5.3.1 Valeurs manquantes (NaN)
1 # �� Dé tecter les valeurs manquantes ��������������������������
2 print (df. isnull ().sum ()) # nombre de NaN par colonne
3 print (df. isnull ().sum () / len(df) * 100) # pourcentage de NaN
4
5 # Visualiser les cellules manquantes
6 print (df. isnull ()) # tableau de True/False
7
8 # �� Stratégies de traitement ����������������������������������
9
10 # Strat égie 1 : SUPPRIMER les lignes avec NaN
11 df_sans_nan = df. dropna () # supprimer si
AU MOINS 1 NaN
12 df_sans_nan = df. dropna ( subset =[" note_maths "]) # seulement si
NaN dans note_maths
13 df_sans_nan = df. dropna ( thresh =5) # supprimer si
moins de 5 valeurs valides
14
15 # Strat égie 2 : REMPLACER ( imputation )
16 df_copie = [Link] ()
17
18 # Imputation par la moyenne ( simple mais sensible aux outliers )
Python pour la Data Science — Ibrahima SY
44 CHAPITRE 5. PANDAS — L’OUTIL CENTRAL DU DATA SCIENTIST
19 df_copie [" note_maths "] =
df_copie [" note_maths "]. fillna ( df_copie [" note_maths "]. mean ())
20
21 # Imputation par la médiane (plus robuste , à préférer si des
outliers existent )
22 mediane = df[" note_maths "]. median ()
23 df_copie [" note_maths "] = df_copie [" note_maths "]. fillna ( mediane )
24
25 # Imputation par la valeur précédente / suivante (pour les séries
temporelles )
26 # . ffill () propage la derni ère valeur valide vers le bas ( forward
fill)
27 df_copie [" note_maths "] = df_copie [" note_maths "]. ffill ()
28
29 # Imputation par une valeur fixe
30 df_copie ["admis "] = df_copie ["admis "]. fillna ( False )
5.3.2 Doublons et types de données
1 # �� Doublons ��������������������������������������������������
2 print (f" Lignes dupliqu ées : {df. duplicated ().sum ()}")
3 df_unique = df. drop_duplicates ()
4 df_unique = df. drop_duplicates ( subset =["nom", " prenom "],
keep="first ")
5
6 # �� Corriger les types de données ����������������������������
7 # Un CSV lit tout comme du texte ; il faut convertir
8 df["age"] = df["age"]. astype (int)
9 df[" note_maths "] = pd. to_numeric (df[" note_maths "],
errors =" coerce ") # sûr
10
11 # �� Nettoyer les chaînes de caract ères �����������������������
12 # Probl èmes fré quents : espaces , majuscules incoh é rentes
13 df["nom"] = df["nom"]. str. upper ().str. strip () # tout en
majuscules , sans espaces
14 df[" prenom "] = df[" prenom "]. str. capitalize ().str. strip () #
Premi ère lettre majuscule
15 df[" filiere "] = df[" filiere "]. str. strip ().str. replace (" ", " ")
# normaliser
16
17 # Vé rifier les valeurs uniques (dé tecter les erreurs de saisie )
18 print (df[" filiere "]. unique ()) # ['Info ' 'Maths '
'Physique ' 'Chimie ']
19 print (df[" filiere "]. value_counts ()) # Combien par catégorie
5.4 Filtrer, trier et transformer
1 # �� Filtrer par condition �������������������������������������
Python pour la Data Science — Ibrahima SY
5.5. GROUPBY : AGRÉGER DES DONNÉES PAR GROUPE 45
2 admis = df[df[" admis"] == True]
3 bonne_note = df[df[" note_maths "] >= 14]
4 info_admis = df [( df[" filiere "] == "Info") & (df["admis "] ==
True)] # ET logique
5 non_admis = df [~ df["admis "]] # NOT logique (tilde =
né gation )
6
7 # Syntaxe . query () : plus lisible pour les conditions complexes
8 info_admis = df. query (" filiere == 'Info ' and note_maths >= 12")
9 jeunes = df. query ("18 <= age <= 22")
10
11 # �� Trier �����������������������������������������������������
12 df_trie = df. sort_values (" note_maths ", ascending = False ) #
dé croissant
13 df_trie = df. sort_values ([" filiere ", " note_maths "],
14 ascending =[ True , False ]) # filière
croissant , note dé croissant
15
16 # �� Créer de nouvelles colonnes �������������������������������
17 # Colonne calcul ée
18 df[" moyenne "] = df [[" note_maths ", " note_info ",
" note_anglais "]]. mean(axis =1)
19
20 # Colonne conditionnelle
21 df[" mention "] = np. where (df[" moyenne "] >= 16, "Très Bien",
22 np. where (df[" moyenne "] >= 14, "Bien",
23 np. where (df[" moyenne "] >= 12, "Assez Bien",
24 np. where (df[" moyenne "] >= 10, " Passable ",
" Ajourn é"))))
25
26 # Appliquer une fonction personnalis ée à chaque ligne
27 def categorie_age (age):
28 if age < 21: return "Moins de 21 ans"
29 elif age < 24: return "21 -23 ans"
30 else: return "24 ans et plus"
31
32 df[" tranche_age "] = df["age"]. apply ( categorie_age )
33 # Ou avec une lambda (équivalent , plus concis )
34 df[" tranche_age "] = df["age"]. apply ( lambda a: "Jeune " if a < 23
else " Senior ")
5.5 Groupby : agréger des données par groupe
groupby() est l’équivalent Pandas du SQL GROUP BY. Il vous permet de calculer des
statistiques séparément pour chaque groupe de valeurs d’une colonne.
1 # Calculer la moyenne par filière
2 moy_filiere = df. groupby (" filiere ")[" moyenne "]. mean ()
3 print ( moy_filiere )
4 # filiere
Python pour la Data Science — Ibrahima SY
46 CHAPITRE 5. PANDAS — L’OUTIL CENTRAL DU DATA SCIENTIST
5 # Info 12.83
6 # Maths 15.17
7 # Physique 12.33
8 # Name: moyenne , dtype: float64
9
10 # Plusieurs agré gations en une fois
11 stats = df. groupby (" filiere ").agg ({
12 " moyenne ": ["mean", "std", "min", "max"], # 4 stats sur
moyenne
13 " admis": "sum", # nombre
d'admis
14 " note_maths ": " count" # nombre
d'observations
15 })
16 print (stats )
17
18 # Compter les é tudiants par catégorie
19 print (df[" filiere "]. value_counts ()) # fré quences par
filière
20 print (df[" mention "]. value_counts ( normalize =True).mul (100) . round (1))
# en %
21
22 # Tableau crois é : filière × mention
23 tableau_croise = pd. crosstab (df[" filiere "], df[" mention "])
24 print ( tableau_croise )
25
26 # Tableau crois é avec normalization par ligne ( proportions )
27 tableau_prop = pd. crosstab (df[" filiere "], df[" mention "],
normalize ="index ")
28 print ( tableau_prop . round (2))
Python pour la Data Science — Ibrahima SY
5.6. RÉCAPITULATIF 47
5.6 Récapitulatif
Key À retenir
Ce que vous devez retenir
— pd.read_csv() lit un CSV en une ligne. df.to_csv(index=False) le sauve-
garde.
— [Link](), [Link](), [Link]() : les 3 premières commandes dès que
vous chargez un nouveau dataset.
— [Link]().sum() compte les NaN ; fillna() les remplace ; dropna() sup-
prime les lignes.
— .loc[] accède par étiquette ; .iloc[] accède par position.
— Filtrer : df[condition] ou [Link]("...").
— [Link]("col").agg({...}) : agrégations par groupe.
— df["new_col"] = ... crée une colonne ; .apply(fonction) applique une fonc-
tion ligne par ligne.
Python pour la Data Science — Ibrahima SY
Chapitre 6
Analyse Exploratoire des Données (EDA)
◎ Objectifs du chapitre
— Calculer et interpréter les statistiques descriptives essentielles
— Analyser les distributions et comprendre leur forme
— Mesurer et interpréter les corrélations entre variables
— Détecter et traiter les valeurs aberrantes (outliers)
Il existe une règle non écrite en Data Science : ne jamais construire un modèle avant
d’avoir exploré les données. Un chercheur qui modélise sans explorer, c’est comme un
médecin qui prescrit un traitement sans examiner le patient. L’EDA (Exploratory Data
Analysis) est cette phase d’examen — elle révèle la structure cachée des données, les problèmes
de qualité, et les pistes à explorer.
6.1 Les statistiques descriptives : résumer un dataset en
quelques chiffres
BOOK Concept : Statistiques descriptives
Les statistiques descriptives résument la distribution d’une variable en quelques
indicateurs clés : où se situe le centre ? Quelle est la dispersion ? La distribution est-elle
symétrique ? Y a-t-il des valeurs extrêmes ?
6.1.1 La commande describe() : votre premier réflexe
1 import pandas as pd
2 import numpy as np
3
4 df = pd. read_csv (" eleves .csv")
5 df[" moyenne "] =
df[[" note_maths "," note_info "," note_anglais "]]. mean(axis =1)
6
7 # describe () calcule 8 statistiques sur toutes les colonnes
numé riques
48
6.1. LES STATISTIQUES DESCRIPTIVES : RÉSUMER UN DATASET EN QUELQUES
CHIFFRES 49
8 print (df. describe (). round (2))
1 note_maths note_info note_anglais moyenne
2 count 95.00 100.00 100.00 100.00 <-
observations valides
3 mean 13.17 13.45 12.95 13.19 <- moyenne
arithm é tique
4 std 2.98 3.02 2.99 2.46 <- é
cart -type
5 min 6.00 5.00 5.00 6.83 <- minimum
6 25% 11.00 11.00 11.00 11.25 <- 1er
quartile
7 50% 13.50 13.50 13.00 13.17 <- mé diane
8 75% 15.50 16.00 15.00 15.08 <- 3e
quartile
9 max 20.00 20.00 20.00 19.00 <- maximum
1 # Statistiques individuelles et avanc ées
2 col = df[" note_maths "]. dropna ()
3
4 print (f" Moyenne : {[Link] () :.2f}")
5 print (f"Médiane : {col. median () :.2f}")
6 print (f"Ecart -type : {[Link] () :.2f}")
7 print (f"IQR : {col. quantile (0.75) -
col. quantile (0.25) :.2f}")
8 print (f" Skewness : {[Link] () :.3f}") # asymétrie
9 print (f" Kurtosis : {col. kurtosis () :.3f}") # aplatissement
6.1.2 Interpréter les indicateurs clés
Indicateur Ce qu’il mesure Piège / Limite
Moyenne 𝑥 ̄ Centre de la distribution Très sensible aux outliers
Médiane Valeur centrale (50% dessous) Robuste aux outliers
Écart-type 𝜎 Dispersion autour de la moyenne Sensible aux outliers
IQR (𝑄3 − 𝑄1 ) Dispersion du milieu 50% Robuste aux outliers
Skewness > 0 Distribution asymétrique droite Queue de valeurs élevées
Skewness < 0 Distribution asymétrique gauche Queue de valeurs faibles
Python pour la Data Science — Ibrahima SY
50 CHAPITRE 6. ANALYSE EXPLORATOIRE DES DONNÉES (EDA)
INFO-CIRCLE Note
Moyenne vs Médiane : quand préférer laquelle ? Si un étudiant a 20/20 dans un
groupe où tous les autres ont 10/20, la moyenne monte à 11.5/20, alors que la médiane
reste 10/20. La médiane est plus représentative du “cas typique” en présence de valeurs
extrêmes. C’est pourquoi les économistes utilisent la médiane des salaires, pas la
moyenne — sinon, Elon Musk fait de nous tous des millionnaires “en moyenne”.
6.2 Analyser les distributions
1 # Variables caté gorielles : compter les valeurs
2 print ("=== Ré partition par filière ===")
3 print (df[" filiere "]. value_counts ())
4 print (df[" filiere "]. value_counts ( normalize =True).mul (100) . round (1))
5
6 # Dé couper une variable continue en tranches : [Link] ()
7 bins = [0, 10, 12, 14, 16, 20]
8 labels = [" Ajourn é", " Passable ", "Assez Bien", "Bien", "Très
Bien"]
9 df[" tranche "] = [Link](df[" moyenne "], bins=bins , labels = labels )
10 print (df[" tranche "]. value_counts (). sort_index ())
11
12 # Comparer les distributions par groupe
13 print ("\n=== Statistiques par filière ===")
14 print (df. groupby (" filiere ")[" moyenne "]. describe (). round (2))
15
16 # Tableau crois é : filière × mention
17 print ("\n=== Filière vs Admission ===")
18 tab = pd. crosstab (df[" filiere "], df["admis "], margins =True)
19 tab. columns = ["Non admis ", " Admis ", "Total "]
20 print (tab)
6.3 La corrélation : mesurer les relations entre variables
BOOK Concept : Coefficient de corrélation de Pearson
Le coefficient 𝑟 mesure la force et le sens de la relation linéaire entre deux variables
numériques.
∑(𝑥𝑖 − 𝑥)(𝑦
̄ 𝑖 − 𝑦)̄
𝑟= ∈ [−1, 1]
√∑(𝑥𝑖 − 𝑥)̄ 2 ⋅ ∑(𝑦𝑖 − 𝑦)̄ 2
— 𝑟 ≈ +1 : forte relation positive (quand l’un monte, l’autre monte)
— 𝑟 ≈ −1 : forte relation négative (quand l’un monte, l’autre descend)
— 𝑟 ≈ 0 : pas de relation linéaire
1 # Matrice de corré lation : toutes les paires en une seule fois
Python pour la Data Science — Ibrahima SY
6.3. LA CORRÉLATION : MESURER LES RELATIONS ENTRE VARIABLES 51
2 cols = [" note_maths ", " note_info ", " note_anglais ", " moyenne "]
3 corr_matrix = df[cols ]. corr (). round (3)
4 print ( corr_matrix )
1 note_maths note_info note_anglais moyenne
2 note_maths 1.000 0.653 0.481 0.847
3 note_info 0.653 1.000 0.512 0.882
4 note_anglais 0.481 0.512 1.000 0.773
5 moyenne 0.847 0.882 0.773 1.000
1 # Interpr éter la force de la corré lation
2 def interpreter_r (r):
3 r = abs(r)
4 if r >= 0.8: return "Très forte "
5 elif r >= 0.6: return "Forte "
6 elif r >= 0.4: return "Modérée"
7 elif r >= 0.2: return " Faible "
8 else: return "Très faible ou nulle "
9
10 # La variable la plus corrélée avec 'admis ' ( variable cible )
11 # .copy () crée une copie indé pendante pour éviter le
SettingWithCopyWarning
12 df_num =
df[[" note_maths "," note_info "," note_anglais "," moyenne "]]. copy ()
13 df_num [" admis_num "] = df["admis "]. astype (int)
14
15 corrs_avec_admis = df_num .corr ()[" admis_num "]. drop(" admis_num ")
16 print ("Corré lation avec 'admis ' :")
17 for var , r in
corrs_avec_admis . sort_values ( ascending = False ). items ():
18 print (f" {var :15} : r={r:.3f} -> { interpreter_r (r)}")
19
20 # Corré lation de Spearman : pour les relations non -linéaires ou
ordinales
21 corr_spearman = df[cols ]. corr( method =" spearman ")
Exclamation-Triangle Attention
Corrélation ≠ Causalité. Si la corrélation entre “les ventes de glaces” et “les noyades”
est forte (r = 0.85), ce n’est pas parce que les glaces causent les noyades. Les deux sont
causés par un tiers facteur : la chaleur estivale. Une corrélation n’implique jamais une
relation de cause à effet. Toujours chercher l’explication avant de conclure.
Python pour la Data Science — Ibrahima SY
52 CHAPITRE 6. ANALYSE EXPLORATOIRE DES DONNÉES (EDA)
6.4 Détection et traitement des outliers
BOOK Concept : Valeur aberrante (outlier)
Un outlier est une observation qui s’écarte anormalement des autres. Il peut avoir trois
origines :
1. Une erreur de saisie (un étudiant noté 200/20 au lieu de 20/20)
2. Un cas exceptionnel réel (un étudiant particulièrement brillant ou en difficulté)
3. Un signal important (un groupe de patients avec des symptômes atypiques)
Dans les trois cas, il faut les identifier et comprendre avant de décider quoi en faire.
6.4.1 Méthode 1 : la règle de l’IQR
1 def detecter_outliers_iqr ( series ):
2 """
3 Retourne un masque booléen identifiant les outliers selon la
règle de l'IQR.
4
5 La règle : est consid érée outlier toute valeur qui se situe à
plus de
6 1.5 × IQR en dessous de Q1 ou au - dessus de Q3.
7 """
8 Q1 = series . quantile (0.25)
9 Q3 = series . quantile (0.75)
10 IQR = Q3 - Q1
11 borne_basse = Q1 - 1.5 * IQR
12 borne_haute = Q3 + 1.5 * IQR
13 return ( series < borne_basse ) | ( series > borne_haute )
14
15 # Appliquer sur la note de maths
16 notes_valides = df[" note_maths "]. dropna ()
17 masque = detecter_outliers_iqr ( notes_valides )
18 outliers = notes_valides [ masque ]
19 print (f" Outliers détectés : { masque .sum ()}
({100* masque .mean () :.1f}%)")
20 print ( outliers )
6.4.2 Méthode 2 : le Z-score
1 def z_score ( series ):
2 """ Calcule le Z-score de chaque valeur ."""
3 return ( series - series .mean ()) / series .std ()
4
5 z = z_score (df[" note_maths "]. dropna ())
6 # Convention : |z| > 3 = outlier (plus de 3 écarts -types de la
moyenne )
7 outliers_z = z[abs(z) > 3]
Python pour la Data Science — Ibrahima SY
6.5. RÉCAPITULATIF 53
8 print (f" Outliers Z- score (|z| >3) : {len( outliers_z )}")
6.4.3 Que faire avec les outliers ?
1 # Dé cision 1 : SUPPRIMER si c'est clairement une erreur
2 masque_ok =
~ detecter_outliers_iqr (df[" note_maths "]. fillna (df[" note_maths "]. median ()))
3 df_sans_outliers = df[ masque_ok ]
4
5 # Dé cision 2 : PLAFONNEMENT ( winsorization ) - limiter sans
supprimer
6 Q1 = df[" note_maths "]. quantile (0.25)
7 Q3 = df[" note_maths "]. quantile (0.75)
8 IQR = Q3 - Q1
9 df[" note_maths_win "] = df[" note_maths "]. clip(
10 lower =Q1 - 1.5 * IQR ,
11 upper =Q3 + 1.5 * IQR
12 )
13
14 # Dé cision 3 : CONSERVER et documenter
15 # Si un é tudiant a vraiment 20/20 dans toutes les matières ,
16 # ce n'est pas une erreur -> le conserver mais le signaler .
6.5 Récapitulatif
Key À retenir
Ce que vous devez retenir
— [Link]() est la première commande à lancer sur un nouveau dataset.
— Médiane et IQR sont robustes aux outliers ; moyenne et écart-type ne le sont pas.
— Skewness > 0 : queue à droite (outliers hauts) ; < 0 : queue à gauche.
— [Link]() calcule toutes les corrélations de Pearson en une fois.
— 𝑟 mesure la relation linéaire. Corrélation ≠ Causalité.
— Règle IQR : outlier si < 𝑄1 − 1.5 × IQR ou > 𝑄3 + 1.5 × IQR.
— Face à un outlier : comprendre son origine avant de décider.
Python pour la Data Science — Ibrahima SY
Chapitre 7
Visualisation de données
◎ Objectifs du chapitre
— Comprendre la structure Figure/Axes de Matplotlib
— Créer les graphiques fondamentaux : histogramme, barres, scatter, boxplot
— Produire des visualisations statistiques avancées avec Seaborn
— Choisir le bon graphique selon la question posée
Imaginez qu’un directeur pédagogique vous demande d’analyser les résultats de 500
étudiants répartis dans quatre filières sur trois matières. Vous pourriez lui remettre un ta-
bleau de 500 lignes et 8 colonnes. Mais si vous lui montrez un seul graphique bien choisi
— par exemple un boxplot comparant la distribution des moyennes par filière — il verra
immédiatement où sont les forces, les faiblesses et les anomalies.
C’est la puissance de la visualisation : transformer des chiffres en images qui parlent
d’elles-mêmes. La visualisation sert deux maîtres à la fois : c’est un outil d’exploration
(pour vous, pendant l’analyse) et un outil de communication (pour votre audience, lors de la
restitution).
7.1 Matplotlib : la fondation de la visualisation Python
BOOK Concept : Matplotlib
Matplotlib est la bibliothèque de référence pour la visualisation en Python, créée
en 2003 par John Hunter. Elle offre un contrôle total sur chaque élément visuel. Son
module pyplot expose une interface de haut niveau inspirée de MATLAB qui permet
de créer des graphiques en quelques lignes.
7.1.1 La métaphore de la toile et du cadre
Pour utiliser Matplotlib correctement, il faut comprendre son modèle conceptuel. Un
graphique Matplotlib est composé de deux niveaux imbriqués :
— La Figure (fig) : la “feuille de papier” entière. Elle peut contenir un ou plusieurs gra-
phiques, un titre global, une légende partagée.
54
7.1. MATPLOTLIB : LA FONDATION DE LA VISUALISATION PYTHON 55
— Les Axes (ax) : le “cadre” dans lequel est dessiné un graphique. C’est là que se trouvent
les axes x et y, le titre, les courbes, les barres, etc.
Cette distinction est importante parce qu’une Figure peut contenir plusieurs Axes disposés
en grille. Si vous avez quatre graphiques côte à côte, vous avez une Figure et quatre objets
Axes.
1 import matplotlib . pyplot as plt
2 import numpy as np
3 import pandas as pd
4
5 # Configuration globale : s'applique à tous les graphiques du
notebook
6 plt. rcParams [" figure . figsize "] = (10 , 6) # taille par défaut
7 plt. rcParams ["[Link]"] = 12 # taille de police par
défaut
8 plt. rcParams ["[Link]"] = True # grille activ ée
9 plt. rcParams ["grid. alpha"] = 0.3 # grille discr ète (30%
d'opacit é)
10
11 # Charger le dataset fil rouge
12 df = pd. read_csv (" eleves .csv")
13 df[" moyenne "] =
df[[" note_maths "," note_info "," note_anglais "]]. mean(axis =1)
7.1.2 Créer un graphique : la syntaxe de base
1 # plt. subplots () crée simultan ément la Figure et ses Axes
2 # figsize =( largeur , hauteur ) en pouces
3 fig , ax = plt. subplots ( figsize =(10 , 6))
4
5 # Dessiner une courbe simple sur cet axe
6 [Link](
7 [1, 2, 3, 4], # données x ( semaines )
8 [10, 12, 9, 14] , # données y ( valeurs )
9 color =" steelblue ", # couleur de la courbe
10 linewidth =2, # é paisseur du trait
11 linestyle ="--", # style : tirets
12 marker ="o", # marque un point à chaque donnée
13 markersize =8, # taille des marques
14 label ="Série A" # é tiquette pour la légende
15 )
16
17 # Habiller le graphique
18 ax. set_title (" Évolution hebdomadaire ", fontsize =14 ,
fontweight ="bold")
19 ax. set_xlabel (" Semaine ")
20 ax. set_ylabel (" Valeur ")
21 ax. legend () # afficher la légende ( utilise les
labels )
22 ax. set_ylim (0, 20) # forcer l'axe y de 0 à 20
Python pour la Data Science — Ibrahima SY
56 CHAPITRE 7. VISUALISATION DE DONNÉES
23
24 # Finaliser et sauvegarder
25 plt. tight_layout () # ajuste automatiquement les marges pour é
viter les coupures
26 plt. savefig (" graphique .png", dpi =150 , bbox_inches ="tight ")
27 [Link] ()
INFO-CIRCLE Note
Toujours habiller vos graphiques. Un graphique sans titre, sans labels d’axes
et sans unité est inutilisable. La règle minimale : set_title(), set_xlabel(),
set_ylabel(). Sans cela, votre audience ne sait pas ce qu’elle regarde.
7.2 Les graphiques fondamentaux
7.2.1 L’histogramme — voir la forme d’une distribution
L’histogramme est le premier graphique à tracer sur une nouvelle variable numérique. Il
découpe la plage de valeurs en intervalles (bins) et compte combien d’observations tombent
dans chaque intervalle. En un coup d’œil, vous voyez si la distribution est symétrique, si elle
a une queue, si elle présente plusieurs modes, et où se situent les valeurs typiques.
1 fig , axes = plt. subplots (1, 2, figsize =(14 , 5))
2 # plt. subplots (1, 2) crée une grille de 1 ligne × 2 colonnes
3 # axes est alors un tableau de 2 objets Axes : axes [0] et axes [1]
4
5 # --- Graphique de gauche : histogramme avec repères statistiques
---
6 axes [0]. hist(
7 df[" moyenne "]. dropna () , # données : on enlève les NaN
d'abord
8 bins =10 , # 10 intervalles (à ajuster selon
les données)
9 color =" steelblue ", # couleur des barres
10 edgecolor =" white", # bord blanc pour mieux distinguer
les barres
11 alpha =0.8 # légère transparence
12 )
13
14 # Tracer la ligne de la moyenne (rouge ) et de la médiane ( orange )
15 # axvline = " vertical line" à la valeur x spécifiée
16 axes [0]. axvline (
17 df[" moyenne "]. mean () ,
18 color ="red", linestyle ="--", linewidth =2,
19 label =f" Moyenne ={ df[' moyenne ']. mean () :.1f}"
20 )
21 axes [0]. axvline (
22 df[" moyenne "]. median () ,
23 color =" orange ", linestyle ="--", linewidth =2,
24 label =f"Médiane ={ df[' moyenne ']. median () :.1f}"
Python pour la Data Science — Ibrahima SY
7.2. LES GRAPHIQUES FONDAMENTAUX 57
25 )
26 axes [0]. set_title (" Distribution des moyennes ")
27 axes [0]. set_xlabel (" Moyenne (/ 20)")
28 axes [0]. set_ylabel (" Nombre d'élèves")
29 axes [0]. legend ()
30
31 # --- Graphique de droite : histogramme superpos é par filière ---
32 # On boucle sur chaque filière et on trace un histogramme
semi - transparent
33 for filiere , groupe in df. groupby (" filiere "):
34 axes [1]. hist(
35 groupe [" moyenne "]. dropna () ,
36 bins =8,
37 alpha =0.6 , # transparence pour voir les
superpositions
38 label = filiere
39 )
40 axes [1]. set_title (" Distribution par filière")
41 axes [1]. set_xlabel (" Moyenne ")
42 axes [1]. legend ()
43
44 plt. tight_layout ()
45 [Link] ()
LIGHTBULB Astuce
Combien de bins ? Il n’y a pas de règle absolue. En pratique : pour 100 observations,
10 à 15 bins. Trop peu de bins (5) et la distribution est floue ; trop de bins (50) et le
graphique devient bruité. La règle de Sturges donne 𝑘 = ⌈1 + log2 𝑛⌉ comme point de
départ.
7.2.2 Le diagramme en barres — comparer des catégories
Le diagramme en barres est l’outil de choix pour comparer des valeurs entre des catégories
discrètes : filières, villes, années, groupes. À la différence de l’histogramme, les barres ne
représentent pas des intervalles continus — elles représentent des catégories distinctes.
1 # Calculer la moyenne ET l'écart -type par filière
2 # . reset_index () transforme le groupby en DataFrame ordinaire
3 stats = df. groupby (" filiere ")[" moyenne "]. agg (["mean",
"std"]). reset_index ()
4 stats. columns = [" filiere ", " moyenne ", " ecart_type "]
5
6 fig , ax = plt. subplots ( figsize =(10 , 5))
7
8 bars = [Link](
9 stats [" filiere "], # caté gories sur l'axe x
10 stats [" moyenne "], # hauteur des barres
11 yerr= stats [" ecart_type "], # barres d'erreur (± 1 écart -type)
12 color =[" steelblue ","coral "," mediumseagreen "," mediumpurple "],
13 edgecolor =" white",
Python pour la Data Science — Ibrahima SY
58 CHAPITRE 7. VISUALISATION DE DONNÉES
14 capsize =5 # petits chapeaux horizontaux sur
les barres d'erreur
15 )
16
17 # Ajouter la valeur numérique au - dessus de chaque barre
18 # bar.get_x () + bar. get_width () /2 = centre horizontal de la barre
19 # bar. get_height () = hauteur (la valeur ) de la barre
20 for bar , val in zip(bars , stats [" moyenne "]):
21 [Link](
22 bar. get_x () + bar. get_width ()/2,
23 bar. get_height () + 0.2 ,
24 f"{val :.1f}",
25 ha=" center ", va=" bottom ", fontsize =11
26 )
27
28 ax. set_ylim (0, 22)
29 ax. set_title (" Moyenne par filière (± écart -type)")
30 ax. set_xlabel ("Filière")
31 ax. set_ylabel (" Moyenne / 20")
32 # axhline = " horizontal line" à la valeur y spécifiée
33 ax. axhline (10 , color ="red", linestyle ="--", alpha =0.5 ,
label ="Seuil d'admission ")
34 ax. legend ()
35 plt. tight_layout ()
36 [Link] ()
7.2.3 Le scatter plot — révéler les relations entre variables
Le scatter plot (nuage de points) place chaque observation comme un point dans un espace
à deux dimensions. C’est le graphique indispensable pour voir si deux variables numériques
sont liées : plus les points forment un nuage allongé, plus la corrélation est forte.
1 fig , ax = plt. subplots ( figsize =(9 , 6))
2
3 # Attribuer une couleur par filière
4 colors = {"Info": " steelblue ", "Maths ": "coral ",
5 " Physique ": " mediumseagreen ", " Chimie ": " mediumpurple "}
6
7 # Tracer un nuage de points par filière (pour avoir la légende
par couleur )
8 for filiere , groupe in df. groupby (" filiere "):
9 ax. scatter (
10 groupe [" note_maths "], # axe x : note de maths
11 groupe [" note_info "], # axe y : note d'info
12 color = colors .get(filiere , "gray"),
13 label =filiere ,
14 alpha =0.7 , # transparence pour voir les
superpositions
15 s=80 # taille des points (s = size)
16 )
17
Python pour la Data Science — Ibrahima SY
7.2. LES GRAPHIQUES FONDAMENTAUX 59
18 # Ajouter une droite de tendance
19 # np. polyfit (x, y, 1) calcule les coefficients d'une droite
(degré 1) par moindres carrés
20 x = df[" note_maths "]. dropna ()
21 y = [Link][[Link] , " note_info "]. dropna ()
22 x_clean = x[x. index .isin(y. index )]
23 y_clean = y[y. index .isin(x. index )]
24 coefficients = np. polyfit (x_clean , y_clean , 1)
25 droite = np. poly1d ( coefficients ) # crée une fonction
polynomiale
26 x_ligne = np. linspace ( x_clean .min () , x_clean .max () , 100)
27 [Link](x_ligne , droite ( x_ligne ), "k--", alpha =0.5 ,
label =" Tendance ")
28
29 ax. set_title ("Note Maths vs Note Info")
30 ax. set_xlabel ("Note Maths / 20")
31 ax. set_ylabel ("Note Info / 20")
32 ax. legend ()
33 ax. set_xlim (0, 21)
34 ax. set_ylim (0, 21)
35 plt. tight_layout ()
36 [Link] ()
INFO-CIRCLE Note
La droite de tendance donne le sens, pas la force. Si la droite monte de gauche à
droite, la corrélation est positive. Mais une droite bien ajustée sur un nuage très dispersé
peut indiquer une corrélation faible (r = 0.3) tout comme un nuage serré peut indiquer
une corrélation forte (r = 0.9). Pour connaître la force, calculez 𝑟 avec [Link]().
7.2.4 Le boxplot — comparer les distributions en un coup d’œil
Le boxplot (boîte à moustaches) est un résumé visuel de cinq statistiques : le minimum, le
premier quartile 𝑄1 , la médiane, le troisième quartile 𝑄3 , et le maximum. Les points au-delà
des moustaches sont les valeurs aberrantes.
1 fig , ax = plt. subplots ( figsize =(10 , 6))
2
3 # Pré parer une liste de tableaux NumPy , un par filière
4 filieres = df[" filiere "]. dropna (). unique ()
5 data_par_filiere = [
6 df[df[" filiere "] == f][" moyenne "]. dropna (). values
7 for f in filieres
8 ]
9
10 # patch_artist =True : remplit les boîtes avec de la couleur
(sinon contours seulement )
11 # medianprops : personnalise la ligne médiane
12 bp = ax. boxplot (
13 data_par_filiere ,
14 labels =filieres ,
Python pour la Data Science — Ibrahima SY
60 CHAPITRE 7. VISUALISATION DE DONNÉES
15 patch_artist =True ,
16 medianprops =dict( color ="red", linewidth =2)
17 )
18
19 # Colorier chaque boîte
20 colors_box = [" steelblue ", "coral ", " mediumseagreen ",
" mediumpurple "]
21 for patch , color in zip(bp["boxes "], colors_box ):
22 patch . set_facecolor ( color )
23 patch . set_alpha (0.7)
24
25 ax. set_title (" Distribution des moyennes par filière")
26 ax. set_ylabel (" Moyenne / 20")
27 ax. axhline (10 , color ="red", linestyle ="--", alpha =0.4 ,
label ="Seuil d'admission ")
28 ax. legend ()
29 plt. tight_layout ()
30 [Link] ()
LIGHTBULB Astuce
Boxplot vs Histogramme : quand préférer lequel ? L’histogramme montre la forme
complète d’une distribution (modes, asymétrie). Le boxplot est meilleur pour comparer
plusieurs groupes simultanément — il condense l’information en peu d’espace. Si
vous avez 10 filières à comparer, 10 boxplots côte à côte sont bien plus lisibles que 10
histogrammes superposés.
7.3 Seaborn : la visualisation statistique simplifiée
BOOK Concept : Seaborn
Seaborn est une bibliothèque construite au-dessus de Matplotlib. Elle ne le remplace
pas — elle le complète. Seaborn s’interface directement avec les DataFrames Pandas :
au lieu de passer des tableaux NumPy, on passe le nom des colonnes. Elle applique au-
tomatiquement des palettes soignées et calcule des statistiques (intervalles de confiance,
courbes KDE) à la volée.
La relation entre Matplotlib et Seaborn est similaire à celle entre NumPy et Pandas :
Matplotlib est plus bas niveau et plus puissant, Seaborn est plus haut niveau et plus rapide
pour les usages statistiques courants. Dans la pratique, on les utilise ensemble : Seaborn pour
le graphique principal, Matplotlib pour les ajustements fins.
1 import seaborn as sns
2
3 # Définir le thème global de Seaborn
4 # style =" whitegrid " : fond blanc avec grille horizontale
5 # palette =" muted" : couleurs douces et distinctes
6 sns. set_theme ( style =" whitegrid ", palette ="muted ")
7
Python pour la Data Science — Ibrahima SY
7.3. SEABORN : LA VISUALISATION STATISTIQUE SIMPLIFIÉE 61
8 fig , axes = plt. subplots (2, 2, figsize =(14 , 10))
9 # plt. subplots (2, 2) crée une grille 2×2 : axes[ligne , colonne ]
10
11 # �� 1. Heatmap de corré lation �����������������������������������������������
12 # La heatmap colore chaque cellule selon la valeur de la
corré lation
13 # annot =True : affiche les valeurs numé riques dans chaque cellule
14 # cmap =" coolwarm " : bleu (négatif ) → blanc (zéro) → rouge
( positif )
15 # center =0 : le blanc est centr é sur zéro
16 cols = [" note_maths ", " note_info ", " note_anglais ", " moyenne "]
17 corr = df[cols ]. corr ()
18 sns. heatmap (corr , annot =True , fmt=".2f", cmap=" coolwarm ",
19 center =0, ax=axes [0, 0])
20 axes [0, 0]. set_title (" Matrice de corré lation ")
21
22 # �� 2. Violin plot �����������������������������������������������������������
23 # Le violin plot combine boxplot + courbe de densit é (KDE)
24 # Il montre la forme de la distribution , pas seulement les
quartiles
25 # data=df : Seaborn lit directement le DataFrame
26 # x=" filiere " : colonne caté gorielle sur l'axe x
27 # y=" moyenne " : colonne numérique sur l'axe y
28 sns. violinplot (data=df , x=" filiere ", y=" moyenne ",
29 palette ="muted ", ax=axes [0, 1])
30 axes [0, 1]. set_title (" Distribution par filière ( violin )")
31 axes [0, 1]. axhline (10 , color ="red", linestyle ="--", alpha =0.5)
32
33 # �� 3. Scatter avec encodage multi - variable ��������������������������������
34 # hue =" filiere " : une couleur par filière
35 # size =" moyenne " : la taille du point encode la moyenne générale
36 # Les deux encodages simultan és révèlent trois dimensions d'un
coup
37 sns. scatterplot (data=df , x=" note_maths ", y=" note_info ",
38 hue=" filiere ", size=" moyenne ",
39 palette =" muted ", ax=axes [1, 0])
40 axes [1, 0]. set_title ("Maths vs Info ( taille = moyenne générale)")
41
42 # �� 4. Courbes de densit é (KDE) ���������������������������������������������
43 # kdeplot trace la courbe de densit é de probabilit é estim ée
( Kernel Density Estimate )
44 # fill=True : remplit sous la courbe (plus lisible )
45 # alpha =0.2 : semi - transparent pour voir les superpositions
46 for filiere in df[" filiere "]. dropna (). unique ():
47 sous = df[df[" filiere "] == filiere ][" moyenne "]. dropna ()
48 sns. kdeplot (sous , ax=axes [1, 1], fill=True , alpha =0.2 ,
label = filiere )
49 axes [1, 1]. set_title (" Densit é des moyennes par filière")
50 axes [1, 1]. set_xlabel (" Moyenne ")
51 axes [1, 1]. legend ()
52
Python pour la Data Science — Ibrahima SY
62 CHAPITRE 7. VISUALISATION DE DONNÉES
53 plt. tight_layout ()
54 plt. savefig (" dashboard_eda .png", dpi =150 , bbox_inches ="tight ")
55 [Link] ()
INFO-CIRCLE Note
Le violin plot est supérieur au boxplot quand la distribution est multimodale. Si
une filière a deux groupes d’étudiants bien distincts (par exemple un groupe fort et
un groupe faible), le boxplot montrera juste une boîte large, alors que le violin plot
révélera deux “ventres” dans la courbe.
7.4 Quel graphique pour quelle question ?
La visualisation n’est pas une question de préférence esthétique : c’est un choix analytique.
Chaque type de graphique répond à un type de question précis. Voici le guide de décision :
Question posée Type de graphique Fonction
Quelle est la distribution d’une Histogramme hist()
variable ?
Quelle est la forme lissée de la Courbe KDE kdeplot()
distribution ?
Comment comparer plusieurs Boxplot ou Violin boxplot()
groupes ?
Existe-t-il une relation entre Scatter plot scatter()
deux variables ?
Quelles sont les valeurs par ca- Barres bar()
tégorie ?
Comment évoluent les valeurs Courbe plot()
dans le temps ?
Quelles sont toutes les corréla- Heatmap heatmap()
tions ?
Quelle est la proportion de Barres empilées bar(stacked=True)
chaque catégorie ?
Python pour la Data Science — Ibrahima SY
7.5. RÉCAPITULATIF 63
Exclamation-Triangle Attention
Trois erreurs classiques de visualisation à éviter.
1. Axe y tronqué : si l’axe y commence à 10 au lieu de 0 sur un diagramme en barres,
une différence de 10% paraît énorme. Toujours démarrer à 0 pour les barres.
2. Trop d’information : un graphique qui essaie de tout dire ne dit rien. Un graphique
= une idée.
3. Oublier les labels : un graphique sans titre et sans unités sur les axes oblige le
lecteur à deviner. C’est une question de rigueur scientifique.
7.5 Récapitulatif
Key À retenir
Ce que vous devez retenir
— Matplotlib : fig, ax = [Link]() crée la figure et ses axes. Matplotlib
donne un contrôle total mais demande plus de code.
— Seaborn s’interfasce directement avec les DataFrames :
[Link](data=df, x="filiere", y="moyenne").
— Toujours habiller : set_title(), set_xlabel(), set_ylabel(), legend().
— plt.tight_layout() évite les chevauchements ; [Link]() enregistre.
— Histogramme = distribution d’une variable ; Boxplot = comparaison de groupes.
— Scatter = relation entre deux variables numériques.
— Heatmap = vue d’ensemble des corrélations.
— Violin plot = boxplot + forme de la distribution.
Python pour la Data Science — Ibrahima SY
Troisième partie
Vers le Machine Learning
64
Chapitre 8
Préparation des données pour le Machine
Learning
◎ Objectifs du chapitre
— Comprendre la règle fondamentale train/test et le concept de data leakage
— Normaliser et standardiser correctement les variables numériques
— Encoder les variables catégorielles (Label, One-Hot)
— Assembler un pipeline de préparation complet et reproductible
Il y a une règle d’or en Machine Learning, résumée par l’expression anglaise : garbage
in, garbage out. Si vous alimentez un algorithme avec des données mal préparées — des
notes sur des échelles différentes, des filières encodées avec des entiers qui suggèrent un
ordre inexistant, des paramètres calculés sur les données de test — votre modèle produira de
mauvaises prédictions, peu importe sa sophistication.
Ce chapitre traite de la phase qui précède tout entraînement : la préparation des données.
C’est une phase ingrate, invisible dans les résultats finaux, mais qui conditionne absolument
tout ce qui suit.
8.1 La séparation train / test : la règle fondamentale
BOOK Concept : Train / Test Split
Avant d’entraîner tout modèle, on divise le dataset en deux parties étanches :
— Ensemble d’entraînement (train, 70–80%) : données sur lesquelles le modèle
apprend les patterns.
— Ensemble de test (test, 20–30%) : données jamais vues pendant l’entraînement.
Elles servent uniquement à évaluer les performances réelles.
Cette séparation simule la situation réelle : le modèle sera un jour confronté à des
données qu’il n’a jamais vues.
Pourquoi cette règle est-elle si stricte ? Imaginez un étudiant qui révise sur les sujets
d’examen de l’année passée, puis est évalué sur ces mêmes sujets. Il aura l’air excellent,
mais vous ne saurez pas s’il a vraiment compris ou s’il a simplement mémorisé les réponses.
65
66 CHAPITRE 8. PRÉPARATION DES DONNÉES POUR LE MACHINE LEARNING
En ML, évaluer un modèle sur ses données d’entraînement donne un score optimiste trom-
peur : le modèle a “mémorisé” les données. On appelle ce phénomène le surapprentissage
(overfitting).
1 import pandas as pd
2 import numpy as np
3 from sklearn . model_selection import train_test_split
4
5 df = pd. read_csv (" eleves .csv")
6 df[" moyenne "] =
df[[" note_maths "," note_info "," note_anglais "]]. mean(axis =1)
7
8 # Supprimer les lignes où la cible est manquante (on ne peut pas
entra îner sans cible )
9 df = df. dropna ( subset =["admis "])
10
11 # �� Étape 1 : sé parer les features (X) de la cible (y) ��������������������
12 # Convention : X est la matrice d'entrée, y est le vecteur cible
13 # Ici : prédire si un é tudiant est admis à partir de ses notes et
son âge
14 X = df[[" note_maths ", " note_info ", " note_anglais ", "age"]]
15 y = df["admis "] # variable cible : True/False (ou 1/0)
16
17 # �� Étape 2 : split 80/20 �������������������������������������������������
18 X_train , X_test , y_train , y_test = train_test_split (
19 X, y,
20 test_size =0.2 , # 20% des données vont dans le test
21 random_state =42 , # graine alé atoire : garantit qu 'on
obtient le même split
22 # à chaque exé cution ( essentiel pour la
reproductibilit é)
23 stratify =y # conserve la proportion d'admis /non -admis
dans chaque partie
24 # sans ça , le split alé atoire pourrait
mettre tous les
25 # non - admis dans le test par malchance
26 )
27
28 print (f"Train : {len( X_train )} exemples ")
29 print (f"Test : {len( X_test )} exemples ")
30 print (f"Admis dans train : { y_train .mean () :.1%} ")
31 print (f"Admis dans test : { y_test .mean () :.1%} ") # les
proportions sont identiques
1 Train : 80 exemples
2 Test : 20 exemples
3 Admis dans train : 72.5%
4 Admis dans test : 72.5%
Python pour la Data Science — Ibrahima SY
8.2. LA MISE À L’ÉCHELLE : POURQUOI ET COMMENT 67
Exclamation-Triangle Attention
Le data leakage : l’erreur la plus courante et la plus grave. Le data leakage (fuite
de données) se produit quand des informations des données de test “contaminent” la
préparation du train.
L’erreur classique : calculer la moyenne et l’écart-type sur tout le dataset (train + test),
puis normaliser les données.
Mauvais : [Link](X) puis [Link](X_train) et
[Link](X_test)
Correct : [Link](X_train) puis [Link](X_train) et
[Link](X_test)
La règle absolue : le scaler (ou tout autre preprocesseur) doit apprendre (fit) unique-
ment sur le train, puis appliquer (transform) sur les deux.
8.2 La mise à l’échelle : pourquoi et comment
BOOK Concept : Mise à l’échelle (Feature Scaling)
La mise à l’échelle transforme les variables numériques pour les ramener à une plage
comparable. C’est nécessaire pour tous les algorithmes qui calculent des distances ou
des gradients : régression logistique, SVM, KNN, réseaux de neurones.
Pour comprendre pourquoi c’est nécessaire, imaginez un dataset avec deux variables :
l’âge (entre 18 et 25 ans, variation de 7 unités) et le revenu (entre 500 000 et 5 000 000
FCFA, variation de 4 500 000 unités). Un algorithme qui calcule des distances traitera la
variable revenu comme presque infiniment plus importante que l’âge — pas parce qu’elle
l’est réellement, mais parce qu’elle a une plage beaucoup plus grande. La mise à l’échelle
corrige cette asymétrie.
Méthode Formule Résultat À utiliser si
𝑥−𝜇
Standardisation 𝑧= ≈ 𝒩(0, 1) Distribution normale
𝜎
(Z-score) (cas le plus courant)
𝑥 − 𝑥min
Normalisation 𝑥′ = [0, 1] Distribution quel-
𝑥max − 𝑥min
(Min-Max) conque
mais peu d’outliers
𝑥 − 𝑄2
Robust Scaler Centré, ro- Beaucoup d’outliers
IQR
buste
1 from sklearn . preprocessing import StandardScaler , MinMaxScaler ,
RobustScaler
2
3 # �� StandardScaler : moyenne = 0, écart -type = 1 ��������������������������
4 scaler = StandardScaler ()
5
Python pour la Data Science — Ibrahima SY
68 CHAPITRE 8. PRÉPARATION DES DONNÉES POUR LE MACHINE LEARNING
6 # fit_transform = fit () puis transform () en une seule étape
7 # fit () : calcule la moyenne et l'écart -type de chaque colonne
sur X_train
8 # transform () : applique la transformation z = (x - mu) / sigma
9 X_train_scaled = scaler . fit_transform ( X_train )
10
11 # Sur le test : UNIQUEMENT transform () , pas fit_transform ()
12 # On utilise les paramètres (mu , sigma ) calcul és sur le train
13 X_test_scaled = scaler . transform ( X_test )
14
15 # Vé rifier la transformation
16 X_train_df = pd. DataFrame ( X_train_scaled , columns = X_train . columns )
17 print (" Moyenne par colonne (doit être ~0) :")
18 print ( X_train_df .mean (). round (3))
19 print ("Écart -type par colonne (doit être ~1) :")
20 print ( X_train_df .std (). round (3))
21
22 # �� MinMaxScaler : toutes les valeurs dans [0, 1] �������������������������
23 mm_scaler = MinMaxScaler ()
24 X_train_mm = mm_scaler . fit_transform ( X_train ) # min et max
calcul és sur le train
25 X_test_mm = mm_scaler . transform ( X_test )
26
27 # �� Inverser la transformation : retrouver les valeurs originales
����������
28 # Très utile pour interpr éter les pré dictions dans l'espace
original
29 X_original = scaler . inverse_transform ( X_train_scaled )
1 Moyenne par colonne (doit être ~0) :
2 note_maths 0.0
3 note_info 0.0
4 note_anglais 0.0
5 age 0.0
6
7 Écart -type par colonne (doit être ~1) :
8 note_maths 1.0
9 note_info 1.0
10 note_anglais 1.0
11 age 1.0
INFO-CIRCLE Note
Tous les algorithmes ne nécessitent pas la mise à l’échelle. Les arbres de décision
(Random Forest, Gradient Boosting) utilisent des seuils sur les valeurs brutes — ils sont
insensibles à l’échelle. La régression linéaire, SVM, KNN, et les réseaux de neurones,
eux, en ont absolument besoin. En cas de doute, standardisez — ça ne peut pas nuire.
Python pour la Data Science — Ibrahima SY
8.3. L’ENCODAGE DES VARIABLES CATÉGORIELLES 69
8.3 L’encodage des variables catégorielles
BOOK Concept : Encodage (Encoding)
Un algorithme ML ne comprend que les nombres. Il est incapable de calculer la
distance entre “Info” et “Maths”. L’encodage est la transformation des catégories en
représentations numériques exploitables par les algorithmes.
Il existe plusieurs stratégies d’encodage, et le choix dépend crucialmente de la nature de
la variable catégorielle.
8.3.1 L’encodage ordinal (Label Encoding)
Le Label Encoding remplace chaque catégorie par un entier : 0, 1, 2, 3…Cette approche
n’est adaptée que pour les variables ordinales, c’est-à-dire les variables où il existe un ordre
naturel entre les catégories.
Exemple : la mention est ordinale — “Passable” est inférieur à “Assez Bien”, qui est
inférieur à “Bien”, qui est inférieur à “Très Bien”. Attribuer 0, 1, 2, 3 à ces catégories préserve
cet ordre et l’algorithme peut en tirer parti.
1 from sklearn . preprocessing import LabelEncoder
2
3 df_prep = [Link] ()
4
5 # LabelEncoder trie les caté gories par ordre alphab étique et leur
attribue 0, 1, 2...
6 le = LabelEncoder ()
7 df_prep [" mention_enc "] =
le. fit_transform ( df_prep [" mention "]. fillna (" Ajourn é"))
8
9 # Voir la correspondance caté gorie -> entier
10 correspondance = dict(zip(le.classes_ , le. transform (le. classes_ )))
11 print (" Correspondance mention -> entier :")
12 print ( correspondance )
1 Correspondance mention -> entier :
2 {'Ajourn é': 0, 'Assez Bien ': 1, 'Bien ': 2, 'Passable ': 3, 'Très
Bien ': 4}
Exclamation-Triangle Attention
Ne jamais utiliser le Label Encoding pour les variables nominales. Si on encode la
filière avec Label Encoding : Info=0, Maths=1, Physique=2. L’algorithme va “lire” :
Physique (2) = 2 × Info (1). Ce qui est mathématiquement absurde — une filière n’est
pas “deux fois” une autre. Pour les variables nominales (sans ordre), il faut le One-Hot
Encoding.
Python pour la Data Science — Ibrahima SY
70 CHAPITRE 8. PRÉPARATION DES DONNÉES POUR LE MACHINE LEARNING
8.3.2 L’encodage One-Hot (variables nominales)
Le One-Hot Encoding crée une nouvelle colonne binaire (0 ou 1) pour chaque catégorie.
Si la variable “filiere” a 4 valeurs possibles, on crée 4 nouvelles colonnes : filiere_Info,
filiere_Maths, filiere_Physique, filiere_Chimie. Pour chaque étudiant, exactement
une de ces colonnes vaut 1 — les autres valent 0.
1 # �� Mé thode Pandas : pd. get_dummies () �������������������������������������
2 # C'est la mé thode la plus simple pour le One -Hot Encoding
3 # prefix =" filiere " : préfixe les nouveaux noms de colonnes
4 dummies = pd. get_dummies ( df_prep [" filiere "], prefix =" filiere ")
5 print ( dummies .head (3))
1 filiere_Chimie filiere_Info filiere_Maths filiere_Physique
2 0 0 1 0 0
3 1 0 0 1 0
4 2 1 0 0 0
1 # Fusionner les nouvelles colonnes avec le DataFrame original
2 # axis =1 : concat éner horizontalement ( ajouter des colonnes , pas
des lignes )
3 df_encode = pd. concat ([ df_prep , dummies ], axis =1)
4 # Supprimer la colonne originale , maintenant inutile
5 df_encode = df_encode .drop( columns =[" filiere "])
6
7 # �� drop_first =True : éviter la multi -colin éarité �������������������������
8 # Si on a 4 filières et 4 colonnes binaires , la derni ère colonne
est toujours
9 # dé ductible des 3 autres (si les 3 sont 0, c'est forcément la
4e).
10 # Cette redondance (multi -colin éarité) peut perturber certains
algorithmes .
11 # drop_first =True supprime la premi ère catégorie pour é liminer ce
probl ème.
12 dummies = pd. get_dummies ( df_prep [" filiere "], prefix ="fil",
drop_first =True)
13 print (" Colonnes créées avec drop_first =True :",
dummies . columns . tolist ())
1 Colonnes créées avec drop_first =True : ['fil_Info ', 'fil_Maths ',
'fil_Physique ']
8.4 Le pipeline de préparation complet
Maintenant que vous connaissez les différentes étapes, voici comment les assembler en
un pipeline de préparation complet, ordonné et reproductible. C’est le code que vous écrirez
au début de tout projet ML.
1 import pandas as pd
2 import numpy as np
Python pour la Data Science — Ibrahima SY
8.4. LE PIPELINE DE PRÉPARATION COMPLET 71
3 from sklearn . model_selection import train_test_split
4 from sklearn . preprocessing import StandardScaler
5
6 # �� Étape 1 : Charger le dataset ������������������������������������������
7 df = pd. read_csv (" eleves .csv")
8 df[" moyenne "] =
df[[" note_maths "," note_info "," note_anglais "]]. mean(axis =1)
9
10 # �� Étape 2 : Nettoyer ( imputer les NaN) ����������������������������������
11 # On ne peut pas entraîner si la cible est manquante -> supprimer
ces lignes
12 df = df. dropna ( subset =["admis "])
13
14 # Pour les features : remplacer par la médiane ( robuste aux
outliers )
15 df[" note_maths "] =
df[" note_maths "]. fillna (df[" note_maths "]. median ())
16 df[" note_info "] =
df[" note_info "]. fillna (df[" note_info "]. median ())
17 df[" note_anglais "] =
df[" note_anglais "]. fillna (df[" note_anglais "]. median ())
18
19 # �� Étape 3 : Encoder les variables caté gorielles �������������������������
20 # One -Hot sur la filière ( variable nominale )
21 dummies = pd. get_dummies (df[" filiere "], prefix ="fil",
drop_first =True)
22 df = pd. concat ([df , dummies ], axis =1)
23
24 # �� Étape 4 : Sé lectionner les features utiles ����������������������������
25 features = [" note_maths ", " note_info ", " note_anglais ", "age"] \
26 + list( dummies . columns )
27 X = df[ features ]. astype ( float ) # s'assurer que tout est
numérique
28 y = df["admis "]. astype (int) # 1 = admis , 0 = non admis
29
30 # �� Étape 5 : Sé parer train / test ����������������������������������������
31 X_train , X_test , y_train , y_test = train_test_split (
32 X, y, test_size =0.2 , random_state =42 , stratify =y
33 )
34
35 # �� Étape 6 : Standardiser (fit sur train , transform sur les
deux) ���������
36 scaler = StandardScaler ()
37 X_train_sc = scaler . fit_transform ( X_train ) # apprend mu/sigma +
transforme
38 X_test_sc = scaler . transform ( X_test ) # applique mu/sigma
du train seulement
39
40 print (f"Train prêt : { X_train_sc .shape }")
41 print (f"Test prêt : { X_test_sc .shape }")
42 print ("Données prêtes pour le modèle !")
Python pour la Data Science — Ibrahima SY
72 CHAPITRE 8. PRÉPARATION DES DONNÉES POUR LE MACHINE LEARNING
1 Train prêt : (80 , 6)
2 Test prêt : (20 , 6)
3 Données prêtes pour le modèle !
STAR Bonne pratique
L’ordre des étapes est fixe et non négociable.
1. Charger les données
2. Nettoyer (NaN, doublons)
3. Encoder les catégorielles
4. Séparer train/test
5. Scaler (fit uniquement sur train)
En particulier, le split doit toujours venir avant le scaling. Inverser ces deux étapes est
la définition du data leakage.
8.5 Récapitulatif
Key À retenir
Ce que vous devez retenir
— X = features (entrées) ; y = cible (sortie). Séparer avant toute transformation.
— train_test_split(X, y, test_size=0.2, random_state=42,
stratify=y).
— Règle absolue : scaler.fit_transform(X_train) puis
[Link](X_test).
— Label Encoding pour les variables ordinales (ordre naturel).
— One-Hot Encoding pour les variables nominales (pas d’ordre). Utiliser
pd.get_dummies(df["col"], drop_first=True).
— L’ordre des étapes est : nettoyer → encoder → split → scaler.
— Data leakage = calculer les paramètres de normalisation sur train+test. À éviter
absolument.
Python pour la Data Science — Ibrahima SY
Chapitre 9
Introduction aux pipelines de Data Science
◎ Objectifs du chapitre
— Comprendre le workflow complet d’un projet Data Science
— Utiliser [Link] pour enchaîner les étapes de façon sécu-
risée
— Entraîner un premier modèle et interpréter ses métriques d’évaluation
— Comparer plusieurs algorithmes de façon rigoureuse avec la validation croisée
Imaginez une chaîne de montage automobile. Chaque station effectue une transformation
précise : d’abord la carrosserie, puis la motorisation, puis l’intérieur, puis la peinture. L’ordre
est fixé, chaque étape prend l’output de la précédente, et le processus est reproductible à
l’identique pour chaque voiture.
C’est exactement ce qu’est un pipeline de Data Science. Jusqu’ici, chaque étape — net-
toyage, encodage, normalisation, modèle — était écrite séparément dans des cellules indépen-
dantes. Ce fonctionnement est pratique pour l’exploration, mais fragile : il suffit d’oublier une
cellule ou d’exécuter dans le mauvais ordre pour introduire un bug subtil (data leakage) ou
obtenir des résultats non reproductibles.
Le Pipeline Scikit-learn résout ce problème en encapsulant toutes les étapes en un objet
unique, cohérent et sécurisé.
9.1 Le workflow d’un projet Data Science
Avant d’écrire une ligne de code, il est utile de comprendre l’enchaînement complet des
étapes d’un projet de Data Science. Ce workflow est universel — il s’applique à n’importe
quel projet, de la prédiction d’admissions étudiantes à la détection de fraudes bancaires.
Collecte Nettoyage Préparation Entraîne- Évalua-
données EDA features ment tion
itérer
Dans la pratique, ce workflow n’est jamais linéaire. L’évaluation révèle souvent que le
modèle manque d’une feature importante, ou que les données d’une catégorie sont trop rares.
73
74 CHAPITRE 9. INTRODUCTION AUX PIPELINES DE DATA SCIENCE
On revient alors à la préparation, on améliore, on ré-entraîne. Ce cycle d’itération est au cœur
du travail de Data Scientist.
9.2 Scikit-learn : l’interface unifiée
BOOK Concept : Scikit-learn
Scikit-learn est la bibliothèque de Machine Learning de référence en Python. Elle
implémente des dizaines d’algorithmes (classification, régression, clustering, réduction
de dimension) avec une interface identique pour tous :
— fit(X_train, y_train) : entraîner le modèle sur les données
— predict(X_test) : faire des prédictions sur de nouvelles données
— score(X_test, y_test) : évaluer les performances (accuracy par défaut)
Cette uniformité est un atout majeur : apprendre à utiliser un algorithme, c’est apprendre
à utiliser tous les autres.
1 from sklearn .tree import DecisionTreeClassifier
2 from sklearn . metrics import accuracy_score , classification_report
3
4 # Hypoth èse : X_train_sc , X_test_sc , y_train , y_test ont été
préparés
5 # comme dans le chapitre précédent
6
7 # �� Entraîner un arbre de dé cision ����������������������������������������
8 # max_depth : limite la profondeur de l'arbre (évite le
surapprentissage )
9 # random_state : pour la reproductibilit é
10 modele = DecisionTreeClassifier ( max_depth =5, random_state =42)
11 modele .fit( X_train_sc , y_train ) # le modèle apprend les patterns
12
13 # �� Prédire ��������������������������������������������������������������
14 y_pred = modele . predict ( X_test_sc )
15
16 # �� Évaluer ��������������������������������������������������������������
17 print (f" Accuracy : { accuracy_score (y_test , y_pred ):.2%} ")
18 print ( classification_report (y_test , y_pred ,
19 target_names =["Non admis ", "Admis "]))
1 Accuracy : 87.50%
2 precision recall f1 - score support
3 Non admis 0.82 0.75 0.78 8
4 Admis 0.90 0.93 0.92 15
5 accuracy 0.88 23
Pour interpréter ce rapport, il faut comprendre les quatre métriques :
Python pour la Data Science — Ibrahima SY
9.3. LE PIPELINE SCIKIT-LEARN : ENCHAÎNER LES ÉTAPES EN TOUTE SÉCURITÉ 75
Métrique Signification Quand l’utiliser
Accuracy % de prédictions cor- Classes équilibrées
rectes
Précision Parmi les prédits posi- Quand les faux positifs coûtent
tifs, combien sont vrais ? cher
Rappel Parmi les vrais positifs, Quand les faux négatifs
combien détecte-t-on ? coûtent cher
F1-score Moyenne harmonique Classes déséquilibrées
précision/rappel
INFO-CIRCLE Note
Précision vs Rappel : un exemple médical. Imaginez un modèle de détection de
cancer.
Faux négatif : on prédit “pas de cancer” alors qu’il y en a un — le patient n’est pas
traité, c’est dramatique. Ici, on veut maximiser le rappel (détecter tous les malades).
Faux positif : on prédit “cancer” alors qu’il n’y en a pas — le patient subit un traitement
inutile. Ici, on veut maximiser la précision (n’alerter que quand on est sûr).
Le F1-score fait le compromis entre les deux. L’accuracy seule est trompeuse : un
modèle qui prédit toujours “pas de cancer” aura 95% d’accuracy si seulement 5% des
patients sont malades, tout en ayant un rappel de 0.
9.3 Le Pipeline Scikit-learn : enchaîner les étapes en toute
sécurité
BOOK Concept : Pipeline
Un Pipeline Scikit-learn est un objet qui enchaîne une séquence d’étapes. Chaque étape
reçoit la sortie de la précédente. Les premières étapes sont des transformateurs (ils
modifient les données sans produire de prédictions) ; la dernière étape est un estimateur
(le modèle ML).
L’avantage fondamental : appeler [Link](X_train, y_train) exécute au-
tomatiquement toutes les étapes dans l’ordre, et garantit que le fit() de chaque
transformateur utilise uniquement les données train.
1 import pandas as pd
2 import numpy as np
3 from sklearn . model_selection import train_test_split ,
cross_val_score
4 from sklearn . pipeline import Pipeline
5 from sklearn . preprocessing import StandardScaler
6 from sklearn . impute import SimpleImputer
7 from sklearn .tree import DecisionTreeClassifier
Python pour la Data Science — Ibrahima SY
76 CHAPITRE 9. INTRODUCTION AUX PIPELINES DE DATA SCIENCE
8 from sklearn . metrics import classification_report
9
10 # �� Préparer les données ��������������������������������������������������
11 df = pd. read_csv (" eleves .csv")
12 df[" moyenne "] =
df[[" note_maths "," note_info "," note_anglais "]]. mean(axis =1)
13 dummies = pd. get_dummies (df[" filiere "], prefix ="fil",
drop_first =True)
14 df = pd. concat ([df , dummies ], axis =1)
15
16 features = [" note_maths "," note_info "," note_anglais ","age"] +
list( dummies . columns )
17 X = df[ features ]. astype ( float )
18 y = df["admis "]. dropna (). astype (int)
19 X = [Link][y. index ] # aligner X et y après dropna
20
21 X_train , X_test , y_train , y_test = train_test_split (
22 X, y, test_size =0.2 , random_state =42 , stratify =y)
23
24 # �� Dé finir le Pipeline ���������������������������������������������������
25 # Chaque tuple = (" nom_étape", objet_transformateur_ou_estimateur )
26 # Le nom est libre (il servira pour la configuration des
hyperparam ètres)
27 pipeline = Pipeline ([
28 (" imputer ", SimpleImputer ( strategy =" median ")),
29 # SimpleImputer remplace les NaN par la médiane de chaque
colonne
30 # Calcul ée sur X_train uniquement ( garanti par le pipeline )
31
32 (" scaler ", StandardScaler ()),
33 # StandardScaler normalise chaque colonne : moyenne 0, é
cart -type 1
34 # Param ètres calcul és sur X_train uniquement
35
36 (" modele ", DecisionTreeClassifier ( max_depth =5,
random_state =42))
37 # L'estimateur final : l'arbre de dé cision
38 ])
39
40 # �� Entraîner le pipeline ��������������������������������������������������
41 # Une seule ligne dé clenche toutes les étapes en sé quence sur
X_train
42 pipeline .fit(X_train , y_train )
43
44 # �� Prédire sur le test ���������������������������������������������������
45 # Les transformations apprises sur train sont appliqu ées
automatiquement à X_test
46 y_pred = pipeline . predict ( X_test )
47
48 print (f" Accuracy test : { pipeline .score (X_test , y_test ):.2%} ")
49 print ( classification_report (y_test , y_pred ,
Python pour la Data Science — Ibrahima SY
9.4. LA VALIDATION CROISÉE : UNE ÉVALUATION ROBUSTE 77
50 target_names =["Non admis ", "Admis "]))
1 Accuracy test : 87.50%
2 precision recall f1 - score support
3 Non admis 0.82 0.75 0.78 8
4 Admis 0.90 0.93 0.92 15
5 accuracy 0.88 23
9.4 La validation croisée : une évaluation robuste
L’évaluation sur un seul split train/test a une limite : si par chance tous les exemples faciles
sont dans le test, le score sera artificiellement élevé. À l’inverse, si les exemples difficiles sont
dans le test, le score semblera trop bas.
La validation croisée 𝑘-fold résout ce problème en répétant l’évaluation 𝑘 fois sur des
splits différents :
1. Diviser le dataset en 𝑘 sous-ensembles (“folds”) de taille égale.
2. Pour chaque fold 𝑖 : entraîner sur les 𝑘 − 1 autres folds, évaluer sur le fold 𝑖.
3. La performance finale est la moyenne des 𝑘 scores.
Avec 𝑘 = 5 : chaque exemple est dans le test exactement une fois. Le score moyen est une
estimation bien plus fiable que le score sur un seul split.
1 # cross_val_score effectue toute la validation crois ée
automatiquement
2 # Il gère le pipeline correctement : le fit () de chaque étape
3 # est refait à chaque fold uniquement sur les données train de ce
fold
4 scores = cross_val_score (
5 pipeline , # le pipeline entier ( transformations +
modèle)
6 X, # toutes les données (X non - splitt é)
7 y, # toutes les cibles
8 cv=5, # 5-fold cross - validation
9 scoring ="f1" # mé trique d'é valuation : F1 -score
10 )
11
12 print (" Scores F1 par fold :", scores . round (3))
13 print (f"F1 moyen : { scores .mean () :.3f}")
14 print (f"Écart -type : { scores .std () :.3f}")
15 # Un écart -type élevé signale une forte variabilit é selon le
split -> instabilit é
1 Scores F1 par fold : [0.873 0.912 0.889 0.856 0.901]
2 F1 moyen : 0.886
3 Écart -type : 0.020
Python pour la Data Science — Ibrahima SY
78 CHAPITRE 9. INTRODUCTION AUX PIPELINES DE DATA SCIENCE
9.5 Comparer plusieurs modèles équitablement
L’intérêt du Pipeline est aussi de permettre des comparaisons équitables : chaque algo-
rithme reçoit les mêmes données, préparées de la même façon. Sans pipeline, il est trop facile
de faire varier involontairement les conditions entre deux modèles.
1 from sklearn . linear_model import LogisticRegression
2 from sklearn . neighbors import KNeighborsClassifier
3 from sklearn . ensemble import RandomForestClassifier
4
5 # Dictionnaire : nom -> algorithme
6 modeles = {
7 " Arbre de dé cision ":
8 DecisionTreeClassifier ( max_depth =5, random_state =42) ,
9 "Ré gression logistique ":
10 LogisticRegression ( max_iter =500 , random_state =42) ,
11 "K plus proches voisins ":
12 KNeighborsClassifier ( n_neighbors =5) ,
13 " Random Forest ":
14 RandomForestClassifier ( n_estimators =100 , random_state =42) ,
15 }
16
17 resultats = []
18 for nom , clf in modeles . items ():
19 # Créer un pipeline identique pour chaque algorithme
20 # Seule la dernière étape (le classificateur ) change
21 pipe = Pipeline ([
22 (" imputer ", SimpleImputer ( strategy =" median ")),
23 (" scaler ", StandardScaler ()),
24 (" modele ", clf)
25 ])
26 # Évaluer avec la validation crois ée 5-fold
27 scores = cross_val_score (pipe , X, y, cv=5, scoring ="f1")
28 resultats . append ({
29 "Modèle": nom ,
30 "F1 moyen ": round ( scores .mean () , 3) ,
31 "Écart -type": round ( scores .std () , 3)
32 })
33
34 # Trier par F1 dé croissant pour voir le meilleur modèle en premier
35 df_res = pd. DataFrame ( resultats ). sort_values ("F1 moyen ",
ascending = False )
36 print ( df_res . to_string ( index = False ))
1 Modèle F1 moyen Écart -type
2 Random Forest 0.924 0.021
3 Ré gression logistique 0.901 0.024
4 Arbre de dé cision 0.886 0.020
5 K plus proches voisins 0.865 0.031
Python pour la Data Science — Ibrahima SY
9.6. RÉCAPITULATIF 79
STAR Bonne pratique
Comment lire ce tableau ? Le Random Forest a le meilleur F1 moyen (0.924) et un
écart-type faible (0.021), ce qui signifie qu’il est à la fois performant et stable. Le
K plus proches voisins a un écart-type plus élevé (0.031) : ses performances varient
davantage selon le split — il est moins robuste sur ce dataset. En pratique, choisir le
modèle avec le meilleur rapport performance/stabilité.
9.6 Récapitulatif
Key À retenir
Ce que vous devez retenir
— Interface unifiée Scikit-learn : fit(), predict(), score(). Elle est identique
pour tous les algorithmes.
— Pipeline([("nom", étape), ...]) enchaîne les transformations et le modèle
en garantissant l’absence de data leakage.
— cross_val_score(pipeline, X, y, cv=5) donne une évaluation plus robuste
qu’un seul split. Un écart-type élevé signale une instabilité.
— Accuracy seule peut être trompeuse sur des classes déséquilibrées. Préférer le
F1-score.
— Comparer plusieurs modèles avec le même pipeline garantit une comparaison
équitable.
— Le cycle itératif du Data Science : préparer → entraîner → évaluer → améliorer.
Python pour la Data Science — Ibrahima SY
Chapitre 10
Projet Final — Étude de cas complète
◎ Objectifs du chapitre
— Appliquer toutes les compétences du cours sur un problème réel de bout en bout
— Structurer un notebook de Data Science professionnel et reproductible
— Comprendre le feature engineering et comment créer de nouvelles variables perti-
nentes
— Formuler des conclusions exploitables et des recommandations concrètes
Vous avez acquis, chapitre après chapitre, les outils du Data Scientist : Python, NumPy,
Pandas, la visualisation, la préparation des données et les pipelines. Il est temps de tout
assembler sur un projet complet, tel que vous en rencontrerez dans un contexte professionnel.
Voici le scénario : la direction pédagogique d’une université vous contacte. Elle a constaté
un taux d’échec préoccupant dans certaines filières et veut comprendre pourquoi — pas
intuitivement, mais avec des données. Elle vous soumet trois questions précises :
1. Quels sont les facteurs les plus fortement associés à l’échec académique ?
2. Existe-t-il des profils d’étudiants à risque identifiables dès le début du semestre ?
3. Peut-on construire un modèle capable de prédire, avec fiabilité, quels étudiants risquent
de ne pas valider ?
Ce chapitre vous guide à travers la réponse complète à ces trois questions.
10.1 La structure d’un notebook professionnel
Avant d’écrire la première ligne de code, tout projet Data Science doit suivre une structure
claire. Cette structure n’est pas arbitraire : elle garantit que votre travail est reproductible,
auditable et compréhensible par quelqu’un qui n’était pas dans votre tête quand vous l’avez
écrit.
1. Introduction : contexte métier, objectifs précis, hypothèses de départ
2. Chargement et aperçu : head(), info(), describe()
3. Nettoyage : valeurs manquantes, doublons, types incorrects
4. Feature Engineering : créer de nouvelles variables à partir des existantes
5. Analyse exploratoire (EDA) : statistiques, distributions, corrélations
80
10.2. ÉTAPE 1 — CHARGEMENT ET EXPLORATION INITIALE 81
6. Visualisations : graphiques commentés et orientés vers les questions métier
7. Modélisation : pipeline, entraînement, évaluation
8. Conclusions : réponses explicites aux questions initiales
9. Recommandations : actions concrètes pour le décideur
Cette structure ressemble à un rapport scientifique, et c’est intentionnel. Un Data Scientist
produit des preuves et des recommandations, pas seulement du code.
10.2 Étape 1 — Chargement et exploration initiale
La première chose à faire sur tout nouveau dataset est de l’examiner sans présupposé.
Combien de lignes ? Quelles colonnes ? Y a-t-il des valeurs manquantes ? Les types sont-ils
corrects ? Ces questions semblent basiques, mais leurs réponses orientent toutes les décisions
suivantes.
1 # �� Tous les imports en début de notebook ����������������������������������
2 import pandas as pd
3 import numpy as np
4 import matplotlib . pyplot as plt
5 import seaborn as sns
6 from sklearn . model_selection import train_test_split ,
cross_val_score
7 from sklearn . pipeline import Pipeline
8 from sklearn . preprocessing import StandardScaler
9 from sklearn . impute import SimpleImputer
10 from sklearn . ensemble import RandomForestClassifier
11 from sklearn . metrics import classification_report ,
ConfusionMatrixDisplay
12
13 # Thème visuel uniforme pour tous les graphiques
14 sns. set_theme ( style =" whitegrid ", palette ="muted ")
15 plt. rcParams [" figure . figsize "] = (12 , 5)
16
17 # �� Chargement ������������������������������������������������������������
18 df = pd. read_csv (" eleves .csv")
19 print (f" Dataset : {[Link] [0]} lignes × {[Link] [1]} colonnes ")
20 print ("\ nAperçu des 5 premi ères lignes :")
21 print ([Link] ())
22 print ("\ nTypes et valeurs manquantes :")
23 [Link] ()
24 print ("\ nStatistiques descriptives :")
25 print (df. describe (). round (2))
1 Dataset : 100 lignes × 8 colonnes
2
3 <class 'pandas .[Link] . DataFrame '>
4 RangeIndex : 100 entries , 0 to 99
5 Data columns ( total 8 columns ):
6 # Column Non -Null Count Dtype
7 --- ------ -------------- -----
Python pour la Data Science — Ibrahima SY
82 CHAPITRE 10. PROJET FINAL — ÉTUDE DE CAS COMPLÈTE
8 0 nom 100 non -null object
9 1 prenom 100 non -null object
10 2 age 100 non -null int64
11 3 filiere 100 non -null object
12 4 note_maths 95 non -null float64
13 5 note_info 100 non -null float64
14 6 note_anglais 100 non -null float64
15 7 admis 100 non -null bool
16 dtypes : bool (1) , float64 (3) , int64 (1) , object (3)
Premier constat : note_maths a 5 valeurs manquantes (95 non-null sur 100). Il faudra
les traiter. Les autres colonnes sont complètes. La variable cible admis est de type booléen
— on l’encodera en entier (0/1) avant la modélisation.
10.3 Étape 2 — Nettoyage systématique
Le nettoyage doit être documenté : noter combien de valeurs ont été modifiées et pourquoi.
Cette traçabilité est essentielle pour auditer l’analyse.
1 # �� Rapport qualit é des données ��������������������������������������������
2 print ("=== Valeurs manquantes ===")
3 print ((df. isnull ().sum () / len(df) * 100).round (1). to_string ())
4
5 print (f"\n=== Doublons : {df. duplicated ().sum ()} ===")
6
7 # �� Normaliser les chaînes de caract ères ����������������������������������
8 # Les noms en majuscules , les prénoms avec premi ère lettre
majuscule ,
9 # et on supprime les espaces parasites en début/fin de chaîne
10 df["nom"] = df["nom"]. str. upper ().str. strip ()
11 df[" prenom "] = df[" prenom "]. str. capitalize ().str. strip ()
12
13 # �� Imputation des valeurs manquantes �������������������������������������
14 # On choisit la médiane ( robuste aux outliers ) plutôt que la
moyenne
15 for col in [" note_maths ", " note_info ", " note_anglais "]:
16 n_nan = df[col ]. isnull ().sum ()
17 if n_nan > 0:
18 mediane = df[col ]. median ()
19 df[col] = df[col ]. fillna ( mediane )
20 print (f" {col} : { n_nan } NaN remplac és par la médiane
({ mediane :.1f})")
21
22 # �� Validation des plages ( contrainte métier : notes entre 0 et
20) ��������
23 print ("\n=== Validation des plages ===")
24 for col in [" note_maths ", " note_info ", " note_anglais "]:
25 hors = (( df[col] < 0) | (df[col] > 20)).sum ()
26 if hors:
27 print (f" ALERTE : {hors} valeurs hors [0, 20] dans
{col}")
Python pour la Data Science — Ibrahima SY
10.4. ÉTAPE 3 — FEATURE ENGINEERING 83
28 else:
29 print (f" {col} : OK ( toutes les valeurs dans [0, 20])")
30
31 print (f"\ nDataset après nettoyage : {[Link] [0]} lignes ×
{[Link] [1]} colonnes ")
10.4 Étape 3 — Feature Engineering
Le feature engineering est l’art de créer de nouvelles variables à partir des variables
existantes, pour donner plus d’information au modèle.
Ici, les notes brutes nous donnent les performances dans chaque matière, mais un modèle
ML apprendrait mieux si on lui donne aussi : la moyenne générale (synthèse globale), l’écart
entre les notes (mesure de la régularité), et un indicateur de régularité binarisé. Ces nouvelles
features peuvent parfois être plus prédictives que les variables originales.
1 # �� Variables dérivées ����������������������������������������������������
2
3 # Moyenne générale : synthèse des trois matières
4 # axis =1 : calculer la moyenne par ligne (un é tudiant à la fois)
5 df[" moyenne "] =
df[[" note_maths "," note_info "," note_anglais "]]. mean(axis =1)
6
7 # Écart entre les notes : un é tudiant avec 15/15/15 est différent
de 5/15/25
8 # même si les deux ont la même moyenne .
9 # std () sur axis =1 mesure cet écart
10 df[" ecart_notes "] =
df[[" note_maths "," note_info "," note_anglais "]]. std(axis =1)
11
12 # Note maximale et minimale : identifier les points forts et
faibles
13 df[" note_max "] =
df[[" note_maths "," note_info "," note_anglais "]]. max(axis =1)
14 df[" note_min "] =
df[[" note_maths "," note_info "," note_anglais "]]. min(axis =1)
15
16 # Mention : variable ordinale dérivée de la moyenne
17 def attribuer_mention (moy):
18 """ Retourne la mention correspondant à une moyenne sur 20. """
19 if moy >= 16: return "Très Bien"
20 elif moy >= 14: return "Bien"
21 elif moy >= 12: return "Assez Bien"
22 elif moy >= 10: return " Passable "
23 else: return " Ajourn é"
24
25 df[" mention "] = df[" moyenne "]. apply ( attribuer_mention )
26
27 # Indicateur de ré gularit é : 1 si l'é tudiant est ré gulier ( faible
écart entre notes )
28 # Le seuil de 2.5 points est une dé cision métier raisonnable
Python pour la Data Science — Ibrahima SY
84 CHAPITRE 10. PROJET FINAL — ÉTUDE DE CAS COMPLÈTE
29 df[" regulier "] = (df[" ecart_notes "] < 2.5). astype (int)
30
31 print (" Nouvelles features créées :")
32 print (df [[" moyenne "," ecart_notes "," mention "," regulier "]]. describe (). round (2))
10.5 Étape 4 — Analyse exploratoire et visualisations
L’EDA doit être orientée par les questions métier. Pour chaque question, on choisit les
graphiques et statistiques les plus pertinents.
1 fig , axes = plt. subplots (2, 3, figsize =(18 , 10))
2
3 # �� 1. Distribution des moyennes ������������������������������������������
4 # Répond à : "À quoi ressemble le niveau général ?"
5 axes [0 ,0]. hist(df[" moyenne "], bins =15 , color =" steelblue ",
6 edgecolor ="white ", alpha =0.8)
7 axes [0 ,0]. axvline (df[" moyenne "]. mean () , color ="red",
linestyle ="--",
8 linewidth =2,
label =f"Moy ={ df[' moyenne ']. mean () :.1f}")
9 axes [0 ,0]. axvline (10 , color =" orange ", linestyle =":", linewidth =2,
10 label =" Seuil (10/20) ")
11 axes [0 ,0]. set_title (" Distribution des moyennes générales ")
12 axes [0 ,0]. set_xlabel (" Moyenne / 20")
13 axes [0 ,0]. set_ylabel (" Nombre d'é tudiants ")
14 axes [0 ,0]. legend ()
15
16 # �� 2. Moyennes par filière : boxplot �������������������������������������
17 # Répond à : "Y a-t-il des filières plus en difficult é ?"
18 sns. boxplot (data=df , x=" filiere ", y=" moyenne ", palette ="muted ",
ax=axes [0 ,1])
19 axes [0 ,1]. axhline (10 , color ="red", linestyle ="--", alpha =0.5 ,
20 label =" Seuil d'admission ")
21 axes [0 ,1]. set_title ("Ré partition des moyennes par filière")
22 axes [0 ,1]. set_xlabel ("Filière")
23 axes [0 ,1]. set_ylabel (" Moyenne / 20")
24 axes [0 ,1]. legend ()
25
26 # �� 3. Taux d'admission par filière ��������������������������������������
27 # Répond à : "Dans quelle filière échoue -t-on le plus ?"
28 taux = df. groupby (" filiere ")["admis "]. mean (). sort_values ()
29 [Link](kind="barh", ax=axes [0 ,2] , color ="coral ")
30 axes [0 ,2]. set_title ("Taux d'admission par filière")
31 axes [0 ,2]. set_xlabel (" Proportion d'é tudiants admis ")
32 axes [0 ,2]. axvline (0.5 , color ="red", linestyle ="--", alpha =0.5)
33 for i, val in enumerate (taux):
34 axes [0 ,2]. text(val + 0.01 , i, f"{val :.0%} ", va=" center ",
fontsize =10)
35
36 # �� 4. Heatmap des corré lations �������������������������������������������
Python pour la Data Science — Ibrahima SY
10.5. ÉTAPE 4 — ANALYSE EXPLORATOIRE ET VISUALISATIONS 85
37 # Répond à : " Quelles variables sont liées entre elles ?"
38 cols_num =
[" note_maths "," note_info "," note_anglais ","age"," moyenne "," ecart_notes "]
39 corr = df[ cols_num ]. corr ()
40 sns. heatmap (corr , annot =True , fmt=".2f", cmap=" coolwarm ",
41 center =0, linewidths =0.5 , ax=axes [1 ,0])
42 axes [1 ,0]. set_title (" Matrice de corré lation ")
43
44 # �� 5. Scatter : profil moyen vs ré gularit é ������������������������������
45 # Répond à : "Les é tudiants ré guliers réussissent -ils mieux ?"
46 # Couleur = admis ou non admis
47 couleurs = df[" admis"]. map ({ True: " steelblue ", False : "coral "})
48 axes [1 ,1]. scatter (df[" moyenne "], df[" ecart_notes "], c=couleurs ,
alpha =0.6 , s=60)
49 axes [1 ,1]. set_xlabel (" Moyenne générale / 20")
50 axes [1 ,1]. set_ylabel ("Écart -type des notes (irré gularit é)")
51 axes [1 ,1]. set_title (" Profil des é tudiants : moyenne vs
ré gularit é")
52 from matplotlib . patches import Patch
53 axes [1 ,1]. legend ( handles =[
54 Patch ( color =" steelblue ", label ="Admis "),
55 Patch ( color =" coral", label ="Non admis ")
56 ])
57
58 # �� 6. Ré partition des mentions �������������������������������������������
59 ordre = [" Ajourn é"," Passable ","Assez Bien","Bien","Très Bien"]
60 mention_counts =
df[" mention "]. value_counts (). reindex ( ordre ). dropna ()
61 couleurs_mention =
["# d32f2f ","# f57c00 ","# fbc02d ","#388 e3c"," #1976 d2"]
62 axes [1 ,2]. bar( mention_counts .index , mention_counts .values ,
color = couleurs_mention )
63 axes [1 ,2]. set_title ("Ré partition des mentions ")
64 axes [1 ,2]. set_ylabel (" Nombre d'é tudiants ")
65 axes [1 ,2]. tick_params (axis="x", rotation =25)
66 # Afficher les effectifs sur les barres
67 for i, (cat , val) in enumerate ( mention_counts . items ()):
68 axes [1 ,2]. text(i, val + 0.5 , str(val), ha=" center ",
fontsize =10)
69
70 plt. suptitle (" Analyse Exploratoire — Ré sultats Acadé miques ",
71 fontsize =14 , fontweight ="bold", y =1.01)
72 plt. tight_layout ()
73 plt. savefig (" eda_projet .png", dpi =150 , bbox_inches ="tight ")
74 [Link] ()
Python pour la Data Science — Ibrahima SY
86 CHAPITRE 10. PROJET FINAL — ÉTUDE DE CAS COMPLÈTE
INFO-CIRCLE Note
Lire les graphiques avec les yeux du décideur. Quand vous présentez ces graphiques
à la direction pédagogique, le boxplot “Moyennes par filière” doit être accompagné
d’une phrase : “La filière X a la médiane la plus basse et la plus grande variabilité —
c’est là que se concentrent les difficultés.” Les chiffres sans interprétation sont du bruit.
10.6 Étape 5 — Modélisation et évaluation
La modélisation répond à la troisième question : peut-on prédire l’admission ? On utilise
un Random Forest, l’algorithme qui a donné les meilleurs résultats dans la comparaison du
chapitre précédent.
1 # �� Pré paration des features ����������������������������������������������
2 # One -Hot sur la filière ( variable nominale )
3 dummies = pd. get_dummies (df[" filiere "], prefix ="fil",
drop_first =True)
4 df_ml = pd. concat ([df , dummies ], axis =1)
5
6 # Liste des features retenues : notes brutes + features dérivées
+ filières encod ées
7 # On N'inclut PAS " mention " ni " moyenne " si on veut tester la
pré diction
8 # "en cours de semestre " (avant de calculer la moyenne officielle )
9 features = [" note_maths ", " note_info ", " note_anglais ", "age",
10 " ecart_notes ", " regulier "] + list( dummies . columns )
11
12 X = df_ml [ features ]. astype ( float )
13 y = df_ml [" admis"]. astype (int)
14
15 X_train , X_test , y_train , y_test = train_test_split (
16 X, y, test_size =0.2 , random_state =42 , stratify =y)
17
18 # �� Pipeline de modé lisation ����������������������������������������������
19 pipeline = Pipeline ([
20 (" imputer ", SimpleImputer ( strategy =" median ")),
21 (" scaler ", StandardScaler ()),
22 (" modele ", RandomForestClassifier ( n_estimators =100 ,
random_state =42))
23 ])
24
25 # �� Entraîner ��������������������������������������������������������������
26 pipeline .fit(X_train , y_train )
27 y_pred = pipeline . predict ( X_test )
28
29 print (f" Accuracy sur le test : { pipeline .score (X_test ,
y_test ):.2%} ")
30 print ("\ nRapport de classification :")
31 print ( classification_report (y_test , y_pred ,
32 target_names =["Non admis ","Admis "]))
Python pour la Data Science — Ibrahima SY
10.7. ÉTAPE 6 — CONCLUSIONS ET RECOMMANDATIONS 87
33
34 # �� Validation crois ée pour une estimation robuste ������������������������
35 cv_scores = cross_val_score (pipeline , X, y, cv=5, scoring ="f1")
36 print (f"\nF1 moyen (5- fold CV) : { cv_scores .mean () :.2%} ±
{ cv_scores .std () :.2%} ")
1 Accuracy sur le test : 90.00%
2
3 Rapport de classification :
4 precision recall f1 - score support
5 Non admis 0.86 0.86 0.86 7
6 Admis 0.92 0.92 0.92 13
7 accuracy 0.90 20
8
9 F1 moyen (5- fold CV) : 0.924 ± 0.021
1 # �� Importance des features : quelles variables sont les plus
pré dictives ? ��
2 # feature_importances_ donne le score d'importance de chaque
variable
3 # ( combien elle contribue à réduire l'impuret é dans les arbres de
la forêt)
4 importances = pipeline . named_steps [" modele "]. feature_importances_
5 feat_imp = pd. Series ( importances ,
index = features ). sort_values ( ascending =True)
6
7 fig , ax = plt. subplots ( figsize =(9 , 5))
8 # .tail (8) : afficher seulement les 8 features les plus
importantes
9 feat_imp .tail (8).plot(kind="barh", ax=ax , color =" steelblue ")
10 ax. set_title (" Importance des variables ( Random Forest )")
11 ax. set_xlabel (" Score d'importance ")
12 plt. tight_layout ()
13 plt. savefig (" feature_importance .png", dpi =150 ,
bbox_inches ="tight ")
14 [Link] ()
10.7 Étape 6 — Conclusions et recommandations
L’analyse répond maintenant aux trois questions initiales. Un bon rapport de Data Science
doit répondre explicitement à chaque question posée, en citant les chiffres qui soutiennent
chaque conclusion.
Python pour la Data Science — Ibrahima SY
88 CHAPITRE 10. PROJET FINAL — ÉTUDE DE CAS COMPLÈTE
Key À retenir
Réponses aux questions de la direction pédagogique
Q1 : Quels facteurs sont associés à l’échec ? D’après la matrice de corrélation et
l’importance des features, la note d’informatique est la variable la plus corrélée avec
l’admission (r = 0.88). L’irrégularité entre les notes (ecart_notes) est également un
facteur : les étudiants avec des notes très hétérogènes ont un taux d’échec plus élevé.
Q2 : Existe-t-il des profils à risque ? Oui. Le scatter plot “Moyenne vs Écart-type”
révèle un cluster d’étudiants avec une moyenne inférieure à 11/20 et un écart-type
supérieur à 3 : ces étudiants cumulent faiblesse générale et irrégularité. Ce groupe
mériterait un suivi renforcé dès le début du semestre.
Q3 : Peut-on prédire l’admission ? Oui, avec une fiabilité de 92% de F1-score (vali-
dation croisée 5-fold). Le modèle identifie correctement 86% des étudiants à risque
(rappel pour “Non admis”).
Recommandation Justification
Renforcer l’encadrement en in- C’est la matière la plus prédictive de l’ad-
formatique mission
Mettre en place un tutorat dès Pour les étudiants du cluster “faible + irré-
la 2e semaine gulier”
Déployer le modèle en prédic- Accuracy 90%, F1 92% : fiabilité suffisante
tion précoce pour l’alerte
Collecter plus de données sur Feature potentiellement très prédictive, ab-
l’assiduité sente du dataset actuel
10.8 Les critères d’un livrable professionnel
Un projet Data Science se livre sous forme d’un notebook propre, documenté et reproduc-
tible. Voici les critères qui distinguent un livrable professionnel d’un simple script :
Python pour la Data Science — Ibrahima SY
10.9. RÉCAPITULATIF DU COURS 89
Critère Ce qui est attendu
Reproductibilité random_state défini partout ; chemin vers les
données clair
Lisibilité Cellules Markdown entre chaque section pour
expliquer le raisonnement
Visualisations Titre, labels, unités sur chaque graphique ; com-
mentaires d’interprétation
Conclusions Réponses explicites et numérotées aux questions
du cahier des charges
Recommandations Actions concrètes, réalisables, avec justification
chiffrée
Code propre Fonctions nommées, pas de code dupliqué, im-
ports en haut
10.9 Récapitulatif du cours
Key À retenir
Ce que vous savez faire maintenant
— Écrire du Python propre : types, structures, fonctions, compréhensions.
— Manipuler des tableaux numériques avec NumPy (vectorisation, broadcasting,
masques).
— Charger, nettoyer, filtrer et agréger des données avec Pandas.
— Explorer un dataset avec des statistiques descriptives et des visualisations perti-
nentes.
— Choisir le bon graphique pour la bonne question (Matplotlib + Seaborn).
— Préparer des données pour le Machine Learning : split, normalisation, encodage.
— Construire un Pipeline Scikit-learn reproductible et l’évaluer par validation croisée.
— Interpréter les métriques d’un modèle de classification (précision, rappel, F1).
— Livrer un notebook professionnel avec conclusions et recommandations exploi-
tables.
Python pour la Data Science — Ibrahima SY
Quatrième partie
Travaux Pratiques
90
TP 1 — Installation et premier notebook
Flask Informations pratiques
Durée : 1h30
Chapitre : Chapitre 1 — Introduction
Rendu : Fichier tp01_installation.ipynb
Objectifs
— Installer Python et Jupyter Notebook
— Vérifier l’installation des bibliothèques
— Exécuter un premier script d’exploration de données
91
92
PEN Exercice 1 — Installation et vérification
1. Installez Anaconda (recommandé) ou Python + pip sur votre machine.
2. Ouvrez un terminal et créez un environnement dédié :
1 conda create -n ds_cours python =3.11
2 conda activate ds_cours
3 conda install numpy pandas matplotlib seaborn
scikit - learn jupyter
3. Lancez Jupyter Notebook : jupyter notebook
4. Créez un nouveau notebook appelé tp01_installation.ipynb.
5. Dans la première cellule, exécutez le code suivant et copiez la sortie dans une
cellule Markdown :
1 import sys , numpy as np , pandas as pd , matplotlib ,
seaborn as sns
2 import sklearn
3
4 for nom , module in [(" Python ", sys), ("NumPy ", np),
5 (" Pandas ", pd), (" Matplotlib ",
matplotlib ),
6 (" Seaborn ", sns), ("Scikit -learn ",
sklearn )]:
7 version = getattr (module , " __version__ ",
sys. version . split () [0])
8 print (f"{nom :15} : { version }")
PEN Exercice 2 — Premier calcul scientifique
Écrivez un script qui :
1. Définit une liste de 10 notes (inventées) entre 0 et 20.
2. Calcule et affiche : la somme, la moyenne, le minimum et le maximum en utilisant
uniquement les fonctions Python de base (sum, min, max, len).
3. Affiche combien d’étudiants sont admis (note ≥ 10) en utilisant une boucle for.
4. Refait le même calcul avec une compréhension de liste en une ligne.
Sortie attendue :
1 Notes : [12.5 , 8.0 , 17.0 , 14.5 , 9.5, 11.0 , 16.0 , 7.5 , 13.0 ,
15.5]
2 Somme : 124.5
3 Moyenne : 12.45
4 Min / Max: 7.5 / 17.0
5 Admis : 7 / 10
Python pour la Data Science — Ibrahima SY
93
PEN Exercice 3 — Explorer le dataset fil rouge
Créez le fichier [Link] avec les données suivantes (ou téléchargez-le depuis
l’espace de cours) :
1 import pandas as pd
2
3 data = {
4 "nom":
["SY"," DIALLO "," NDIAYE ","FALL","BA","DIOP","SARR"," GUEYE ","KANE","MBAY
5 " prenom ":
[" Ibrahima ","Fatou ","Amina "," Seydou "," Moussa "," Aissatou "," Cheikh "," Rok
6 "age": [22 , 21, 23, 22, 24, 20, 23, 21, 25, 22],
7 " filiere ":
["Info","Maths ","Info"," Physique "," Maths","Info"," Physique ","Maths ","I
8 " note_maths ": [14.5 , 17.0 , 8.0 , 12.0 , None , 15.5 ,
11.0 , 18.0 , 9.5 , 13.0] ,
9 " note_info ": [17.0 , 13.5 , 10.5 , 14.0 , 11.0 , 16.0 ,
12.5 , 14.5 , 8.0 , 11.5] ,
10 " note_anglais ": [13.0 , 15.0 , 9.5 , 11.0 , 14.0 , 12.0 ,
10.0 , 16.0 , 7.5 , 12.0] ,
11 "admis ": [True , True , False , True , True , True , True ,
True , False , True]
12 }
13 df = pd. DataFrame (data)
14 df. to_csv (" eleves .csv", index= False )
15 print(" Fichier créé !")
16 print(df)
Répondez dans des cellules Markdown :
1. Combien d’étudiants et de colonnes contient ce dataset ?
2. Quel est le type de chaque colonne ? (utilisez [Link])
3. Y a-t-il des valeurs manquantes ? Où ?
4. Quel est le taux d’admission global ?
Questions de synthèse
1. Quelle est la différence entre une cellule Code et une cellule Markdown dans Jupyter ?
2. Pourquoi crée-t-on un environnement virtuel dédié plutôt que d’installer directement
dans Python de base ?
3. Qu’est-ce qu’un fichier CSV ? Quels sont ses avantages et inconvénients ?
Python pour la Data Science — Ibrahima SY
TP 2 — Bases du langage Python
Flask Informations pratiques
Durée : 2 heures
Chapitre : Chapitre 2 — Bases du langage
Rendu : Fichier tp02_bases.ipynb
PEN Exercice 1 — Types et conversions
1. Déclarez les variables suivantes et affichez leur type avec type() :
— nb_etudiants = 35
— taux_reussite = 0.74
— universite = "UADB"
— accredite = True
2. Un relevé de notes contient la chaîne "16.5". Convertissez-la en float, sous-
trayez 1.5, puis reconvertissez en str. Affichez le résultat formaté : "Note
finale : 15.0/20".
3. Expliquez en commentaire pourquoi int(15.9) donne 15 et non 16.
94
95
PEN Exercice 2 — Calculatrice de bulletin
Écrivez une fonction bulletin(nom, prenom, maths, info, anglais) qui :
1. Calcule la moyenne pondérée : maths coeff 4, info coeff 4, anglais coeff 2.
2. Retourne un dictionnaire avec les clés : etudiant, moyenne, mention, admis.
3. La mention suit les règles standard (Très Bien/Bien/Assez Bien/Passable/A-
journé).
Testez avec :
1 b = bulletin ("SY", " Ibrahima ", maths =14.5 , info =17.0 ,
anglais =13.0)
2 print(b)
3 # Attendu : {' etudiant ': 'Ibrahima SY ', 'moyenne ': 15.1 ,
'mention ': 'Bien ', 'admis ': True}
4
5 b2 = bulletin (" DIALLO ", "Omar", maths =8.0 , info =9.5 ,
anglais =7.0)
6 print(b2)
7 # Attendu : {' etudiant ': 'Omar DIALLO ', 'moyenne ': 8.55 ,
'mention ': 'Ajourn é', 'admis ': False}
PEN Exercice 3 — Boucles et statistiques simples
Vous disposez de la liste de notes :
1 notes = [14.5 , 8.0 , 17.5 , 12.0 , 9.5, 11.0 , 16.0 , 7.5 , 13.0 ,
15.5 , None , 10.0]
Sans utiliser NumPy ni Pandas, répondez aux questions suivantes en utilisant des
boucles et des fonctions Python pures :
1. Filtrez les valeurs None et stockez les notes valides.
2. Calculez : nombre de notes, somme, moyenne, minimum, maximum.
3. Comptez le nombre d’admis (note ≥ 10) et le taux d’admission.
4. Affichez un tableau de résultats formaté avec f-string :
1 === Statistiques de la classe ===
2 Effectif : 11
3 Moyenne : 12.27 / 20
4 Mé diane : 12.00 / 20
5 Min / Max : 7.5 / 17.5
6 Admis : 8 / 11 (72.7%)
Python pour la Data Science — Ibrahima SY
96
PEN Exercice 4 — Générateur de bulletins
À partir du dataset [Link] créé au TP 1, écrivez une fonction
generer_bulletins(fichier_csv) qui :
1. Lit le fichier CSV ligne par ligne (sans Pandas — utilisez le module csv).
2. Pour chaque étudiant, calcule la moyenne simple des trois notes (ignorez les
None).
3. Affiche un bulletin textuel formaté pour chaque étudiant.
4. Retourne le nom de l’étudiant avec la meilleure moyenne.
1 import csv
2
3 def generer_bulletins ( fichier_csv ):
4 meilleur = None
5 meilleure_moy = -1
6 with open( fichier_csv , newline ="", encoding ="utf -8") as
f:
7 reader = csv. DictReader (f)
8 for row in reader :
9 # Votre code ici
10 pass
11 return meilleur
12
13 vainqueur = generer_bulletins (" eleves .csv")
14 print(f"\ nMeilleur (e) é tudiant (e) : { vainqueur }")
Questions de synthèse
1. Expliquez la différence entre == et = en Python.
2. Quelle est la portée d’une variable définie dans une fonction ? Donnez un exemple.
3. Quand utiliser une boucle while plutôt qu’une boucle for ?
Barème
Exercice Points
Exercice 1 : types et conversions 4
Exercice 2 : fonction bulletin 6
Exercice 3 : boucles et stats 6
Exercice 4 : générateur de bulletins 4
Total 20
Python pour la Data Science — Ibrahima SY
TP 3 — Structures de données
Flask Informations pratiques
Durée : 2 heures
Chapitre : Chapitre 3 — Structures de données
Rendu : Fichier tp03_structures.ipynb
PEN Exercice 1 — Manipulation de listes
1. Créez une liste promotions contenant les noms de 8 étudiants.
2. Affichez le 3e et le dernier étudiant.
3. Insérez un nouvel étudiant à la position 4.
4. Triez la liste alphabétiquement et affichez-la.
5. Créez une nouvelle liste pairs contenant uniquement les étudiants aux positions
paires (0, 2, 4...) en utilisant le slicing.
6. Inversez la liste en utilisant le slicing (sans reverse()).
97
98
PEN Exercice 2 — Dictionnaire d’étudiants
1. Créez un dictionnaire classe où chaque clé est le nom d’un étudiant et la valeur
est un dictionnaire contenant ses notes :
1 classe = {
2 "SY Ibrahima ": {" maths": 14.5 , "info": 17.0 ,
" anglais ": 13.0} ,
3 " DIALLO Fatou": {" maths": 17.0 , "info": 13.5 ,
" anglais ": 15.0} ,
4 " NDIAYE Amina": {" maths": 8.0, "info": 10.5 ,
" anglais ": 9.5} ,
5 "FALL Seydou ": {" maths": 12.0 , "info": 14.0 ,
" anglais ": 11.0} ,
6 "BA Moussa ": {" maths": None , "info": 11.0 ,
" anglais ": 14.0} ,
7 }
2. Écrivez une fonction moyenne_etudiant(notes_dict) qui calcule la
moyenne en ignorant les None.
3. Affichez le nom et la moyenne de chaque étudiant.
4. Identifiez l’étudiant avec la meilleure moyenne.
5. Comptez combien d’étudiants ont une note de maths supérieure à 12 (en excluant
les None).
PEN Exercice 3 — Compréhensions et fréquences
Vous disposez d’une liste de mots extraits de réponses d’étudiants :
1 texte = """ python pandas numpy visualisation données analyse
2 exploration machine learning modèle données python pandas
3 visualisation python données apprentissage modèle numpy """
4
5 mots = texte . lower (). split ()
1. En utilisant une compréhension de liste, créez une liste des mots de plus de 6
caractères.
2. En utilisant un dictionnaire de compréhension, comptez la fréquence de chaque
mot unique.
3. Affichez les 5 mots les plus fréquents (utilisez sorted() avec une clé lambda).
4. En utilisant un ensemble, listez les mots uniques.
5. Calculez le pourcentage de mots qui apparaissent plus d’une fois.
Python pour la Data Science — Ibrahima SY
99
PEN Exercice 4 — Application : analyse de filières
Reprenez le fichier [Link] et, sans Pandas, réalisez l’analyse suivante unique-
ment avec des listes et des dictionnaires :
1. Lisez le CSV et stockez les données dans une liste de dictionnaires.
2. Créez un dictionnaire stats_filiere où chaque clé est une filière et la valeur
contient : liste des moyennes, nombre d’admis, nombre total.
3. Affichez pour chaque filière : taux d’admission et moyenne générale.
4. Identifiez la filière avec le meilleur taux d’admission.
Sortie attendue (exemple) :
1 === Statistiques par filière ===
2 Informatique : moy =12.83 , admis =3/3 (100.0%)
3 Maths : moy =15.17 , admis =3/3 (100.0%)
4 Physique : moy =12.00 , admis =3/4 ( 75.0%)
5
6 Meilleure filière : Maths
Questions de synthèse
1. Quelle est la différence entre [Link]() et sorted(list) ?
2. Pourquoi ne peut-on pas utiliser une liste comme clé de dictionnaire ?
3. Dans quel cas utiliserait-on un set plutôt qu’une list ?
Barème
Exercice Points
Exercice 1 : listes et slicing 4
Exercice 2 : dictionnaires imbriqués 6
Exercice 3 : compréhensions et fréquences 5
Exercice 4 : analyse de filières 5
Total 20
Python pour la Data Science — Ibrahima SY
TP 4 — NumPy : calcul numérique
Flask Informations pratiques
Durée : 2 heures
Chapitre : Chapitre 4 — NumPy
Rendu : Fichier tp04_numpy.ipynb
PEN Exercice 1 — Création et inspection de tableaux
1. Créez les tableaux NumPy suivants et affichez leur shape, dtype et ndim :
— Un tableau 1D de 15 entiers aléatoires entre 0 et 20 (simulation de notes).
— Une matrice 4 × 5 remplie de zéros.
— Un vecteur de 8 valeurs régulièrement espacées entre 0 et 20.
— Une matrice identité 3 × 3.
2. Créez une matrice 5 × 3 représentant les notes de 5 étudiants dans
3 matières. Utilisez [Link](42) pour la reproductibilité, puis
[Link](5, 20, (5, 3)).round(1).
3. Affichez la forme, la taille totale et le type de données de cette matrice.
PEN Exercice 2 — Opérations vectorisées
Soit la matrice des notes resultats de l’exercice 1 (5 étudiants, 3 matières).
1. Sans boucle, calculez la moyenne, le minimum et le maximum global.
2. Calculez la moyenne de chaque étudiant (par ligne) avec axis=1.
3. Calculez la moyenne de chaque matière (par colonne) avec axis=0.
4. Appliquez un bonus de +1 point à tous les étudiants sans dépasser 20. (Astuce :
[Link]())
5. Calculez le rang de chaque étudiant selon sa moyenne, du plus élevé au plus
faible. (Astuce : [Link]())
100
101
PEN Exercice 3 — Indexation et masques
1. À partir de la matrice resultats, extrayez :
— La ligne du 3e étudiant.
— La colonne de la 2e matière.
— Les 3 premières lignes et les 2 premières colonnes.
2. Créez un vecteur moyennes (moyenne de chaque étudiant). En utilisant l’indexa-
tion booléenne, extrayez les moyennes des étudiants admis (moyenne ≥ 10).
3. Utilisez [Link]() pour créer un tableau de chaînes : "Admis" si moyenne
≥ 10, "Ajourné" sinon.
4. Remplacez toutes les notes inférieures à 5 par 5.0 (note plancher).
PEN Exercice 4 — Broadcasting et simulation
1. Vous avez une matrice de notes 100×3 et un vecteur de coefficients [0.4, 0.4, 0.2].
Calculez la moyenne pondérée de chaque étudiant sans boucle.
1 np. random .seed (0)
2 notes_100 = np. random . uniform (5, 20, (100 , 3)). round (1)
3 poids = np. array ([0.4 , 0.4, 0.2])
4 # Votre code ici : moyennes = ?
2. Centrez les données : soustrayez la moyenne de chaque colonne. Vérifiez que les
nouvelles moyennes sont bien nulles (à la précision numérique près).
3. Comparaison de performance : comparez le temps d’exécution du calcul de la
somme de 10 millions de nombres :
— Avec une boucle Python : sum(x*x for x in data)
— Avec NumPy : [Link](data**2)
Utilisez %timeit ou le module time. Quel est le facteur d’accélération ?
Questions de synthèse
1. Quelle est la différence entre [Link](a) et b = a ? Pourquoi est-ce important ?
2. Expliquez la règle de broadcasting en un exemple concret.
3. Pourquoi NumPy est-il plus rapide que les listes Python pour les calculs ?
Python pour la Data Science — Ibrahima SY
102
Barème
Exercice Points
Exercice 1 : création et inspection 4
Exercice 2 : opérations vectorisées 5
Exercice 3 : indexation et masques 6
Exercice 4 : broadcasting et simulation 5
Total 20
Python pour la Data Science — Ibrahima SY
TP 5 — Pandas : manipulation de données
Flask Informations pratiques
Durée : 3 heures
Chapitre : Chapitre 5 — Pandas
Rendu : Fichier tp05_pandas.ipynb
PEN Exercice 1 — Chargement et exploration
Générez un dataset de 100 étudiants fictifs et sauvegardez-le en CSV :
1 import pandas as pd
2 import numpy as np
3
4 np. random .seed (42)
5 n = 100
6 filieres =
np. random . choice (["Info","Maths "," Physique "," Chimie "], n)
7 df = pd. DataFrame ({
8 "id": range (1, n+1) ,
9 " filiere ": filieres ,
10 "age": np. random . randint (18, 28, n),
11 " note_maths ": np. where(np. random .rand(n) < 0.05 ,
[Link] ,
12 np. random . uniform (4, 20,
n).round (1)),
13 " note_info ": np. random . uniform (5, 20, n). round (1) ,
14 " note_anglais ": np. random . uniform (5, 20, n). round (1) ,
15 "admis ": np. random . choice ([ True , False ], n, p=[0.75 ,
0.25])
16 })
17 df. to_csv (" eleves_100 .csv", index= False )
1. Chargez le fichier et affichez : forme, types, premières et dernières lignes.
2. Combien de valeurs manquantes y a-t-il par colonne (en nombre et en %) ?
3. Affichez les statistiques descriptives (describe()) pour les colonnes numé-
riques.
4. Combien d’étudiants par filière ? (Utilisez value_counts())
103
104
PEN Exercice 2 — Nettoyage
1. Remplacez les NaN de note_maths par la médiane de la colonne.
2. Vérifiez qu’il n’y a plus de valeurs manquantes.
3. Détectez et supprimez les doublons (sur toutes les colonnes).
4. Ajoutez un doublon artificiel pour tester :
1 doublon = [Link] [0:1]. copy ()
2 df = pd. concat ([df , doublon ], ignore_index =True)
3 print (f" Avant suppression : {len(df)} lignes ")
4 df = df. drop_duplicates ()
5 print (f"Après suppression : {len(df)} lignes ")
5. Vérifiez que les notes sont bien dans [0, 20]. Combien de valeurs sont hors
plage ? Remplacez-les par [Link].
PEN Exercice 3 — Filtrage, tri et nouvelles colonnes
1. Créez une colonne moyenne = moyenne simple des 3 notes.
2. Créez une colonne mention avec la fonction de l’exercice 2 du TP 2.
3. Filtrez les étudiants de la filière "Info" avec une moyenne ≥ 14. Combien y en
a-t-il ?
4. Utilisez .query() pour obtenir les étudiants entre 20 et 25 ans non admis.
Affichez leurs noms et leurs moyennes.
5. Triez le DataFrame par filière (croissant) puis par moyenne (décroissant). Affi-
chez le Top 5.
PEN Exercice 4 — Groupby et agrégations
1. Calculez, par filière, la moyenne, l’écart-type, le minimum et le maximum de la
colonne moyenne.
2. Calculez le taux d’admission par filière (proportion d’étudiants admis).
3. Créez un tableau croisé ([Link]) entre la filière et la mention.
4. Trouvez, pour chaque filière, l’étudiant avec la meilleure moyenne. (Astuce :
groupby().idxmax())
5. Exportez le tableau de statistiques par filière en CSV : stats_filieres.csv.
Sortie attendue pour la question 1 :
1 moyenne
2 mean std min max
3 filiere
4 Chimie 12.34 3.21 5.67 19.80
5 Info 13.10 3.05 6.20 19.50
6 Maths 13.75 2.90 7.10 20.00
7 Physique 12.80 3.15 5.90 19.70
Python pour la Data Science — Ibrahima SY
105
Questions de synthèse
1. Quelle est la différence entre [Link][] et [Link][] ?
2. Pourquoi faut-il privilégier l’imputation par la médiane plutôt que la moyenne en
présence d’outliers ?
3. Expliquez la différence entre df["col"].apply() et df["col"].map().
Barème
Exercice Points
Exercice 1 : chargement et exploration 4
Exercice 2 : nettoyage 4
Exercice 3 : filtrage et nouvelles colonnes 6
Exercice 4 : groupby et agrégations 6
Total 20
Python pour la Data Science — Ibrahima SY
TP 6 — Analyse Exploratoire (EDA)
Flask Informations pratiques
Durée : 3 heures
Chapitre : Chapitre 6 — EDA
Rendu : Fichier tp06_eda.ipynb
PEN Exercice 1 — Statistiques descriptives
Chargez le dataset eleves_100.csv (du TP 5, propre et enrichi).
1. Produisez un rapport descriptif complet avec describe() et interprétez chaque
statistique (moyenne, médiane, std, quartiles).
2. Pour la colonne moyenne :
— Calculez manuellement la moyenne, la médiane et l’IQR.
— Calculez le coefficient d’asymétrie (skew()).
— Interprétez : la distribution est-elle symétrique, positivement ou négative-
ment asymétrique ?
3. Comparez les statistiques selon l’admission :
[Link]("admis").describe(). Quelles variables semblent les
mieux discriminer admis vs non-admis ?
PEN Exercice 2 — Corrélation
1. Calculez la matrice de corrélation de Pearson des variables numériques.
2. Identifiez les deux paires de variables les plus corrélées positivement et négati-
vement.
3. Interprétez la corrélation entre note_maths et note_info. Est-elle forte, mo-
dérée ou faible ? Que cela signifie-t-il ?
4. Calculez également la corrélation de Spearman. Les résultats diffèrent-ils signi-
ficativement ? Pourquoi ?
5. Testez la corrélation entre age et moyenne. Trouvez-vous un lien entre l’âge et
les résultats académiques ?
106
107
PEN Exercice 3 — Détection et traitement des outliers
1. Appliquez la méthode IQR pour détecter les outliers dans les trois colonnes de
notes. Combien en trouvez-vous ?
2. Appliquez le Z-score (|z| > 3). Les deux méthodes donnent-elles les mêmes
résultats ?
3. Pour chaque outlier détecté, affichez l’enregistrement complet et décidez s’il
faut le supprimer, le corriger, ou le conserver. Justifiez votre décision dans une
cellule Markdown.
4. Comparez les statistiques avant et après le traitement des outliers (moyenne,
std, min, max).
PEN Exercice 4 — Rapport EDA complet
Rédigez un rapport EDA structuré dans votre notebook. Ce rapport doit :
1. Commencer par une cellule Markdown d’introduction décrivant le dataset et les
questions auxquelles vous voulez répondre.
2. Inclure pour chaque variable numérique :
— La distribution (médiane, IQR, skewness)
— Le nombre de valeurs manquantes
— Le nombre d’outliers détectés
3. Identifier les variables les plus prédictives de l’admission (corrélation la plus
forte avec la variable admis).
4. Conclure avec 3 à 5 observations clés formulées en français, sous forme de
bullets.
Exemple de conclusion attendue :
Observations principales :
— La moyenne générale suit approximativement une distribution normale
(skewness = 0.12), centrée autour de 12.5/20.
— note_info est la variable la plus corrélée avec l’admission (r = 0.72).
— Les étudiants en Maths ont un taux d’admission 15% supérieur à la filière
Physique.
— 8% des notes de maths sont des outliers selon la règle IQR, concentrés
sous 6/20.
Questions de synthèse
1. Quelle est la différence entre corrélation et causalité ? Donnez un exemple de corrélation
qui n’implique pas de causalité.
2. Pourquoi l’écart-type est-il moins robuste que l’IQR en présence d’outliers ?
3. Dans quel cas préférerait-on conserver un outlier plutôt que de le supprimer ?
Python pour la Data Science — Ibrahima SY
108
Barème
Exercice Points
Exercice 1 : statistiques descriptives 5
Exercice 2 : corrélation et interprétation 5
Exercice 3 : outliers 4
Exercice 4 : rapport EDA complet 6
Total 20
Python pour la Data Science — Ibrahima SY
TP 7 — Visualisation de données
Flask Informations pratiques
Durée : 3 heures
Chapitre : Chapitre 7 — Visualisation
Rendu : Fichier tp07_visualisation.ipynb
PEN Exercice 1 — Histogrammes et distributions
1. Tracez un histogramme de la distribution des moyennes. Ajoutez : titre, labels
d’axes, ligne verticale pour la moyenne et la médiane (couleurs différentes),
légende.
2. Sur une même figure avec 3 sous-graphiques (subplots(1,3)), tracez l’histo-
gramme de chacune des 3 notes. Toutes doivent avoir la même échelle (0–20)
sur l’axe x.
3. Tracez la distribution des moyennes séparément pour chaque filière sur le même
graphique (alpha=0.5 pour la transparence). Laquelle semble la plus à droite ?
Que cela signifie-t-il ?
PEN Exercice 2 — Diagrammes en barres et comparaisons
1. Créez un diagramme en barres montrant la moyenne par filière, avec les barres
d’erreur représentant l’écart-type. Ajoutez les valeurs numériques sur chaque
barre.
2. Créez un diagramme en barres groupées montrant côte à côte, pour chaque
filière, le taux d’admission des hommes et des femmes. (Générez une colonne
genre aléatoire si elle n’existe pas.)
3. Créez un diagramme en barres horizontales montrant le nombre d’étudiants par
filière, trié par effectif décroissant. Mettez en rouge la filière avec le plus petit
effectif.
109
110
PEN Exercice 3 — Scatter plots et boxplots
1. Tracez un scatter plot de note_maths vs note_info. Coloriez les points selon
la filière et variez leur taille selon la moyenne. Ajoutez une ligne de tendance
(régression linéaire avec [Link]).
2. Tracez un boxplot des moyennes par filière. Affichez également les points indivi-
duels superposés (stripplot ou swarmplot de Seaborn).
3. Créez une grille 3 × 3 de scatter plots pour les combinaisons (note_maths,
note_info, note_anglais) — 9 graphiques au total. Cette visualisation s’appelle
une pair plot. Simplifiez avec [Link]().
PEN Exercice 4 — Heatmap et rapport visuel
1. Tracez la heatmap de corrélation de toutes les variables numériques. Anno-
tez chaque cellule avec la valeur arrondie à 2 décimales. Utilisez une palette
coolwarm centrée sur 0.
2. Créez un tableau de bord (dashboard) en une seule figure 2 × 3 comportant :
— [0,0] : Histogramme des moyennes
— [0,1] : Barres du taux d’admission par filière
— [0,2] : Boxplot par filière
— [1,0] : Scatter maths vs info
— [1,1] : Heatmap de corrélation
— [1,2] : Répartition des mentions (barres colorées)
Sauvegardez en PNG haute résolution : dashboard_eleves.png.
Questions de synthèse
1. Quel graphique utiliseriez-vous pour montrer l’évolution d’une note sur 5 semestres ?
Pourquoi pas un diagramme en barres ?
2. Un collègue vous dit : “L’histogramme de nos notes est très à gauche (long tail à droite).”
Que cela signifie-t-il pour la médiane par rapport à la moyenne ?
3. Pourquoi est-il important d’ajouter des titres et des labels à tous vos graphiques, même
dans un notebook exploratoire ?
Python pour la Data Science — Ibrahima SY
111
Barème
Exercice Points
Exercice 1 : histogrammes 4
Exercice 2 : diagrammes en barres 5
Exercice 3 : scatter et boxplots 5
Exercice 4 : heatmap et tableau de bord 6
Total 20
Python pour la Data Science — Ibrahima SY
TP 8 — Préparation des données pour le
ML
Flask Informations pratiques
Durée : 2h30
Chapitre : Chapitre 8 — Préparation ML
Rendu : Fichier tp08_preparation_ml.ipynb
PEN Exercice 1 — Train / Test Split
1. Chargez eleves_100.csv et préparez les features et la cible :
1 X = df [[" note_maths ", " note_info ", " note_anglais ",
"age"]]
2 y = df[" admis"]. astype (int)
2. Faites un split 80%/20% avec random_state=42 et stratify=y.
3. Affichez :
— Le nombre d’exemples dans train et test.
— Le taux d’admis dans train et test.
— Pourquoi stratify=y est-il important ici ?
4. Refaites le split sans stratify. Comparez les taux d’admis. Que se passe-t-il
avec un petit dataset ?
PEN Exercice 2 — Normalisation : comprendre l’impact
1. Appliquez StandardScaler sur les features de train. Vérifiez que la moyenne
est ≈ 0 et l’écart-type ≈ 1.
2. Appliquez MinMaxScaler. Vérifiez que les valeurs sont dans [0, 1].
3. Erreur volontaire : fittez le scaler sur l’ensemble complet (X) puis sur X_train.
Comparez les paramètres (mean_, scale_). Expliquez en Markdown pourquoi
c’est une erreur.
4. Appliquez RobustScaler et comparez les 3 méthodes sur les mêmes données
avec des statistiques de base.
112
113
PEN Exercice 3 — Encodage des variables catégorielles
1. Appliquez LabelEncoder sur la colonne mention. Affichez le mapping (classe
→ entier). Pourquoi le Label Encoding n’est-il pas adapté pour la colonne
filiere ?
2. Appliquez pd.get_dummies() sur filiere avec drop_first=True. Fusion-
nez avec le DataFrame.
3. Comparez les dimensions du DataFrame avant et après l’encodage.
4. Créez une colonne tranche_age : “< 21”, “21–23”, “> 23” et encodez-la avec
Label Encoding. Vérifiez que l’ordre est respecté.
PEN Exercice 4 — Pipeline de préparation complet
Assemblez toutes les étapes en un pipeline reproductible :
1 import pandas as pd , numpy as np
2 from sklearn . model_selection import train_test_split
3 from sklearn . preprocessing import StandardScaler
4 from sklearn . impute import SimpleImputer
5 from sklearn . pipeline import Pipeline
6
7 # Votre code de bout en bout :
8 # 1. Charger et nettoyer
9 # 2. Feature engineering (moyenne , filiere OHE)
10 # 3. Sé lectionner X et y
11 # 4. Split stratifi é 80/20
12 # 5. Pipeline : imputation -> normalisation
13 # 6. Transformer X_train et X_test
14 # 7. Afficher la forme et 5 premi ères lignes de X_train
transform é
Vérifiez que votre pipeline est reproductible : exécutez deux fois la même cellule et
obtenez les mêmes résultats.
Bonus : sauvegardez le pipeline avec [Link]() et rechargez-le dans une nouvelle
cellule.
1 import joblib
2 joblib .dump(pipeline , " pipeline_preparation .pkl")
3 pipeline_charge = joblib .load(" pipeline_preparation .pkl")
4 # Vé rifier que les ré sultats sont identiques
Questions de synthèse
1. Expliquez ce qu’est le data leakage et donnez un exemple concret où il se produirait
lors de la normalisation.
2. Pourquoi utilise-t-on stratify=y pour des problèmes de classification ?
3. Quelle normalisation choisiriez-vous pour un dataset contenant de nombreux outliers ?
Pourquoi ?
Python pour la Data Science — Ibrahima SY
114
Barème
Exercice Points
Exercice 1 : split et stratification 4
Exercice 2 : normalisation 5
Exercice 3 : encodage 5
Exercice 4 : pipeline complet 6
Total 20
Python pour la Data Science — Ibrahima SY
TP 9 — Pipelines et premier modèle
Flask Informations pratiques
Durée : 3 heures
Chapitre : Chapitre 9 — Pipelines
Rendu : Fichier tp09_pipelines.ipynb
PEN Exercice 1 — Premier modèle sans Pipeline
1. Préparez les données (étapes du TP 8 : nettoyage, encodage, split).
2. Entraînez un DecisionTreeClassifier(max_depth=3) manuellement (sans
Pipeline) et calculez l’accuracy sur le test.
3. Entraînez maintenant un KNeighborsClassifier(n_neighbors=5). Compa-
rez les accuracy.
4. Affichez la matrice de confusion pour chaque modèle. Quel modèle fait plus
d’erreurs sur les “Non admis” ?
PEN Exercice 2 — Pipeline Scikit-learn
1. Réécrivez votre meilleur modèle dans un Pipeline :
1 from sklearn . pipeline import Pipeline
2 from sklearn . preprocessing import StandardScaler
3 from sklearn . impute import SimpleImputer
4 from sklearn .tree import DecisionTreeClassifier
5
6 pipeline = Pipeline ([
7 (" imputer ", SimpleImputer ( strategy =" median ")),
8 (" scaler ", StandardScaler ()),
9 ("clf", DecisionTreeClassifier ( max_depth =3,
random_state =42))
10 ])
11 pipeline .fit(X_train , y_train )
12 print (f" Accuracy : { pipeline .score (X_test , y_test ):.2%} ")
2. Vérifiez que le Pipeline donne exactement les mêmes résultats que la version
manuelle.
3. Quel est l’avantage du Pipeline pour la mise en production ? Répondez en cellule
Markdown.
115
116
PEN Exercice 3 — Validation croisée et comparaison de modèles
1. Comparez les 4 modèles suivants avec une validation croisée à 5 plis :
— DecisionTreeClassifier(max_depth=5)
— LogisticRegression(max_iter=500)
— KNeighborsClassifier(n_neighbors=5)
— RandomForestClassifier(n_estimators=100)
2. Utilisez les métriques accuracy et f1 (pondéré).
3. Affichez un tableau de résultats trié par F1 décroissant.
4. Tracez un graphique en barres des F1 moyens avec les barres d’erreur.
5. Quel modèle recommandez-vous ? Justifiez en tenant compte des performances
ET de l’interprétabilité.
PEN Exercice 4 — Analyse du meilleur modèle
Prenez le modèle avec le meilleur F1 de l’exercice 3.
1. Entraînez-le sur l’intégralité du train et évaluez sur le test.
2. Affichez le rapport de classification complet.
3. Tracez la matrice de confusion annotée.
4. Si c’est un RandomForest : tracez l’importance des features (barre horizontale
triée par importance décroissante). Quelle feature est la plus importante ?
5. Testez votre modèle sur un “nouveau” étudiant :
1 nouvel_etudiant = pd. DataFrame ({
2 " note_maths ": [11.0] , " note_info ": [13.5] ,
3 " note_anglais ": [9.0] , "age": [22] ,
4 # Ajouter les colonnes OHE né cessaires
5 })
6 prediction = pipeline . predict ( nouvel_etudiant )
7 proba = pipeline . predict_proba ( nouvel_etudiant )
8 print (f" Prediction : {' Admis ' if prediction [0] else 'Non
admis '}")
9 print (f" Probabilit é d'admission : {proba [0 ,1]:.1%} ")
Questions de synthèse
1. Quelle est la différence entre accuracy et F1-score ? Dans quel cas l’accuracy seule
est-elle insuffisante ?
2. Expliquez en quoi la validation croisée est plus fiable que l’évaluation sur un simple
split train/test.
3. Qu’est-ce que l’overfitting ? Comment le détecter ?
Python pour la Data Science — Ibrahima SY
117
Barème
Exercice Points
Exercice 1 : premier modèle 4
Exercice 2 : Pipeline 4
Exercice 3 : comparaison de modèles 6
Exercice 4 : analyse du meilleur modèle 6
Total 20
Python pour la Data Science — Ibrahima SY
TP 10 — Projet Final
Flask Informations pratiques
Durée : 4–6 heures (travail en autonomie)
Chapitre : Chapitre 10 — Projet Final
Rendu : Dossier projet_final/ contenant le notebook + rapport
Évaluation : 40% de la note finale
Contexte
La direction académique d’une université souhaite automatiser la détection précoce des
étudiants à risque d’échec. Vous êtes chargé(e) de construire un système d’analyse complet à
partir des données historiques.
Dataset
Générez un dataset de 300 étudiants avec le script fourni, ou utilisez le dataset réel fourni
par l’enseignant (Titanic, Iris, ou autre dataset de classification fourni en cours).
1 import pandas as pd , numpy as np
2
3 np. random .seed (2024)
4 n = 300
5 filieres = np. random . choice ([" Informatique ","Mathé matiques ",
6 " Physique "," Chimie "," Biologie "], n,
7 p =[0.35 ,0.25 ,0.20 ,0.12 ,0.08])
8 df = pd. DataFrame ({
9 "id": range (1, n+1) ,
10 " filiere ": filieres ,
11 "age": np. random . randint (17 , 30, n),
12 " semestre ": np. random . choice ([1 ,2 ,3 ,4 ,5 ,6] , n),
13 " note_maths ": np. where (np. random .rand(n) < 0.08 , [Link] ,
14 np. random . normal (12.5 , 3.5 ,
n).clip (0 ,20). round (1)),
15 " note_info ": np. where (np. random .rand(n) < 0.03 , [Link] ,
16 np. random . normal (13.0 , 3.2 ,
n).clip (0 ,20). round (1)),
17 " note_anglais ": np. random . normal (12.0 , 3.0 ,
n).clip (0 ,20).round (1) ,
118
119
18 " note_projet ": np. where (np. random .rand(n) < 0.10 , [Link] ,
19 np. random . normal (13.5 , 3.0 ,
n).clip (0 ,20). round (1)),
20 " absences ": np. random . poisson (4, n),
21 " bourse ": np. random . choice ([ True , False ], n,
p =[0.30 ,0.70]) ,
22 })
23 # Cible : admis si moyenne >= 10 ET absences <= 10
24 df[" moyenne "] =
df[[" note_maths "," note_info "," note_anglais "," note_projet "]]. mean(axis =1)
25 df["admis "] = (( df[" moyenne "] >= 10) & (df[" absences "] <= 10))
26 # Ajouter du bruit
27 [Link][np. random . choice ([Link] , 20) , "admis "] =
~[Link][np. random . choice ([Link] , 20) , "admis "]
28 df. to_csv (" dataset_projet .csv", index = False )
29 print (f" Dataset créé : {df. shape }")
Partie 1 — Exploration et nettoyage (5 points)
PEN Partie 1 — Exploration et nettoyage
1. Chargez le dataset et produisez un rapport d’exploration : forme, types, valeurs
manquantes, statistiques descriptives.
2. Nettoyez les données : imputation des NaN, gestion des doublons, vérification
des plages de valeurs.
3. Identifiez et traitez les outliers avec la méthode de votre choix. Justifiez vos
décisions.
4. Ajoutez au moins 2 nouvelles features pertinentes (ex : ecart_notes,
charge_absence, etc.)
Partie 2 — Analyse exploratoire visuelle (5 points)
PEN Partie 2 — Analyse visuelle
Créez un tableau de bord de 6 graphiques minimum qui répond aux questions :
1. Quelle est la distribution des moyennes générales ?
2. Existe-t-il des différences significatives entre les filières ?
3. Quelles variables sont les plus corrélées avec l’admission ?
4. Quel est le profil type d’un étudiant admis vs non-admis ?
5. Y a-t-il un lien entre les absences et les résultats ?
6. La filière d’origine influence-t-elle le taux d’admission ?
Chaque graphique doit être accompagné d’une cellule Markdown expliquant l’observa-
tion clé.
Python pour la Data Science — Ibrahima SY
120
Partie 3 — Modélisation (7 points)
PEN Partie 3 — Modélisation
1. Préparez les données complètes pour le ML (encodage, normalisation, split
stratifié).
2. Comparez au moins 3 algorithmes par validation croisée (5-fold). Justifiez votre
choix de métrique (accuracy, F1, AUC…).
3. Sélectionnez le meilleur modèle et évaluez-le sur le test. Affichez : accuracy, F1,
matrice de confusion, courbe ROC.
4. Analysez les features les plus importantes.
5. Testez votre modèle sur 3 profils d’étudiants fictifs que vous inventez. Commentez
les prédictions.
Partie 4 — Conclusions et recommandations (3 points)
PEN Partie 4 — Rapport de conclusions
Rédigez en cellules Markdown une conclusion structurée contenant :
1. Résumé des observations clés (3–5 bullet points).
2. Réponses explicites aux 6 questions de la Partie 2.
3. Limites de l’analyse : quelles hypothèses avez-vous faites ? Qu’est-ce que vous
ne savez pas ?
4. Recommandations pour la direction académique : actions concrètes basées sur
votre analyse.
Critères d’évaluation
Critère Points Indicateurs
Exploration et nettoyage 5 Exhaustivité, justifications
Visualisations 5 Pertinence, qualité graphique, commentaires
Modélisation 7 Rigueur, métriques adaptées, analyse features
Conclusions et rapport 3 Clarté, actionabilité, limites identifiées
Total 20
Python pour la Data Science — Ibrahima SY
121
STAR Bonne pratique
Conseils pour un excellent rendu :
— Relancez le notebook de la première à la dernière cellule (Kernel → Restart & Run
All) avant de soumettre.
— Nommez vos variables de façon explicite ; évitez df2, temp…
— Chaque figure doit avoir un titre, des labels d’axes et une légende si nécessaire.
— Vos conclusions doivent s’appuyer sur des chiffres précis.
Python pour la Data Science — Ibrahima SY