Оценка многоклассовых классификаторов с использованием ROC с помощью Scikit - learn

Machine LearningMachine LearningBeginner
Практиковаться сейчас

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

💡 Этот учебник переведен с английского с помощью ИИ. Чтобы просмотреть оригинал, вы можете перейти на английский оригинал

Введение

В этом практическом занятии показано, как использовать метрику Receiver Operating Characteristic (ROC) для оценки качества многоклассовых классификаторов с использованием библиотеки Scikit-learn.

Советы по работе с ВМ

После запуска виртуальной машины щелкните в левом верхнем углу, чтобы переключиться на вкладку Notebook и получить доступ к Jupyter Notebook для практики.

Иногда вам может потребоваться подождать несколько секунд, пока Jupyter Notebook не загрузится полностью. Проверка операций не может быть автоматизирована из-за ограничений Jupyter Notebook.

Если вы столкнетесь с проблемами во время обучения, не стесняйтесь обращаться к Labby. Оставьте отзыв после занятия, и мы оперативно решим проблему для вас.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL sklearn(("Sklearn")) -.-> sklearn/CoreModelsandAlgorithmsGroup(["Core Models and Algorithms"]) sklearn(("Sklearn")) -.-> sklearn/DataPreprocessingandFeatureEngineeringGroup(["Data Preprocessing and Feature Engineering"]) sklearn(("Sklearn")) -.-> sklearn/ModelSelectionandEvaluationGroup(["Model Selection and Evaluation"]) sklearn(("Sklearn")) -.-> sklearn/UtilitiesandDatasetsGroup(["Utilities and Datasets"]) ml(("Machine Learning")) -.-> ml/FrameworkandSoftwareGroup(["Framework and Software"]) sklearn/CoreModelsandAlgorithmsGroup -.-> sklearn/linear_model("Linear Models") sklearn/DataPreprocessingandFeatureEngineeringGroup -.-> sklearn/preprocessing("Preprocessing and Normalization") sklearn/ModelSelectionandEvaluationGroup -.-> sklearn/model_selection("Model Selection") sklearn/ModelSelectionandEvaluationGroup -.-> sklearn/metrics("Metrics") sklearn/UtilitiesandDatasetsGroup -.-> sklearn/datasets("Datasets") ml/FrameworkandSoftwareGroup -.-> ml/sklearn("scikit-learn") subgraph Lab Skills sklearn/linear_model -.-> lab-49275{{"Оценка многоклассовых классификаторов с использованием ROC с помощью Scikit - learn"}} sklearn/preprocessing -.-> lab-49275{{"Оценка многоклассовых классификаторов с использованием ROC с помощью Scikit - learn"}} sklearn/model_selection -.-> lab-49275{{"Оценка многоклассовых классификаторов с использованием ROC с помощью Scikit - learn"}} sklearn/metrics -.-> lab-49275{{"Оценка многоклассовых классификаторов с использованием ROC с помощью Scikit - learn"}} sklearn/datasets -.-> lab-49275{{"Оценка многоклассовых классификаторов с использованием ROC с помощью Scikit - learn"}} ml/sklearn -.-> lab-49275{{"Оценка многоклассовых классификаторов с использованием ROC с помощью Scikit - learn"}} end

Загрузка и подготовка данных

Начнем с загрузки датасета iris и подготовки его для оценки классификатора с использованием метрики ROC.

import numpy as np
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split

iris = load_iris()
target_names = iris.target_names
X, y = iris.data, iris.target
y = iris.target_names[y]

## Добавляем шумовые признаки, чтобы сделать задачу более сложной
random_state = np.random.RandomState(0)
n_samples, n_features = X.shape
n_classes = len(np.unique(y))
X = np.concatenate([X, random_state.randn(n_samples, 200 * n_features)], axis=1)

## Разделяем данные на обучающую и тестовую выборки
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, stratify=y, random_state=0)

