ML評価ツール比較

機械学習の不均衡データ評価:精度に惑わされないための指標と実践テクニック

Tags: 不均衡データ, モデル評価, scikit-learn, F1スコア, ROC曲線, PR曲線

はじめに:不均衡データセットの課題と評価の重要性

機械学習モデルを構築する際、私たちが扱うデータセットには、特定のクラスのデータが他のクラスに比べて極端に少ない「不均衡データセット」が存在することが少なくありません。例えば、クレジットカード詐欺検出では不正取引が極めて稀であり、病気の診断では特定の疾患を持つ患者の数が圧倒的に少ないといったケースが典型です。

このような不均衡データセットに対して、モデルの性能を評価する際に「精度(Accuracy)」だけを指標として用いると、大きな誤解を生む可能性があります。なぜなら、モデルが多数派クラスのデータをすべて正しく予測したとしても、少数派クラスの予測性能が極めて低ければ、見かけ上の精度は高くても実用的な価値は低いという事態に陥るためです。

この記事では、不均衡データセットにおける機械学習モデルの評価において、精度に惑わされずにモデルの真の性能を見抜くための主要な指標と、Pythonの代表的なライブラリであるscikit-learnを用いた実践的な活用方法について解説します。

精度(Accuracy)が不十分な理由

まずは、なぜ不均衡データセットにおいて精度が信頼できない評価指標なのかを具体例で見てみましょう。

ある二値分類問題で、データセットにクラスAが99%、クラスBが1%の割合で存在するとします。もしモデルがすべてのデータをクラスAと予測するだけであれば、99%の精度を達成できます。しかし、このモデルはクラスBのデータを全く検出できておらず、実用上は全く役に立ちません。特にクラスBが検出することが重要な「異常」や「希少なイベント」である場合、このモデルは致命的な欠陥を抱えていることになります。

このように、精度はデータセット全体の正答率を示すため、多数派クラスに偏った予測を行うモデルに対しても高い値を示しがちです。

不均衡データ評価に役立つ主要な指標

精度に代わり、不均衡データセットの評価で重要となる主な指標は以下の通りです。これらの指標は、モデルが少数派クラスをどれだけ正確に識別できているか、あるいは誤検出の傾向はどうかといった、より詳細な情報を教えてくれます。

1. 適合率(Precision)と再現率(Recall)

適合率と再現率は、分類モデルの性能を多角的に評価するための基本的な指標です。

ここで、TPは真陽性(True Positive)、FPは偽陽性(False Positive)、FNは偽陰性(False Negative)を表します。

プロジェクトの目的によって、適合率と再現率のどちらを重視すべきかは異なります。例えば、スパムメールの検出では誤って重要なメールをスパムと判断する(FP)ことを避けたいので適合率を重視します。一方、病気の診断では疾患の見逃し(FN)が命に関わるため、再現率を重視する傾向があります。

2. F1スコア

F1スコアは、適合率と再現率のバランスを示す指標です。適合率と再現率がトレードオフの関係にある場合、両方を考慮した評価が必要となります。

3. ROC曲線(Receiver Operating Characteristic Curve)とAUC(Area Under the Curve)

ROC曲線は、分類モデルが異なる分類閾値において、真陽性率(True Positive Rate, TPR = Recall)と偽陽性率(False Positive Rate, FPR = FP / (FP + TN))の間にどのようなトレードオフがあるかを示すグラフです。

4. PR曲線(Precision-Recall Curve)とAP(Average Precision)

PR曲線は、特に不均衡データセットにおいてROC曲線よりも情報量が多く、より適切な評価指標とされています。PR曲線は、異なる分類閾値における適合率と再現率のトレードオフを示します。

scikit-learnを用いた実践的な評価

Pythonのscikit-learnライブラリは、これらの評価指標を簡単に計算・可視化する機能を提供しています。

ここでは、仮想的な不均衡データセットで分類モデルを訓練し、上記の指標を計算する例を示します。

import numpy as np
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import (
    accuracy_score,
    precision_score,
    recall_score,
    f1_score,
    roc_curve,
    auc,
    precision_recall_curve,
    average_precision_score,
    classification_report
)
import matplotlib.pyplot as plt

