不均衡な分類のための Precision-Recall メトリック

Machine LearningMachine LearningBeginner
オンラインで実践に進む

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

💡 このチュートリアルは英語版からAIによって翻訳されています。原文を確認するには、 ここをクリックしてください

はじめに

このチュートリアルでは、Precision-Recall メトリックを使用して分類器の出力品質を評価する方法について、手順を追って説明します。Precision-Recall 曲線は、クラスが非常に不均衡な場合の予測の成功度を測るのに役立つ尺度です。情報検索において、精度は結果の関連性の尺度であり、再現率は返される真に関連する結果の数の尺度です。

VM のヒント

VM の起動が完了したら、左上隅をクリックして ノートブック タブに切り替え、Jupyter Notebook を使って練習しましょう。

Jupyter Notebook の読み込みには数秒かかる場合があります。Jupyter Notebook の制限により、操作の検証を自動化することはできません。

学習中に問題がある場合は、Labby にお問い合わせください。セッション後にフィードバックを提供してください。すぐに問題を解決いたします。

データセットとモデル

2 種類のアヤメを識別するために、アヤメのデータセットと線形サポートベクター分類器(Linear SVC)を使用します。まず、必要なライブラリをインポートしてデータセットを読み込みます。

import numpy as np
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import LinearSVC

X, y = load_iris(return_X_y=True)

次に、データセットにノイズ付きの特徴量を追加し、訓練用とテスト用のセットに分割します。

random_state = np.random.RandomState(0)
n_samples, n_features = X.shape
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 < 2], y[y < 2], test_size=0.5, random_state=random_state
)

最後に、StandardScaler を使ってデータをスケーリングし、訓練データに線形サポートベクター分類器を適合させます。

classifier = make_pipeline(
    StandardScaler(), LinearSVC(random_state=random_state, dual="auto")
)
classifier.fit(X_train, y_train)

Precision-Recall 曲線を描画する

Precision-Recall 曲線を描画するには、sklearn.metrics ライブラリの PrecisionRecallDisplay クラスを使用します。曲線を計算するには、from_estimator または from_predictions メソッドのどちらかを使用できます。from_estimator メソッドは、曲線を描画する前に予測を計算しますが、from_predictions メソッドは予測スコアを提供する必要があります。

from sklearn.metrics import PrecisionRecallDisplay

## from_estimator メソッドを使用
display = PrecisionRecallDisplay.from_estimator(
    classifier, X_test, y_test, name="LinearSVC", plot_chance_level=True
)
_ = display.ax_.set_title("2-class Precision-Recall curve")

## from_predictions メソッドを使用
y_score = classifier.decision_function(X_test)

display = PrecisionRecallDisplay.from_predictions(
    y_test, y_score, name="LinearSVC", plot_chance_level=True
)
_ = display.ax_.set_title("2-class Precision-Recall curve")

多クラス分類のための Precision-Recall 曲線を描画する

Precision-Recall 曲線は、マルチラベル設定をサポートしていません。ただし、このケースをどのように処理するかを決めることができます。マルチラベルデータセットを作成し、OneVsRestClassifier を使用してフィットと予測を行い、その後 Precision-Recall 曲線を描画します。

from sklearn.preprocessing import label_binarize
from sklearn.multiclass import OneVsRestClassifier
from sklearn.metrics import precision_recall_curve
from sklearn.metrics import average_precision_score

## マルチラベルデータを作成
Y = label_binarize(y, classes=[0, 1, 2])
n_classes = Y.shape[1]
X_train, X_test, Y_train, Y_test = train_test_split(
    X, Y, test_size=0.5, random_state=random_state
)

## OneVsRestClassifier を使用してフィットと予測
classifier = OneVsRestClassifier(
    make_pipeline(StandardScaler(), LinearSVC(random_state=random_state, dual="auto"))
)
classifier.fit(X_train, Y_train)
y_score = classifier.decision_function(X_test)

## 各クラスの精度と再現率を計算
precision = dict()
recall = dict()
average_precision = dict()
for i in range(n_classes):
    precision[i], recall[i], _ = precision_recall_curve(Y_test[:, i], y_score[:, i])
    average_precision[i] = average_precision_score(Y_test[:, i], y_score[:, i])

## マイクロ平均精度と再現率を計算
precision["micro"], recall["micro"], _ = precision_recall_curve(Y_test.ravel(), y_score.ravel())
average_precision["micro"] = average_precision_score(Y_test, y_score, average="micro")

## マイクロ平均 Precision-Recall 曲線を描画
display = PrecisionRecallDisplay(
    recall=recall["micro"],
    precision=precision["micro"],
    average_precision=average_precision["micro"],
    prevalence_pos_label=Counter(Y_test.ravel())[1] / Y_test.size,
)
display.plot(plot_chance_level=True)
_ = display.ax_.set_title("Micro-averaged over all classes")

## 各クラスの Precision-Recall 曲線と iso-f1 曲線を描画
colors = cycle(["navy", "turquoise", "darkorange", "cornflowerblue", "teal"])
_, ax = plt.subplots(figsize=(7, 8))
f_scores = np.linspace(0.2, 0.8, num=4)
lines, labels = [], []
for f_score in f_scores:
    x = np.linspace(0.01, 1)
    y = f_score * x / (2 * x - f_score)
    (l,) = plt.plot(x[y >= 0], y[y >= 0], color="gray", alpha=0.2)
    plt.annotate("f1={0:0.1f}".format(f_score), xy=(0.9, y[45] + 0.02))

display = PrecisionRecallDisplay(
    recall=recall["micro"],
    precision=precision["micro"],
    average_precision=average_precision["micro"],
)
display.plot(ax=ax, name="Micro-average precision-recall", color="gold")

for i, color in zip(range(n_classes), colors):
    display = PrecisionRecallDisplay(
        recall=recall[i],
        precision=precision[i],
        average_precision=average_precision[i],
    )
    display.plot(ax=ax, name=f"Precision-recall for class {i}", color=color)

handles, labels = display.ax_.get_legend_handles_labels()
handles.extend([l])
labels.extend(["iso-f1 curves"])
ax.set_xlim([0.0, 1.0])
ax.set_ylim([0.0, 1.05])
ax.legend(handles=handles, labels=labels, loc="best")
ax.set_title("Extension of Precision-Recall curve to multi-class")
plt.show()

まとめ

このチュートリアルでは、Precision-Recall メトリックを使用して分類器の出力品質を評価する方法について、手順を追って説明しました。sklearn.metrics ライブラリの PrecisionRecallDisplay クラスを使用して、2 値分類の Precision-Recall 曲線を描画する方法を学びました。また、OneVsRestClassifier を使用してマルチラベル分類の Precision-Recall 曲線を描画する方法と、各クラスの精度と再現率を計算する方法についても学びました。