Calibration des probabilités pour la classification à trois classes

Machine LearningMachine LearningBeginner
Pratiquer maintenant

This tutorial is from open-source community. Access the source code

💡 Ce tutoriel est traduit par l'IA à partir de la version anglaise. Pour voir la version originale, vous pouvez cliquer ici

Introduction

Ce laboratoire montre comment utiliser l'étalonnage sigmoïde pour la classification à trois classes en Python à l'aide de scikit-learn. Il montre comment l'étalonnage sigmoïde modifie les probabilités prédites et comment il peut être utilisé pour améliorer les performances du modèle.

Conseils sur la machine virtuelle

Une fois le démarrage de la machine virtuelle terminé, cliquez dans le coin supérieur gauche pour basculer vers l'onglet Carnet de notes pour accéder au carnet Jupyter pour pratiquer.

Parfois, vous devrez peut-être attendre quelques secondes pour que le carnet Jupyter ait fini de charger. La validation des opérations ne peut pas être automatisée en raison des limitations du carnet Jupyter.

Si vous rencontrez des problèmes pendant l'apprentissage, n'hésitez pas à demander à Labby. Donnez votre feedback après la session, et nous résoudrons rapidement le problème pour vous.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL sklearn(("Sklearn")) -.-> sklearn/ModelSelectionandEvaluationGroup(["Model Selection and Evaluation"]) sklearn(("Sklearn")) -.-> sklearn/UtilitiesandDatasetsGroup(["Utilities and Datasets"]) ml(("Machine Learning")) -.-> ml/FrameworkandSoftwareGroup(["Framework and Software"]) sklearn(("Sklearn")) -.-> sklearn/CoreModelsandAlgorithmsGroup(["Core Models and Algorithms"]) sklearn/CoreModelsandAlgorithmsGroup -.-> sklearn/ensemble("Ensemble Methods") sklearn/ModelSelectionandEvaluationGroup -.-> sklearn/metrics("Metrics") sklearn/ModelSelectionandEvaluationGroup -.-> sklearn/calibration("Probability Calibration") sklearn/UtilitiesandDatasetsGroup -.-> sklearn/datasets("Datasets") ml/FrameworkandSoftwareGroup -.-> ml/sklearn("scikit-learn") subgraph Lab Skills sklearn/ensemble -.-> lab-49074{{"Calibration des probabilités pour la classification à trois classes"}} sklearn/metrics -.-> lab-49074{{"Calibration des probabilités pour la classification à trois classes"}} sklearn/calibration -.-> lab-49074{{"Calibration des probabilités pour la classification à trois classes"}} sklearn/datasets -.-> lab-49074{{"Calibration des probabilités pour la classification à trois classes"}} ml/sklearn -.-> lab-49074{{"Calibration des probabilités pour la classification à trois classes"}} end

Données

Nous générons un ensemble de données de classification avec 2000 échantillons, 2 caractéristiques et 3 classes cibles. Nous divisons ensuite les données comme suit :

  • entraînement : 600 échantillons (pour entraîner le classifieur)
  • validation : 400 échantillons (pour étalonner les probabilités prédites)
  • test : 1000 échantillons
import numpy as np
from sklearn.datasets import make_blobs

np.random.seed(0)

X, y = make_blobs(
    n_samples=2000, n_features=2, centers=3, random_state=42, cluster_std=5.0
)
X_train, y_train = X[:600], y[:600]
X_valid, y_valid = X[600:1000], y[600:1000]
X_train_valid, y_train_valid = X[:1000], y[:1000]
X_test, y_test = X[1000:], y[1000:]

Ajustement et étalonnage

Nous entraînons un classifieur à forêt aléatoire avec 25 estimateurs de base (arbres) sur les données d'entraînement et de validation concaténées (1000 échantillons). Il s'agit du classifieur non étalonné.

from sklearn.ensemble import RandomForestClassifier

clf = RandomForestClassifier(n_estimators=25)
clf.fit(X_train_valid, y_train_valid)

