Matrice de confusion dans Sklearn : comment évaluer des modèles de classification
Updated on
Votre modèle de classification affiche 95 % d’accuracy, vous le déployez donc. Puis vous découvrez qu’il rate 80 % des cas positifs qui vous importent vraiment — transactions frauduleuses, diagnostics médicaux, produits défectueux. L’accuracy seule masque des informations critiques sur où et comment un modèle échoue.
Un seul nombre d’accuracy écrase tous les types d’erreurs en une métrique unique. Un filtre anti-spam qui laisse passer tous les spams et classe correctement tous les emails légitimes peut malgré tout obtenir une accuracy élevée si le spam ne représente que 5 % du total. Vous devez voir l’image complète : combien de positifs le modèle détecte, combien de négatifs il confond, et précisément où se situent les erreurs.
La matrice de confusion décompose les performances du modèle en quatre composantes — vrais positifs, vrais négatifs, faux positifs et faux négatifs. Combinée à des métriques dérivées comme la precision, le recall et le F1-score, elle vous donne une compréhension actionnable de ce que votre modèle réussit et de ce qu’il rate. Scikit-learn fournit confusion_matrix, classification_report et ConfusionMatrixDisplay pour rendre cette analyse simple.
Qu’est-ce qu’une matrice de confusion ?
Une matrice de confusion est un tableau qui compare les étiquettes prédites aux étiquettes réelles pour un modèle de classification. Pour une classification binaire, c’est une grille 2x2 :
| Prédit Positif | Prédit Négatif | |
|---|---|---|
| Réel Positif | Vrai Positif (TP) | Faux Négatif (FN) |
| Réel Négatif | Faux Positif (FP) | Vrai Négatif (TN) |
Chaque cellule compte le nombre d’échantillons qui tombent dans cette catégorie :
- Vrai Positif (TP) : le modèle a prédit positif, et c’était réellement positif. Correct.
- Vrai Négatif (TN) : le modèle a prédit négatif, et c’était réellement négatif. Correct.
- Faux Positif (FP) : le modèle a prédit positif, mais c’était réellement négatif. Erreur de type I.
- Faux Négatif (FN) : le modèle a prédit négatif, mais c’était réellement positif. Erreur de type II.
Matrice de confusion de base avec Sklearn
from sklearn.metrics import confusion_matrix
import numpy as np
# Actual and predicted labels
y_true = [1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1]
y_pred = [1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1]
cm = confusion_matrix(y_true, y_pred)
print(cm)
# [[5 1]
# [2 7]]Interprétation de ce résultat : sklearn organise la matrice avec la ligne 0 = négatif réel, la ligne 1 = positif réel.
| Prédit 0 | Prédit 1 | |
|---|---|---|
| Réel 0 | TN = 5 | FP = 1 |
| Réel 1 | FN = 2 | TP = 7 |
Donc le modèle a correctement identifié 5 négatifs et 7 positifs, tout en commettant 1 erreur de faux positif et 2 erreurs de faux négatif.
Extraire les valeurs individuelles
from sklearn.metrics import confusion_matrix
y_true = [1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1]
y_pred = [1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1]
cm = confusion_matrix(y_true, y_pred)
tn, fp, fn, tp = cm.ravel()
print(f"True Negatives: {tn}")
print(f"False Positives: {fp}")
print(f"False Negatives: {fn}")
print(f"True Positives: {tp}")
# True Negatives: 5
# False Positives: 1
# False Negatives: 2
# True Positives: 7Precision, Recall, F1-Score et Accuracy
Ces métriques sont dérivées directement de la matrice de confusion :
| Metric | Formula | What It Answers |
|---|---|---|
| Accuracy | (TP + TN) / (TP + TN + FP + FN) | Parmi toutes les prédictions, combien étaient correctes ? |
| Precision | TP / (TP + FP) | Parmi les positifs prédits, combien étaient réellement positifs ? |
| Recall (Sensitivity) | TP / (TP + FN) | Parmi les positifs réels, combien en avons-nous détectés ? |
| Specificity | TN / (TN + FP) | Parmi les négatifs réels, combien avons-nous correctement identifiés ? |
| F1-Score | 2 * (Precision * Recall) / (Precision + Recall) | Moyenne harmonique de la precision et du recall |
from sklearn.metrics import (
accuracy_score, precision_score, recall_score, f1_score
)
y_true = [1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1]
y_pred = [1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1]
print(f"Accuracy: {accuracy_score(y_true, y_pred):.4f}")
print(f"Precision: {precision_score(y_true, y_pred):.4f}")
print(f"Recall: {recall_score(y_true, y_pred):.4f}")
print(f"F1-Score: {f1_score(y_true, y_pred):.4f}")
# Accuracy: 0.8000
# Precision: 0.8750
# Recall: 0.7778
# F1-Score: 0.8235Quand privilégier la precision vs le recall
| Scenario | Prioritize | Why |
|---|---|---|
| Détection de spam | Precision | Les faux positifs (email légitime marqué spam) agacent les utilisateurs |
| Dépistage de maladies | Recall | Les faux négatifs (maladie manquée) sont dangereux |
| Détection de fraude | Recall | Manquer une fraude coûte plus cher qu’enquêter sur de fausses alertes |
| Résultats d’un moteur de recherche | Precision | Des résultats non pertinents dégradent l’expérience utilisateur |
| Détection de défauts en fabrication | Recall | Des produits défectueux chez les clients coûtent cher |
| Recommandation de contenu | Precision | Des recommandations non pertinentes réduisent l’engagement |
Rapport de classification (Classification Report)
Le classification_report de sklearn calcule la precision, le recall, le F1-score et le support (nombre d’occurrences réelles) pour chaque classe en un seul appel :
from sklearn.metrics import classification_report
y_true = [1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1]
y_pred = [1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1]
print(classification_report(y_true, y_pred, target_names=['Negative', 'Positive']))Output:
precision recall f1-score support
Negative 0.71 0.83 0.77 6
Positive 0.88 0.78 0.82 9
accuracy 0.80 15
macro avg 0.80 0.81 0.80 15
weighted avg 0.81 0.80 0.80 15- macro avg : moyenne non pondérée sur les classes. Traite toutes les classes de manière égale.
- weighted avg : moyenne pondérée par le support de chaque classe. Tient compte du déséquilibre de classes.
- support : nombre d’échantillons réels dans chaque classe.
Visualiser la matrice de confusion
Utiliser ConfusionMatrixDisplay
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_breast_cancer
import matplotlib.pyplot as plt
# Load and split data
data = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(
data.data, data.target, test_size=0.2, random_state=42
)
# Train model
model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
# Plot confusion matrix
cm = confusion_matrix(y_test, y_pred)
disp = ConfusionMatrixDisplay(
confusion_matrix=cm,
display_labels=data.target_names
)
disp.plot(cmap='Blues')
plt.title('Breast Cancer Classification')
plt.tight_layout()
plt.savefig('confusion_matrix.png', dpi=150)
plt.show()Utiliser Seaborn Heatmap
Pour plus de personnalisation, utilisez seaborn directement :
from sklearn.metrics import confusion_matrix
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_breast_cancer
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
# Load, split, train
data = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(
data.data, data.target, test_size=0.2, random_state=42
)
model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
# Create confusion matrix
cm = confusion_matrix(y_test, y_pred)
# Plot with seaborn
plt.figure(figsize=(8, 6))
sns.heatmap(
cm,
annot=True,
fmt='d',
cmap='Blues',
xticklabels=data.target_names,
yticklabels=data.target_names,
square=True,
linewidths=0.5
)
plt.xlabel('Predicted Label')
plt.ylabel('True Label')
plt.title('Confusion Matrix - Breast Cancer Classification')
plt.tight_layout()
plt.savefig('confusion_matrix_seaborn.png', dpi=150)
plt.show()Matrice de confusion normalisée
Les comptages bruts peuvent être trompeurs lorsque les classes ont des tailles différentes. La normalisation montre plutôt des proportions :
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_breast_cancer
import matplotlib.pyplot as plt
data = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(
data.data, data.target, test_size=0.2, random_state=42
)
model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
# Normalized confusion matrix (by true labels)
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# Raw counts
ConfusionMatrixDisplay.from_predictions(
y_test, y_pred,
display_labels=data.target_names,
cmap='Blues',
ax=axes[0]
)
axes[0].set_title('Raw Counts')
# Normalized (rows sum to 1)
ConfusionMatrixDisplay.from_predictions(
y_test, y_pred,
display_labels=data.target_names,
normalize='true',
cmap='Blues',
values_format='.2%',
ax=axes[1]
)
axes[1].set_title('Normalized by True Label')
plt.tight_layout()
plt.savefig('confusion_matrix_normalized.png', dpi=150)
plt.show()Le paramètre normalize accepte trois options :
| Value | Normalization | Use Case |
|---|---|---|
'true' | Les lignes somment à 1 (division par le nombre réel de la classe) | Voir le recall par classe |
'pred' | Les colonnes somment à 1 (division par le nombre prédit par classe) | Voir la precision par classe |
'all' | Toutes les cellules somment à 1 (division par le total) | Voir la distribution globale |
Matrice de confusion multi-classes
La matrice de confusion s’étend naturellement à plus de deux classes. Chaque ligne représente une classe réelle, et chaque colonne représente une classe prédite :
from sklearn.metrics import confusion_matrix, classification_report, ConfusionMatrixDisplay
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
# Load iris dataset (3 classes)
iris = load_iris()
X_train, X_test, y_train, y_test = train_test_split(
iris.data, iris.target, test_size=0.3, random_state=42
)
# Train and predict
model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
# Confusion matrix
cm = confusion_matrix(y_test, y_pred)
print("Confusion Matrix:")
print(cm)
# Classification report
print("\nClassification Report:")
print(classification_report(
y_test, y_pred,
target_names=iris.target_names
))
# Visualize
disp = ConfusionMatrixDisplay(
confusion_matrix=cm,
display_labels=iris.target_names
)
disp.plot(cmap='Blues')
plt.title('Iris Classification - 3 Classes')
plt.tight_layout()
plt.savefig('multi_class_confusion_matrix.png', dpi=150)
plt.show()Stratégies d’agrégation (averaging) en multi-classes
Lors du calcul de la precision, du recall et du F1 pour des problèmes multi-classes, vous devez choisir une méthode d’agrégation :
from sklearn.metrics import precision_score, recall_score, f1_score
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
iris = load_iris()
X_train, X_test, y_train, y_test = train_test_split(
iris.data, iris.target, test_size=0.3, random_state=42
)
model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
for avg in ['micro', 'macro', 'weighted']:
p = precision_score(y_test, y_pred, average=avg)
r = recall_score(y_test, y_pred, average=avg)
f1 = f1_score(y_test, y_pred, average=avg)
print(f"{avg:8s} -- Precision: {p:.4f}, Recall: {r:.4f}, F1: {f1:.4f}")| Average | Method | Best For |
|---|---|---|
micro | TP, FP, FN totaux sur toutes les classes | Quand le déséquilibre de classes compte |
macro | Moyenne non pondérée par classe | Quand toutes les classes sont aussi importantes |
weighted | Moyenne pondérée par le support | Choix par défaut pour des jeux de données déséquilibrés |
Exemple complet : évaluation de classification de bout en bout
from sklearn.metrics import (
confusion_matrix, classification_report, ConfusionMatrixDisplay,
accuracy_score, precision_score, recall_score, f1_score, roc_auc_score
)
from sklearn.model_selection import train_test_split
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.datasets import load_breast_cancer
import matplotlib.pyplot as plt
import numpy as np
# Load data
data = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(
data.data, data.target, test_size=0.2, random_state=42, stratify=data.target
)
# Build pipeline
pipeline = Pipeline([
('scaler', StandardScaler()),
('model', GradientBoostingClassifier(
n_estimators=200, max_depth=3, random_state=42
))
])
# Train
pipeline.fit(X_train, y_train)
y_pred = pipeline.predict(X_test)
y_prob = pipeline.predict_proba(X_test)[:, 1]
# Confusion matrix
cm = confusion_matrix(y_test, y_pred)
tn, fp, fn, tp = cm.ravel()
print("=" * 50)
print("MODEL EVALUATION REPORT")
print("=" * 50)
print(f"\nConfusion Matrix:")
print(f" TP={tp}, FP={fp}")
print(f" FN={fn}, TN={tn}")
print(f"\nAccuracy: {accuracy_score(y_test, y_pred):.4f}")
print(f"Precision: {precision_score(y_test, y_pred):.4f}")
print(f"Recall: {recall_score(y_test, y_pred):.4f}")
print(f"F1-Score: {f1_score(y_test, y_pred):.4f}")
print(f"ROC-AUC: {roc_auc_score(y_test, y_prob):.4f}")
print(f"\nDetailed Report:")
print(classification_report(y_test, y_pred, target_names=data.target_names))
# Visualize
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
ConfusionMatrixDisplay.from_predictions(
y_test, y_pred, display_labels=data.target_names,
cmap='Blues', ax=axes[0]
)
axes[0].set_title('Raw Counts')
ConfusionMatrixDisplay.from_predictions(
y_test, y_pred, display_labels=data.target_names,
normalize='true', values_format='.1%', cmap='Blues', ax=axes[1]
)
axes[1].set_title('Normalized')
plt.tight_layout()
plt.savefig('full_evaluation.png', dpi=150)
plt.show()Explorer les résultats de classification avec PyGWalker
Après avoir construit votre matrice de confusion, allez plus loin dans l’analyse des erreurs en explorant les données brutes de manière interactive. PyGWalker (opens in a new tab) transforme vos résultats de prédiction en une interface d’analytique visuelle « drag-and-drop » dans Jupyter :
import pandas as pd
import pygwalker as pyg
# Build results DataFrame with features and predictions
results = pd.DataFrame(X_test, columns=data.feature_names)
results['actual'] = y_test
results['predicted'] = y_pred
results['correct'] = y_test == y_pred
results['confidence'] = y_prob
# Launch interactive exploration
walker = pyg.walk(results)Filtrez les échantillons mal classés, comparez les distributions de variables entre les groupes TP/FP/FN/TN, et identifiez des patterns qui expliquent où le modèle a du mal.
Pour itérer sur des expériences de classification dans Jupyter — ajuster les seuils, tester différents modèles ou explorer des combinaisons de features — RunCell (opens in a new tab) propose un agent IA qui accélère la boucle d’expérimentation.
FAQ
Qu’est-ce qu’une matrice de confusion dans sklearn ?
Une matrice de confusion est un tableau qui montre le nombre de prédictions correctes et incorrectes pour chaque classe. Dans sklearn, confusion_matrix(y_true, y_pred) renvoie un tableau numpy 2D où les lignes représentent les classes réelles et les colonnes les classes prédites. En classification binaire, elle montre les vrais positifs, vrais négatifs, faux positifs et faux négatifs.
Comment lire une matrice de confusion ?
Dans la matrice de confusion de sklearn, les lignes sont les étiquettes réelles et les colonnes les étiquettes prédites. En binaire : en haut à gauche se trouvent les vrais négatifs (TN), en haut à droite les faux positifs (FP), en bas à gauche les faux négatifs (FN), et en bas à droite les vrais positifs (TP). Les éléments de la diagonale sont les prédictions correctes.
Quelle est la différence entre precision et recall ?
La precision mesure combien de positifs prédits sont réellement positifs (TP / (TP + FP)). Le recall mesure combien de positifs réels le modèle a capturés (TP / (TP + FN)). La precision répond à « quand le modèle dit positif, à quelle fréquence a-t-il raison ? », tandis que le recall répond à « parmi tous les positifs réels, combien le modèle en a-t-il trouvés ? ».
Quand utiliser le F1-score plutôt que l’accuracy ?
Utilisez le F1-score lorsque vos classes sont déséquilibrées. Si 95 % des échantillons sont négatifs, un modèle qui prédit toujours négatif obtient 95 % d’accuracy mais 0 % de recall sur les positifs. Le F1-score est la moyenne harmonique de la precision et du recall : il pénalise donc les modèles qui sacrifient l’un au profit de l’autre.
Comment tracer une matrice de confusion en Python ?
Utilisez ConfusionMatrixDisplay.from_predictions(y_true, y_pred) pour la méthode la plus rapide. Pour plus de personnalisation, calculez la matrice avec confusion_matrix() et tracez-la avec seaborn.heatmap(). Les deux approches prennent en charge les matrices normalisées, les palettes de couleurs personnalisées et les étiquettes de classes.
Que fait normalize='true' dans ConfusionMatrixDisplay ?
Définir normalize='true' divise chaque ligne par le nombre total d’échantillons réels de cette classe, de sorte que chaque ligne somme à 1. Cela montre le recall par classe en pourcentage. Utilisez normalize='pred' pour voir la precision par classe, ou normalize='all' pour voir la proportion globale.
Conclusion
La matrice de confusion est la base de l’évaluation des modèles de classification. L’accuracy seule est insuffisante — vous devez voir les types d’erreurs spécifiques que fait votre modèle. Utilisez confusion_matrix et classification_report de sklearn pour obtenir une vue complète, visualisez avec ConfusionMatrixDisplay ou des heatmaps seaborn pour des présentations et des rapports, et normalisez lorsque les tailles de classes diffèrent. Choisissez votre métrique principale en fonction du coût business de chaque type d’erreur : la precision quand les faux positifs sont coûteux, le recall quand les faux négatifs sont dangereux, et le F1-score quand vous avez besoin d’une mesure équilibrée.