# 1. 不均衡データセットの生成
# 多数派クラス: 0 (約95%), 少数派クラス: 1 (約5%)
X, y = make_classification(
    n_samples=1000,
    n_features=20,
    n_informative=2,
    n_redundant=10,
    n_repeated=0,
    n_classes=2,
    n_clusters_per_class=1,
    weights=[0.95, 0.05], # クラスの比率を指定
    flip_y=0,
    random_state=42
)

# 訓練データとテストデータに分割
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=42, stratify=y # stratifyでクラス比率を維持
)

print(f"訓練データ クラス0: {np.sum(y_train == 0)}, クラス1: {np.sum(y_train == 1)}")
print(f"テストデータ クラス0: {np.sum(y_test == 0)}, クラス1: {np.sum(y_test == 1)}")

# 2. モデルの訓練
model = LogisticRegression(solver='liblinear', random_state=42)
model.fit(X_train, y_train)

# 3. 予測
y_pred = model.predict(X_test)
y_prob = model.predict_proba(X_test)[:, 1] # 少数派クラス (1) の予測確率

# 4. 評価指標の計算と表示

print("\n### 主要な評価指標 ###")
print(f"Accuracy: {accuracy_score(y_test, y_pred):.4f}")
print(f"Precision (Class 1): {precision_score(y_test, y_pred, pos_label=1):.4f}")
print(f"Recall (Class 1): {recall_score(y_test, y_pred, pos_label=1):.4f}")
print(f"F1 Score (Class 1): {f1_score(y_test, y_pred, pos_label=1):.4f}")
print(f"ROC AUC Score: {auc(roc_curve(y_test, y_prob)[0], roc_curve(y_test, y_prob)[1]):.4f}")
print(f"Average Precision Score: {average_precision_score(y_test, y_prob):.4f}")

# classification_reportによる詳細なレポート
print("\n### classification_report ###")
print(classification_report(y_test, y_pred))

# 5. ROC曲線とPR曲線のプロット

plt.figure(figsize=(12, 5))

# ROC曲線
plt.subplot(1, 2, 1)
fpr, tpr, _ = roc_curve(y_test, y_prob)
roc_auc = auc(fpr, tpr)
plt.plot(fpr, tpr, color='darkorange', lw=2, label=f'ROC curve (area = {roc_auc:.2f})')
plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver Operating Characteristic (ROC) Curve')
plt.legend(loc="lower right")
plt.grid(True)

# PR曲線
plt.subplot(1, 2, 2)
precision, recall, _ = precision_recall_curve(y_test, y_prob)
ap_score = average_precision_score(y_test, y_prob)
plt.plot(recall, precision, color='blue', lw=2, label=f'PR curve (AP = {ap_score:.2f})')
plt.xlabel('Recall')
plt.ylabel('Precision')
plt.title('Precision-Recall Curve')
plt.legend(loc="lower left")
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.grid(True)

plt.tight_layout()
plt.show()

このコードを実行すると、精度(Accuracy)は比較的高い値を示す一方で、少数派クラス(Class 1)の適合率や再現率、F1スコアは低くなることが見て取れます。特にclassification_reportは、クラスごとの詳細な指標を一目で確認できるため非常に便利です。また、ROC曲線とPR曲線は、モデルの性能を視覚的に捉え、異なる閾値での挙動を理解するのに役立ちます。APスコアはPR曲線の下の面積であり、不均衡データセットにおいて特に少数クラスの予測性能を評価する上で重要な指標です。

どのようなケース/プロジェクトに適しているか、ツールの選び方のヒント

不均衡データセットにおいて、どの評価指標を重視すべきかはプロジェクトの目的とビジネス要件に大きく依存します。

これらの指標は、モデルの訓練段階でのハイパーパラメータチューニングや、異なるモデルの比較検討を行う際に不可欠です。scikit-learnはこれらの指標を簡単に利用できるため、積極的に活用することをお勧めします。

まとめ

不均衡データセットにおける機械学習モデルの評価は、精度(Accuracy)だけでなく、適合率、再現率、F1スコア、ROC曲線とAUC、PR曲線とAPスコアといった多角的な視点から行うことが極めて重要です。これらの指標を適切に理解し、scikit-learnなどのライブラリを使いこなすことで、モデルの真の性能を正確に把握し、より実用的なモデルを構築するための意思決定が可能になります。

常にプロジェクトの具体的な目標と、各クラスの誤分類がもたらすコストを考慮に入れながら、最適な評価指標を選択し、モデルの検証を進めていきましょう。