One-vs-Rest многоклассовая ROC

Многоклассовая стратегия One-vs-the-Rest (OvR) состоит в вычислении кривой ROC для каждого из n_classes. На каждом этапе определенный класс рассматривается как положительный класс, а остальные классы рассматриваются как единый негативный класс. На этом этапе показано, как вычислить кривую ROC с использованием многоклассовой стратегии OvR.

from sklearn.preprocessing import LabelBinarizer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_curve, roc_auc_score
import matplotlib.pyplot as plt
from sklearn.metrics import RocCurveDisplay

## Бинаризация целевого признака с использованием стратегии OvR
label_binarizer = LabelBinarizer().fit(y_train)
y_onehot_test = label_binarizer.transform(y_test)

## Обучение модели логистической регрессии
classifier = LogisticRegression()
y_score = classifier.fit(X_train, y_train).predict_proba(X_test)

## Вычисление кривой ROC и значения ROC AUC для каждого класса
fpr, tpr, roc_auc = dict(), dict(), dict()
for i in range(n_classes):
    fpr[i], tpr[i], _ = roc_curve(y_onehot_test[:, i], y_score[:, i])
    roc_auc[i] = roc_auc_score(y_onehot_test[:, i], y_score[:, i])

## Вычисление микро-средней кривой ROC и площади под кривой
fpr["micro"], tpr["micro"], _ = roc_curve(y_onehot_test.ravel(), y_score.ravel())
roc_auc["micro"] = roc_auc_score(y_onehot_test, y_score, multi_class="ovr", average="micro")

## Вычисление макро-средней кривой ROC и площади под кривой
## Агрегация истинных/ложных положительных долей для каждого класса
fpr["macro"], tpr["macro"] = [], []
for i in range(n_classes):
    fpr_averaged, tpr_averaged = [], []
    for j in range(n_classes):
        if i!= j:
            fpr_averaged += list(fpr[j])
            tpr_averaged += list(tpr[j])
    fpr_averaged = np.array(fpr_averaged)
    tpr_averaged = np.array(tpr_averaged)
    fpr["macro"].append(fpr_averaged)
    tpr["macro"].append(tpr_averaged)
fpr["macro"] = np.concatenate(fpr["macro"])
tpr["macro"] = np.concatenate(tpr["macro"])
roc_auc["macro"] = roc_auc_score(y_onehot_test, y_score, multi_class="ovr", average="macro")

## Построение кривых ROC для каждого класса и микро/макро-средних значений
fig, ax = plt.subplots(figsize=(6, 6))
colors = ["aqua", "darkorange", "cornflowerblue"]
for i, color in zip(range(n_classes), colors):
    RocCurveDisplay.from_predictions(
        y_onehot_test[:, i],
        y_score[:, i],
        name=f"ROC кривая класса {target_names[i]} (AUC = {roc_auc[i]:.2f})",
        color=color,
        ax=ax,
        plot_micro=False,
        plot_macro=False,
    )

RocCurveDisplay.from_predictions(
    y_onehot_test.ravel(),
    y_score.ravel(),
    name=f"Микро-средняя ROC кривая (AUC = {roc_auc['micro']:.2f})",
    color="deeppink",
    linestyle=":",
    linewidth=4,
    ax=ax,
)

plt.plot(
    fpr["macro"],
    tpr["macro"],
    label=f"Макро-средняя ROC кривая (AUC = {roc_auc['macro']:.2f})",
    color="navy",
    linestyle=":",
    linewidth=4,
)

plt.plot([0, 1], [0, 1], "k--", label="Уровень случайности")
plt.axis("square")
plt.xlabel("Доля ложных положительных")
plt.ylabel("Доля истинных положительных")
plt.title("One-vs-Rest ROC кривые")
plt.legend()
plt.show()

One-vs-One многоклассовая ROC