Pour entraîner le classifieur étalonné, nous commençons avec le même classifieur à forêt aléatoire, mais l'entraînons en utilisant uniquement le sous-ensemble de données d'entraînement (600 échantillons), puis l'étalonnons, avec méthode='sigmoid', en utilisant le sous-ensemble de données de validation (400 échantillons) dans un processus en deux étapes.

from sklearn.calibration import CalibratedClassifierCV

clf = RandomForestClassifier(n_estimators=25)
clf.fit(X_train, y_train)
cal_clf = CalibratedClassifierCV(clf, method="sigmoid", cv="prefit")
cal_clf.fit(X_valid, y_valid)

Comparer les probabilités

Nous traçons un 2-simplex avec des flèches montrant le changement des probabilités prédites des échantillons de test.

import matplotlib.pyplot as plt

plt.figure(figsize=(10, 10))
colors = ["r", "g", "b"]

clf_probs = clf.predict_proba(X_test)
cal_clf_probs = cal_clf.predict_proba(X_test)
## Plot arrows
for i in range(clf_probs.shape[0]):
    plt.arrow(
        clf_probs[i, 0],
        clf_probs[i, 1],
        cal_clf_probs[i, 0] - clf_probs[i, 0],
        cal_clf_probs[i, 1] - clf_probs[i, 1],
        color=colors[y_test[i]],
        head_width=1e-2,
    )

## Plot perfect predictions, at each vertex
plt.plot([1.0], [0.0], "ro", ms=20, label="Classe 1")
plt.plot([0.0], [1.0], "go", ms=20, label="Classe 2")
plt.plot([0.0], [0.0], "bo", ms=20, label="Classe 3")

## Plot boundaries of unit simplex
plt.plot([0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], "k", label="Simplex")

## Annotate points 6 points around the simplex, and mid point inside simplex
plt.annotate(
    r"($\frac{1}{3}$, $\frac{1}{3}$, $\frac{1}{3}$)",
    xy=(1.0 / 3, 1.0 / 3),
    xytext=(1.0 / 3, 0.23),
    xycoords="data",
    arrowprops=dict(facecolor="black", shrink=0.05),
    horizontalalignment="center",
    verticalalignment="center",
)
plt.plot([1.0 / 3], [1.0 / 3], "ko", ms=5)
plt.annotate(
    r"($\frac{1}{2}$, $0$, $\frac{1}{2}$)",
    xy=(0.5, 0.0),
    xytext=(0.5, 0.1),
    xycoords="data",
    arrowprops=dict(facecolor="black", shrink=0.05),
    horizontalalignment="center",
    verticalalignment="center",
)
plt.annotate(
    r"($0$, $\frac{1}{2}$, $\frac{1}{2}$)",
    xy=(0.0, 0.5),
    xytext=(0.1, 0.5),
    xycoords="data",
    arrowprops=dict(facecolor="black", shrink=0.05),
    horizontalalignment="center",
    verticalalignment="center",
)
plt.annotate(
    r"($\frac{1}{2}$, $\frac{1}{2}$, $0$)",
    xy=(0.5, 0.5),
    xytext=(0.6, 0.6),
    xycoords="data",
    arrowprops=dict(facecolor="black", shrink=0.05),
    horizontalalignment="center",
    verticalalignment="center",
)
plt.annotate(
    r"($0$, $0$, $1$)",
    xy=(0, 0),
    xytext=(0.1, 0.1),
    xycoords="data",
    arrowprops=dict(facecolor="black", shrink=0.05),
    horizontalalignment="center",
    verticalalignment="center",
)
plt.annotate(
    r"($1$, $0$, $0$)",
    xy=(1, 0),
    xytext=(1, 0.1),
    xycoords="data",
    arrowprops=dict(facecolor="black", shrink=0.05),
    horizontalalignment="center",
    verticalalignment="center",
)
plt.annotate(
    r"($0$, $1$, $0$)",
    xy=(0, 1),
    xytext=(0.1, 1),
    xycoords="data",
    arrowprops=dict(facecolor="black", shrink=0.05),
    horizontalalignment="center",
    verticalalignment="center",
)
## Add grid
plt.grid(False)
for x in [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]:
    plt.plot([0, x], [x, 0], "k", alpha=0.2)
    plt.plot([0, 0 + (1 - x) / 2], [x, x + (1 - x) / 2], "k", alpha=0.2)
    plt.plot([x, x + (1 - x) / 2], [0, 0 + (1 - x) / 2], "k", alpha=0.2)

