Pour débuter en data science (la science des données), cinq gestes suffisent, et ils s'enchaînent : extraire les données avec SQL, les nettoyer avec Python, les décrire avec des statistiques, tester un modèle, puis expliquer ce que tu trouves. Exemple : une appli de livraison se demande si la pluie fait grimper les commandes. Une requête sort les commandes, Python écarte les lignes douteuses, la médiane compare jours secs et jours de pluie, un modèle prédit la demande, un graphique convainc l'équipe. Chaque geste est repris ici sur des données fictives, avec son piège.
SQL : aller chercher les données
Les données d'une entreprise dorment souvent dans une base relationnelle : des tables faites de lignes (une commande) et de colonnes (ville, montant, durée de livraison, pluie ou non). SQL est le langage qui les interroge, et quatre mots suffisent pour commencer : SELECT choisit les colonnes, FROM la table, WHERE filtre les lignes, GROUP BY les regroupe.
SELECT ville, COUNT(*) AS nb, AVG(montant) AS panier_moyen
FROM commandes
WHERE pluie = 1
GROUP BY ville;
Cette requête donne, par ville, le nombre de commandes de pluie et leur montant moyen. COUNT et AVG sont des agrégats : ils résument plusieurs lignes en une valeur.
Piège classique : pour garder les villes de plus de 100 commandes, WHERE COUNT(*) > 100 est refusé, car WHERE trie les lignes avant que les groupes existent. Une condition sur un total se pose après le regroupement : HAVING COUNT(*) > 100, sous GROUP BY (documentation de PostgreSQL).
Python et pandas : nettoyer avant de calculer
Tu charges ensuite ces données dans Python avec pandas, une bibliothèque (un ensemble d'outils prêts à importer) qui manipule des tableaux appelés DataFrame. Le montant moyen par ville les jours de pluie tient en une ligne :
df[df["pluie"] == 1].groupby("ville")["montant"].mean()
Avant tout calcul, regarde l'état du tableau : df.isna().sum() compte les cases vides par colonne, df.duplicated().sum() les lignes en double, et df.describe() affiche minimum, maximum et quartiles, où une durée de livraison négative ou de 900 minutes saute aux yeux.
Piège classique : pandas ignore les cases vides sans prévenir. Sur les durées 20, 30 et une case vide, df["duree"].mean() renvoie 25 : c'est le réglage par défaut skipna=True (documentation de pandas). Si un tiers des durées manque, ta moyenne ne parle que des deux autres tiers.
Statistiques : décrire avant de conclure
La moyenne $\bar{x} = \dfrac{1}{n}\sum_{i=1}^{n} x_i$ se laisse tirer par les valeurs extrêmes ; la médiane, valeur du milieu des données rangées, leur résiste. Sur des livraisons de 20, 25, 30, 35 et 190 minutes, la moyenne vaut $\dfrac{300}{5} = 60$ minutes, la médiane 30 minutes. La médiane décrit la livraison ordinaire, et l'écart entre les deux trahit une valeur extrême.
Ensuite, une corrélation n'est pas une cause. Si les jours de pluie comptent plus de commandes, il a peut-être surtout plu le week-end, et c'est le week-end qui fait commander : on parle de facteur de confusion. Pour l'écarter, compare samedis pluvieux et samedis secs.
Piège classique : un test statistique ne prouve pas qu'un effet existe. Sa p-valeur est la probabilité, s'il n'y avait aucun effet, d'observer un écart au moins aussi grand que le tien. Une p-valeur de 0,03 ne signifie donc pas « 97 % de chances que l'effet soit réel ».
Tester un modèle sur des données neuves
L'apprentissage automatique (machine learning) laisse un algorithme ajuster un modèle à partir d'exemples. Pour débuter, on fait de l'apprentissage supervisé : chaque exemple porte la réponse attendue, son étiquette. Prédire une catégorie (ce client va-t-il partir ?) est une classification, confiée à un classifieur ; prédire un nombre, une régression.
Une règle prime : on ne juge jamais un modèle sur ses données d'entraînement. Un modèle qui les aurait apprises par cœur y aurait un score parfait sans rien savoir prédire de neuf. Le guide de scikit-learn, une bibliothèque Python, y voit une erreur de méthode : l'usage est de mettre de côté un jeu de test.
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
modele = DecisionTreeClassifier().fit(X_train, y_train)
print(modele.score(X_train, y_train), modele.score(X_test, y_test))
Ici, 20 % des lignes partent en test et random_state fixe le tirage. X contient les variables qui servent à prédire, y les étiquettes ; score renvoie le taux de bonnes réponses.
Définition : un modèle surapprend (overfitting) quand il colle à ses données d'entraînement au point de mal prédire sur des données neuves. Son signe : un score bien meilleur en entraînement qu'en test.
Évaluer un classifieur : précision et rappel
Le taux de bonnes réponses (accuracy) trompe dès qu'une classe est rare. Sur 1 000 transactions dont 10 fraudes, un modèle qui répond toujours « pas de fraude » a raison 990 fois, soit 99 %, sans trouver une seule fraude. Appelle positifs les cas cherchés : un vrai positif ($VP$) est une fraude signalée, un faux positif ($FP$) une transaction honnête signalée, un faux négatif ($FN$) une fraude manquée.
Formule :
$$\text{précision} = \frac{VP}{VP + FP} \qquad \text{rappel} = \frac{VP}{VP + FN}$$
Pour les retrouver : la précision divise par ce que le modèle a signalé, le rappel par les fraudes qui existaient vraiment.
Les deux tirent en sens contraire : tout signaler donne un rappel de 1 et une précision effondrée, et le bon réglage dépend du coût de chaque erreur. Attention : en français, « précision » traduit parfois accuracy ; fie-toi à la formule, pas au mot.
Expliquer ton résultat
Un résultat que personne ne comprend ne change aucune décision. Présente-le avec un graphique et une phrase qui dit ce qu'il montre, limite comprise. Sur nos données fictives : « Les jours de pluie, la durée médiane de livraison à Lille passe de 30 à 38 minutes ; les week-ends n'ont pas été séparés. » Choisis le graphique selon la question : une courbe pour une évolution, des barres pour comparer des groupes, un nuage de points pour relier deux variables.
Dis aussi d'où viennent les données : un modèle entraîné sur un historique biaisé reproduit ce biais dans ses prédictions.
Exercices corrigés
Cherche chacun sur ta feuille avant d'ouvrir la correction.
Exercice 1 : Six livraisons ont duré 18, 22, 26, 30, 34 et 200 minutes. Calcule la moyenne et la médiane. Laquelle décrit une livraison ordinaire ?
Correction :
Somme : $18 + 22 + 26 + 30 + 34 + 200 = 330$, donc $\bar{x} = \dfrac{330}{6} = 55$ minutes.
Le nombre de valeurs est pair : la médiane est la moyenne des deux valeurs centrales, $\dfrac{26 + 30}{2} = 28$ minutes.
La médiane décrit la livraison ordinaire ; la seule durée de 200 minutes tire la moyenne vers le haut.
Exercice 2 : La table commandes a les colonnes ville, montant (en euros) et pluie (1 s'il pleuvait ce jour-là, 0 sinon). Écris la requête qui donne le montant moyen des commandes de pluie par ville, pour les seules villes qui en comptent plus de 50.
Correction :
SELECT ville, AVG(montant) AS panier_moyen
FROM commandes
WHERE pluie = 1
GROUP BY ville
HAVING COUNT(*) > 50;
La pluie porte sur chaque ligne : sa condition va dans WHERE, avant le regroupement. « Plus de 50 commandes » porte sur un total par ville : sa condition va dans HAVING, après GROUP BY. Comme WHERE agit en premier, COUNT(*) ne compte que les commandes de pluie. Le montant moyen sort en euros.
Exercice 3 : Une banque teste un modèle de détection de fraude sur 2 000 transactions, dont 40 frauduleuses. Le modèle en signale 50, parmi lesquelles 30 sont de vraies fraudes. Calcule son taux de bonnes réponses, sa précision et son rappel, puis compare avec un modèle qui ne signale jamais rien.
Correction :
On compte : $VP = 30$, $FP = 50 - 30 = 20$, $FN = 40 - 30 = 10$, et les vrais négatifs $VN = 2\,000 - 30 - 20 - 10 = 1\,940$.
Taux de bonnes réponses : $\dfrac{VP + VN}{2\,000} = \dfrac{1\,970}{2\,000} = 98{,}5\ \%$.
Précision : $\dfrac{30}{30 + 20} = 60\ \%$. Rappel : $\dfrac{30}{30 + 10} = 75\ \%$.
Le modèle muet a raison sur les 1 960 transactions honnêtes, soit $\dfrac{1\,960}{2\,000} = 98\ \%$, avec un rappel nul. Les deux taux se valent presque ; précision et rappel montrent l'écart : trois fraudes sur quatre attrapées, deux alertes sur cinq fausses.
Exercice 4 : Pour prédire quels clients vont se désabonner, tu compares deux modèles. A obtient un taux de bonnes réponses de 0,99 sur l'entraînement et de 0,71 sur le test ; B, de 0,84 et 0,82. Un collègue veut garder A, « qui a le meilleur score ». Lequel choisis-tu ?
Correction :
Seul le score de test mesure ce qui compte : la qualité des prédictions sur des clients jamais vus. Là, B fait mieux, $0{,}82$ contre $0{,}71$.
A surapprend : $0{,}99 - 0{,}71 = 0{,}28$ d'écart entre entraînement et test, contre $0{,}84 - 0{,}82 = 0{,}02$ pour B. Le « meilleur score » du collègue est celui d'un modèle interrogé sur ses propres exemples. Tu gardes B.
À retenir
À retenir :
- SQL :
WHEREfiltre les lignes avant le regroupement,HAVINGles groupes après. - Dans pandas, une moyenne ignore les cases vides : compte-les d'abord.
- La médiane résiste aux valeurs extrêmes ; une corrélation ne prouve pas une cause.
- Un modèle se juge sur un jeu de test qu'il n'a jamais vu.
- Classe rare : regarde précision et rappel, pas le seul taux de bonnes réponses.
- Un résultat se présente avec un graphique, une phrase et sa limite.
Sources
- Documentation de PostgreSQL 18, « Aggregate Functions » : postgresql.org.
- Documentation de pandas 3.0,
DataFrame.mean: pandas.pydata.org. - Guide de scikit-learn 1.9, « Cross-validation: evaluating estimator performance » : scikit-learn.org.