Skip to content

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 PositifPrédit Négatif
Réel PositifVrai Positif (TP)Faux Négatif (FN)
Réel NégatifFaux 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 0Prédit 1
Réel 0TN = 5FP = 1
Réel 1FN = 2TP = 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:  7

Precision, Recall, F1-Score et Accuracy

Ces métriques sont dérivées directement de la matrice de confusion :

MetricFormulaWhat It Answers
Accuracy(TP + TN) / (TP + TN + FP + FN)Parmi toutes les prédictions, combien étaient correctes ?
PrecisionTP / (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 ?
SpecificityTN / (TN + FP)Parmi les négatifs réels, combien avons-nous correctement identifiés ?
F1-Score2 * (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.8235

Quand privilégier la precision vs le recall

ScenarioPrioritizeWhy
Détection de spamPrecisionLes faux positifs (email légitime marqué spam) agacent les utilisateurs
Dépistage de maladiesRecallLes faux négatifs (maladie manquée) sont dangereux
Détection de fraudeRecallManquer une fraude coûte plus cher qu’enquêter sur de fausses alertes
Résultats d’un moteur de recherchePrecisionDes résultats non pertinents dégradent l’expérience utilisateur
Détection de défauts en fabricationRecallDes produits défectueux chez les clients coûtent cher
Recommandation de contenuPrecisionDes 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 :

ValueNormalizationUse 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}")
AverageMethodBest For
microTP, FP, FN totaux sur toutes les classesQuand le déséquilibre de classes compte
macroMoyenne non pondérée par classeQuand toutes les classes sont aussi importantes
weightedMoyenne pondérée par le supportChoix 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.

📚