plt.title("Changement des probabilités prédites sur les échantillons de test après étalonnage sigmoïde")
plt.xlabel("Probabilité de la classe 1")
plt.ylabel("Probabilité de la classe 2")
plt.xlim(-0.05, 1.05)
plt.ylim(-0.05, 1.05)
_ = plt.legend(loc="best")

Comparaison de la perte logarithmique

Nous comparons la perte logarithmique des classifieurs non étalonné et étalonné sur les prédictions des 1000 échantillons de test.

from sklearn.metrics import log_loss

score = log_loss(y_test, clf_probs)
cal_score = log_loss(y_test, cal_clf_probs)

print("Perte logarithmique de")
print(f" * classifieur non étalonné: {score:.3f}")
print(f" * classifieur étalonné: {cal_score:.3f}")

Générer une grille et tracer

Nous générons une grille de probabilités non étalonnées possibles sur le 2-simplex, calculons les probabilités étalonnées correspondantes et traçons des flèches pour chacune. Les flèches sont colorées selon la plus haute probabilité non étalonnée. Cela illustre la carte d'étalonnage apprise :

plt.figure(figsize=(10, 10))
## Générer une grille de valeurs de probabilité
p1d = np.linspace(0, 1, 20)
p0, p1 = np.meshgrid(p1d, p1d)
p2 = 1 - p0 - p1
p = np.c_[p0.ravel(), p1.ravel(), p2.ravel()]
p = p[p[:, 2] >= 0]

## Utiliser les trois étalonneurs par classe pour calculer les probabilités étalonnées
calibrated_classifier = cal_clf.calibrated_classifiers_[0]
prediction = np.vstack(
    [
        calibrator.predict(this_p)
        for calibrator, this_p in zip(calibrated_classifier.calibrators, p.T)
    ]
).T

## Renormaliser les prédictions étalonnées pour vous assurer qu'elles restent à l'intérieur du
## simplex. Cette même étape de renormalisation est effectuée internement par la
## méthode predict de CalibratedClassifierCV pour les problèmes multiclasse.
prediction /= prediction.sum(axis=1)[:, None]

## Tracer les changements dans les probabilités prédites induits par les étalonneurs
for i in range(prediction.shape[0]):
    plt.arrow(
        p[i, 0],
        p[i, 1],
        prediction[i, 0] - p[i, 0],
        prediction[i, 1] - p[i, 1],
        head_width=1e-2,
        color=colors[np.argmax(p[i])],
    )

## Tracer les limites du simplex unitaire
plt.plot([0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], "k", label="Simplex")

plt.grid(False)
for x in [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]:
    plt.plot([0, x], [x, 0], "k", alpha=0.2)
    plt.plot([0, 0 + (1 - x) / 2], [x, x + (1 - x) / 2], "k", alpha=0.2)
    plt.plot([x, x + (1 - x) / 2], [0, 0 + (1 - x) / 2], "k", alpha=0.2)

plt.title("Carte d'étalonnage sigmoïde apprise")
plt.xlabel("Probabilité de la classe 1")
plt.ylabel("Probabilité de la classe 2")
plt.xlim(-0.05, 1.05)
plt.ylim(-0.05, 1.05)

plt.show()

Sommaire

Ce laboratoire a montré comment utiliser l'étalonnage sigmoïde pour la classification à trois classes en Python à l'aide de scikit-learn. Il a démontré l'impact de l'étalonnage sur les probabilités prédites et comment il peut être utilisé pour améliorer les performances du modèle.