Tu entends parler de machine learning partout, mais tu n'as jamais osé franchir le pas ? Ce tutoriel est fait pour toi. On va entraîner ton premier vrai modèle de machine learning en une vingtaine de minutes, avec scikit-learn — la bibliothèque de référence du machine learning classique en Python. Pas besoin d'être mathématicien, pas besoin de GPU : juste un ordinateur, Python installé, et l'envie de voir un algorithme apprendre tout seul à partir de données.
Le machine learning, sans le jargon
Le principe du machine learning supervisé est simple : tu montres des exemples à un algorithme, chaque exemple étant accompagné de sa bonne réponse, et l'algorithme apprend la relation qui les relie. Une fois entraîné, il est capable de prédire la réponse pour des exemples qu'il n'a jamais vus.
Un exemple classique : à partir de la longueur et de la largeur des pétales d'une fleur, prédire son espèce. C'est exactement ce que fait le célèbre jeu de données Iris, livré avec scikit-learn, et c'est ce qu'on va utiliser. C'est un problème de classification : la variable à prédire (l'espèce) prend un nombre fini de valeurs.
Le vocabulaire de base à connaître tient en trois termes. Les caractéristiques (ou features) sont les variables d'entrée, ici les mesures des pétales. L'étiquette (ou label, ou cible) est la variable à prédire, ici l'espèce. Et le modèle est l'objet mathématique qui apprend la relation entre les deux. Toute la discipline se résume à bien choisir ces trois ingrédients.
Pourquoi scikit-learn ? Parce que c'est l'outil le plus mature et le plus pédagogique pour ce type de problème. Son API est d'une régularité remarquable : tous les modèles s'utilisent avec les mêmes méthodes fit(), predict() et score(). Une fois que tu maîtrises un modèle, tu sais les utiliser tous.
Prérequis : installer scikit-learn
L'installation se fait en une commande. scikit-learn s'appuie sur NumPy et SciPy, installés automatiquement comme dépendances.
pip install scikit-learnOn vérifie l'installation et on importe de quoi travailler. On aura aussi besoin de pandas pour la lecture des données, et de matplotlib si tu veux tracer des courbes.
import sklearn
print(sklearn.__version__)Charger et explorer le dataset Iris
scikit-learn embarque quelques jeux de données d'exemple, dont Iris. On le charge et on regarde à quoi il ressemble.
from sklearn.datasets import load_iris
import pandas as pd
iris = load_iris()
X = iris.data # les caractéristiques : 4 mesures par fleur
y = iris.target # les étiquettes : 0, 1 ou 2 (les 3 espèces)
# On transforme en DataFrame pour y voir clair
df = pd.DataFrame(X, columns=iris.feature_names)
df["espece"] = y
print(df.head())
print(df["espece"].value_counts())Chaque fleur est décrite par quatre mesures : la longueur et la largeur des sépales, et la longueur et la largeur des pétales. L'étiquette est un entier de 0 à 2, chaque valeur correspondant à une espèce. Le jeu de données est équilibré : 50 fleurs par espèce, 150 au total. L'objectif est d'apprendre à prédire l'espèce à partir des quatre mesures.
Ce jeu de données est idéal pour débuter : il est petit, propre, et les trois espèces sont bien séparées. Résultat, un modèle simple suffit à atteindre de très bons scores, ce qui te permet de te concentrer sur la méthode plutôt que sur les difficultés des données.
Séparer les données en train et test
C'est l'étape la plus importante du processus, et la plus souvent bâclée par les débutants. Pour savoir si ton modèle a vraiment appris quelque chose de général — et pas simplement mémorisé ses exemples — tu dois le tester sur des données qu'il n'a jamais vues. On découpe donc le jeu de données en deux : une partie pour l'entraînement, une partie pour l'évaluation.
from sklearn.model_selection import train_test_split
# 80 % pour l'entraînement, 20 % pour le test
# random_state fige le hasard pour que le découpage soit reproductible
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
print(f"Entraînement : {len(X_train)} exemples")
print(f"Test : {len(X_test)} exemples")Le paramètre random_state fixe la graine du générateur aléatoire : sans lui, le découpage changerait à chaque exécution et tes résultats ne seraient pas reproductibles. C'est une bonne habitude à prendre dès maintenant. Quant à la répartition 80/20, c'est un point de départ raisonnable : assez d'exemples pour bien entraîner, assez pour évaluer honnêtement.
Entraîner ton premier modèle
On choisit un modèle simple et interprétable pour commencer : un arbre de décision. Il apprend une série de règles du type « si la longueur du pétale est supérieure à 2,45 cm, alors... ». L'entraînement tient en une ligne :
from sklearn.tree import DecisionTreeClassifier
# On crée le modèle puis on l'entraîne sur les données d'entraînement
modele = DecisionTreeClassifier(random_state=42, max_depth=3)
modele.fit(X_train, y_train)
print("Modèle entraîné !")max_depth limite la profondeur de l'arbre. Pourquoi se limiter ? Parce qu'un arbre trop profond mémorise les exemples au lieu d'apprendre la tendance générale : c'est le sur-apprentissage, sur lequel on revient plus bas. Une profondeur de 3 donne un modèle simple, robuste et facile à expliquer.
L'intérêt de l'arbre de décision pour débuter, c'est qu'on peut littéralement le lire. Chaque noeud est une question, chaque branche une réponse. Tu peux tracer l'arbre et voir exactement pourquoi le modèle a pris telle décision — un luxe que n'offrent pas les modèles plus complexes comme les réseaux de neurones.
Évaluer le modèle : prédire et mesurer
Le moment de vérité : on demande au modèle de prédire les espèces des données de test, puis on compare ses prédictions à la réalité.
from sklearn.metrics import accuracy_score, classification_report
predictions = modele.predict(X_test)
# La précision : proportion de bonnes réponses
print(f"Précision : {accuracy_score(y_test, predictions):.2f}")
# Le rapport détaillé, classe par classe
print(classification_report(y_test, predictions, target_names=iris.target_names))La précision (accuracy) te donne le score global : la proportion de prédictions correctes. Mais ce n'est pas toujours suffisant. Le classification_report te montre, pour chaque espèce, la précision, le rappel et le F1-score — trois métriques complémentaires qui révèlent comment le modèle se comporte classe par classe. Sur Iris, un arbre de profondeur 3 atteint typiquement plus de 95 % de bonnes réponses, ce qui est excellent pour un premier modèle.
Lire une matrice de confusion
Une autre façon de voir les erreurs du modèle est la matrice de confusion : un tableau qui croise les espèces réelles et les espèces prédites. Chaque case indique combien de fleurs d'une espèce donnée ont été classées dans telle catégorie.
from sklearn.metrics import confusion_matrix
matrice = confusion_matrix(y_test, predictions)
print(matrice)Sur la diagonale, tu trouves les bonnes prédictions ; partout ailleurs, les confusions. C'est l'outil le plus parlant pour repérer les paires de classes que le modèle a du mal à distinguer — par exemple deux espèces de fleurs aux pétales très proches.
Comprendre le sur-apprentissage
C'est LE concept qui sépare les bons modèles des modèles trompeurs. Un modèle en sur-apprentissage est excellent sur ses données d'entraînement mais médiocre sur des données nouvelles : il a appris par cœur au lieu de généraliser. On le détecte en comparant le score d'entraînement et le score de test :
print(f"Score entraînement : {modele.score(X_train, y_train):.2f}")
print(f"Score test : {modele.score(X_test, y_test):.2f}")Si le score d'entraînement est proche de 1 mais que le score de test s'effondre, c'est le signe d'un sur-apprentissage. Les remèdes classiques : limiter la complexité du modèle (comme on l'a fait avec max_depth), fournir plus de données, ou régulariser. À l'inverse, si les deux scores sont faibles, le modèle est trop simple : c'est le sous-apprentissage, et il faut un modèle plus expressif.
Retiens la métaphore : un modèle en sur-apprentissage est un élève qui a appris ses annales par cœur et panique le jour de l'examen ; un modèle en sous-apprentissage est un élève qui n'a pas assez travaillé. Le bon modèle est celui qui a compris le principe général et sait l'appliquer à des cas nouveaux.
Un pipeline complet et propre
Dans un vrai projet, tu ne te contentes pas d'un modèle nu. Tu enchaînes plusieurs étapes : normaliser les caractéristiques, puis entraîner le modèle. scikit-learn propose l'objet Pipeline pour chaîner ces étapes de façon propre et éviter les fuites de données. On en profite pour changer de modèle et passer à un classifieur plus puissant, la forêt aléatoire :
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestClassifier
# Le pipeline : normalisation des données, puis forêt aléatoire
pipeline = make_pipeline(
StandardScaler(),
RandomForestClassifier(n_estimators=100, random_state=42),
)
pipeline.fit(X_train, y_train)
print(f"Précision : {pipeline.score(X_test, y_test):.2f}")StandardScaler centre et réduit chaque caractéristique pour qu'elle ait une moyenne nulle et un écart-type unitaire. C'est important pour certains modèles, et ça ne coûte rien de le faire systématiquement. La forêt aléatoire, elle, agrège des centaines d'arbres de décision pour produire une prédiction plus stable et plus précise qu'un arbre unique.
L'intérêt du pipeline dépasse la simple commodité : il garantit que les mêmes transformations sont appliquées à l'entraînement et à la prédiction. C'est la parade contre les fuites de données — le biais sournois qui survient quand tu calcules tes statistiques de normalisation sur l'ensemble des données, y compris celles que tu aurais dû garder pour le test.
La validation croisée pour un score fiable
Un seul découpage train/test peut être trompeur si le hasard tombe mal. La validation croisée est plus robuste : elle découpe les données en plusieurs sous-ensembles, entraîne et évalue le modèle plusieurs fois, et moyenne les scores.
from sklearn.model_selection import cross_val_score
scores = cross_val_score(pipeline, X, y, cv=5)
print(f"Scores : {scores}")
print(f"Moyenne : {scores.mean():.2f} (+/- {scores.std():.2f})")cv=5 signifie que les données sont découpées en 5 parties : le modèle est entraîné 5 fois, chaque fois sur 4 parties et évalué sur la cinquième. La moyenne des scores est une estimation bien plus fiable de la performance réelle du modèle.
Sauvegarder et réutiliser le modèle
Un modèle entraîné n'a de valeur que si tu peux le réutiliser plus tard, sans refaire l'entraînement. joblib sérialise le modèle sur disque :
import joblib
# Sauvegarder le pipeline complet (normalisation + modèle)
joblib.dump(pipeline, "modele_iris.joblib")
# Le recharger plus tard, dans un autre script ou en production
modele_charge = joblib.load("modele_iris.joblib")
# Prédire l'espèce d'une nouvelle fleur (4 mesures)
nouvelle_fleur = [[5.1, 3.5, 1.4, 0.2]]
prediction = modele_charge.predict(nouvelle_fleur)
print(f"Espèce prédite : {iris.target_names[prediction[0]]}")Remarque qu'on sauvegarde le pipeline entier, pas seulement le modèle : ainsi, la normalisation est rechargée avec le modèle, et tu ne risques pas d'oublier une étape de prétraitement au moment de prédire. C'est un détail qui t'évitera bien des bugs en production.
Visualiser l'arbre de décision
L'un des grands avantages de l'arbre de décision, c'est qu'on peut le représenter graphiquement et le lire comme un organigramme. Chaque noeud pose une question, chaque branche est une réponse, et les feuilles donnent la prédiction finale. C'est précieux pour comprendre et expliquer tes décisions.
from sklearn.tree import plot_tree
import matplotlib.pyplot as plt
plt.figure(figsize=(12, 8))
plot_tree(modele, feature_names=iris.feature_names,
class_names=iris.target_names, filled=True)
plt.show()Sur le tracé, tu verras que la toute première question porte sur la largeur du pétale — c'est la caractéristique la plus discriminante, celle qui sépare le mieux les espèces. Cette lisibilité est une raison majeure de choisir un arbre de décision quand tu dois justifier tes prédictions auprès d'un client ou d'une équipe non technique.
Choisir le bon modèle
Il n'existe pas de modèle universellement meilleur : tout dépend de tes données et de ton problème. Voici un aperçu des classifieurs les plus courants de scikit-learn et de leurs cas d'usage :
- DecisionTreeClassifier : simple et interprétable, mais sujet au sur-apprentissage s'il n'est pas limité.
- RandomForestClassifier : très robuste, précis, peu sensible au bruit ; un excellent choix par défaut.
- LogisticRegression : rapide et efficace quand la relation entre les variables est à peu près linéaire.
- SVC (machines à vecteurs de support) : puissant sur les petits jeux de données bien séparés.
- KNeighborsClassifier : intuitif (il regarde les exemples les plus proches), mais lent sur de gros volumes.
La bonne nouvelle, c'est que grâce à l'API uniforme de scikit-learn, changer de modèle revient à changer deux lignes : l'import et l'instanciation. Le reste du code — fit, predict, score — ne bouge pas. N'hésite donc pas à en essayer plusieurs et à comparer leurs scores sur tes données de test.
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
# Le même entraînement, trois modèles différents
modeles = {
"Forêt aléatoire": RandomForestClassifier(n_estimators=100, random_state=42),
"Régression logistique": LogisticRegression(max_iter=200),
"SVM": SVC(),
}
for nom, m in modeles.items():
m.fit(X_train, y_train)
print(f"{nom:24} -> {m.score(X_test, y_test):.2f}")Et la régression, alors ?
On a traité la classification, où la sortie est une catégorie. Mais le machine learning sait aussi prédire des valeurs continues : le prix d'une maison, la température de demain, le nombre de visiteurs d'un site. On parle alors de régression. La bonne nouvelle, c'est que la recette est exactement la même — seuls le modèle et la métrique changent.
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error
from sklearn.model_selection import train_test_split
# Un mini-jeu de données : la taille d'une maison et son prix
X = [[35], [50], [65], [80], [110], [130]] # surface en m²
y = [120000, 150000, 180000, 220000, 280000, 330000] # prix en euros
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=0
)
modele = LinearRegression()
modele.fit(X_train, y_train)
# L'erreur moyenne en euros sur le jeu de test
pred = modele.predict(X_test)
print(f"Erreur moyenne : {mean_absolute_error(y_test, pred):.0f} euros")Remarque la symétrie : on retrouve train_test_split, fit et predict, identiques à la classification. Seule la métrique change — ici l'erreur absolue moyenne, qui s'exprime dans la même unité que la cible. C'est toute la force de scikit-learn : une fois la logique comprise, passer de la classification à la régression est un simple changement de modèle.
Conclusion
Tu viens de franchir la ligne : tu as chargé des données, séparé l'entraînement du test, entraîné un premier modèle, mesuré sa performance de plusieurs façons, compris le sur-apprentissage, construit un pipeline complet et sauvegardé le tout. C'est le squelette de n'importe quel projet de machine learning supervisé, de la classification de fleurs à la détection de fraude.
La suite logique : applique exactement la même recette à un problème qui te parle — prédire un prix, classer des emails, détecter une anomalie. Change le dataset, garde la méthode. C'est en répétant ce cycle que tu développeras l'intuition qui distingue un bon praticien d'un simple exécutant.