Многоклассовая стратегия One-vs-One (OvO) состоит в обучении одного классификатора для каждой пары классов. Поскольку это требует обучения n_classes * (n_classes - 1) / 2 классификаторов, этот метод обычно работает медленнее, чем One-vs-Rest, из-за своей сложности O(n_classes ^2). На этом этапе показано, как вычислить кривую ROC с использованием многоклассовой стратегии OvO.

pair_list = [(0, 1), (1, 2), (0, 2)]
pair_scores = []
mean_tpr = dict()

## Вычисление кривой ROC и значения ROC AUC для каждой пары классов
for ix, (label_a, label_b) in enumerate(pair_list):
    a_mask = y_test == target_names[label_a]
    b_mask = y_test == target_names[label_b]
    ab_mask = np.logical_or(a_mask, b_mask)

    a_true = a_mask[ab_mask]
    b_true = b_mask[ab_mask]

    idx_a = np.flatnonzero(label_binarizer.classes_ == target_names[label_a])[0]
    idx_b = np.flatnonzero(label_binarizer.classes_ == target_names[label_b])[0]

    fpr_a, tpr_a, _ = roc_curve(a_true, y_score[ab_mask, idx_a])
    fpr_b, tpr_b, _ = roc_curve(b_true, y_score[ab_mask, idx_b])

    mean_tpr[ix] = np.zeros_like(fpr_grid)
    mean_tpr[ix] += np.interp(fpr_grid, fpr_a, tpr_a)
    mean_tpr[ix] += np.interp(fpr_grid, fpr_b, tpr_b)
    mean_tpr[ix] /= 2
    mean_score = auc(fpr_grid, mean_tpr[ix])
    pair_scores.append(mean_score)

    fig, ax = plt.subplots(figsize=(6, 6))
    plt.plot(
        fpr_grid,
        mean_tpr[ix],
        label=f"Mean {target_names[label_a]} vs {target_names[label_b]} (AUC = {mean_score :.2f})",
        linestyle=":",
        linewidth=4,
    )
    RocCurveDisplay.from_predictions(
        a_true,
        y_score[ab_mask, idx_a],
        ax=ax,
        name=f"{target_names[label_a]} as positive class",
    )
    RocCurveDisplay.from_predictions(
        b_true,
        y_score[ab_mask, idx_b],
        ax=ax,
        name=f"{target_names[label_b]} as positive class",
        plot_chance_level=True,
    )
    plt.axis("square")
    plt.xlabel("Доля ложных положительных")
    plt.ylabel("Доля истинных положительных")
    plt.title(f"{target_names[idx_a]} vs {target_names[idx_b]} ROC curves")
    plt.legend()
    plt.show()

## Вычисление макро-средней кривой ROC и значения ROC AUC
mean_tpr = np.zeros_like(fpr_grid)
for ix in range(len(pair_list)):
    mean_tpr += mean_tpr[ix]
mean_tpr /= len(pair_list)

macro_roc_auc_ovo = roc_auc_score(y_test, y_score, multi_class="ovo", average="macro")

plt.plot(
    fpr_grid,
    mean_tpr,
    label=f"Macro-average ROC curve (AUC = {macro_roc_auc_ovo:.2f})",
    linestyle=":",
    linewidth=4,
)

plt.plot([0, 1], [0, 1], "k--", label="Уровень случайности")
plt.axis("square")
plt.xlabel("Доля ложных положительных")
plt.ylabel("Доля истинных положительных")
plt.title("One-vs-One ROC curves")
plt.legend()
plt.show()

Резюме

В этом практическом занятии мы узнали, как оценить производительность многоклассового классификатора с использованием кривой ROC и значения ROC AUC. Мы показали, как вычислить кривые ROC с использованием многоклассовых стратегий One-vs-Rest (OvR) и One-vs-One (OvO). Также мы показали, как вычислить микро- и макро-средние кривые ROC и значения ROC AUC с использованием Scikit-learn.