メインコンテンツへスキップ

5.4.2 評価指標

混同行列と誤りコスト図

この節の概要

指標は、レポートを飾る点数ではありません。どのモデルを信じるか、どのしきい値を出すか、プロダクトがどのミスを負担するかを決めます。

作るもの

この節では、評価実験を 1 つ完成させます。

  • 不均衡分類で accuracy の罠を見る;
  • しきい値を調整し、偽陽性/偽陰性を読む;
  • ROC AUC と average precision を比較する;
  • MAE、RMSE、R2 で回帰を評価する;
  • 習慣ではなく、プロダクト上のコストから指標を選ぶ。

まず図を見てください。

評価指標選択フローチャート

用語早見表

用語実用上の意味
TPtrue positive。本当に正で、正と予測した
FPfalse positive。本当は負だが、正と予測した
FNfalse negative。本当は正だが、見逃した
precision正と予測した中で、本当に正だった割合
recall本当の正の中で、見つけられた割合
F1precision と recall の調和平均
ROC AUC多くのしきい値にまたがるランキング品質。正例が少ないと楽観的に見えることがある
average_precisionprecision-recall 曲線の面積。正例が少ないとき参考になりやすい
MAE回帰の平均絶対誤差
RMSE平均二乗誤差の平方根。大きなミスを強く罰する

セットアップ

python -m pip install -U scikit-learn

完全な実験を実行する

metrics_lab.py を作成します。

from sklearn.datasets import load_diabetes, make_classification
from sklearn.dummy import DummyClassifier, DummyRegressor
from sklearn.linear_model import LinearRegression, LogisticRegression
from sklearn.metrics import (
accuracy_score,
average_precision_score,
confusion_matrix,
f1_score,
mean_absolute_error,
mean_squared_error,
precision_score,
r2_score,
recall_score,
roc_auc_score,
)
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler


X, y = make_classification(
n_samples=1200,
n_features=12,
n_informative=5,
n_redundant=2,
weights=[0.92, 0.08],
class_sep=1.2,
random_state=42,
)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.25, random_state=42, stratify=y
)

baseline = DummyClassifier(strategy="most_frequent")
baseline.fit(X_train, y_train)
base_pred = baseline.predict(X_test)
print("classification_baseline")
print(f"accuracy={accuracy_score(y_test, base_pred):.3f}")
print(f"precision={precision_score(y_test, base_pred, zero_division=0):.3f}")
print(f"recall={recall_score(y_test, base_pred):.3f}")

model = Pipeline([
("scale", StandardScaler()),
("clf", LogisticRegression(max_iter=2000, random_state=42)),
])
model.fit(X_train, y_train)
prob = model.predict_proba(X_test)[:, 1]

print("threshold_lab")
for threshold in [0.2, 0.5, 0.8]:
pred = (prob >= threshold).astype(int)
tn, fp, fn, tp = confusion_matrix(y_test, pred).ravel()
print(
f"threshold={threshold:.1f} "
f"accuracy={accuracy_score(y_test, pred):.3f} "
f"precision={precision_score(y_test, pred, zero_division=0):.3f} "
f"recall={recall_score(y_test, pred):.3f} "
f"f1={f1_score(y_test, pred):.3f} "
f"fp={fp} fn={fn}"
)
print(f"roc_auc={roc_auc_score(y_test, prob):.3f}")
print(f"average_precision={average_precision_score(y_test, prob):.3f}")

print("regression_lab")
X, y = load_diabetes(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.25, random_state=42
)
for name, reg in [
("mean_baseline", DummyRegressor(strategy="mean")),
("linear", LinearRegression()),
]:
reg.fit(X_train, y_train)
pred = reg.predict(X_test)
rmse = mean_squared_error(y_test, pred) ** 0.5
print(
f"{name:<13} "
f"mae={mean_absolute_error(y_test, pred):.1f} "
f"rmse={rmse:.1f} "
f"r2={r2_score(y_test, pred):.3f}"
)

実行します。

python metrics_lab.py

期待される出力:

classification_baseline
accuracy=0.917
precision=0.000
recall=0.000
threshold_lab
threshold=0.2 accuracy=0.907 precision=0.462 recall=0.720 f1=0.562 fp=21 fn=7
threshold=0.5 accuracy=0.943 precision=0.833 recall=0.400 f1=0.541 fp=2 fn=15
threshold=0.8 accuracy=0.923 precision=1.000 recall=0.080 f1=0.148 fp=0 fn=23
roc_auc=0.889
average_precision=0.660
regression_lab
mean_baseline mae=65.5 rmse=74.9 r2=-0.014
linear mae=41.5 rmse=53.4 r2=0.485

評価指標しきい値と回帰結果図

Accuracy の罠

baseline は毎回多数派クラスを予測します。

accuracy=0.917
precision=0.000
recall=0.000

accuracy は高く見えますが、正例を 1 件も見つけていません。不均衡分類では、accuracy だけを見るとかなり危険です。

まず混同行列を見る

分類指標はすべて 4 つの数から作られます。

意味
TP正例を正しく見つけた
FP正常なサンプルを誤ってアラートした
FN正例を見逃した
TN正常なサンプルを正しく無視した

指標を選ぶ前に確認します。

  • FPFN のどちらが高いか?
  • モデルはスクリーニング、ランキング、ブロック、最終判断のどれに使うのか?
  • 人がレビューできる件数はどれくらいか?

しきい値で話が変わる

しきい値、ROC と PR 曲線の読み方ガイド

同じモデルでも、しきい値が違うと振る舞いが変わります。

threshold=0.2 precision=0.462 recall=0.720 fp=21 fn=7
threshold=0.8 precision=1.000 recall=0.080 fp=0 fn=23

しきい値を下げると、より多くの正例を拾いますが、誤アラートも増えます。しきい値を上げると、誤アラートは減りますが、見逃しが増えます。

次のように選びます。

プロダクト目標主な指標
正例をできるだけ拾うrecall
アラートの信頼性を保つprecision
precision と recall のバランスF1
しきい値をまたいで候補をランキングROC AUC
正例が少ないaverage precision / PR curve

ROC AUC と Average Precision

roc_auc=0.889 は、複数のしきい値をまたいで、正例を負例より上に並べる力があることを示します。

average_precision=0.660 は、precision-recall の振る舞いに注目するため、希少な正例に対してより厳しい指標です。詐欺、医療スクリーニング、セキュリティアラート、解約防止では、ROC AUC だけでなく precision-recall 指標を必ず見ます。

回帰指標

回帰指標と残差診断の図

回帰実験では、平均ベースラインと線形モデルを比べます。

mean_baseline mae=65.5 rmse=74.9 r2=-0.014
linear mae=41.5 rmse=53.4 r2=0.485

読み方は次の通りです。

指標使う場面
MAE元の単位で平均誤差を理解したい
RMSE大きな誤差が特に痛い
R2平均ベースラインよりどれだけ良いかを知りたい

R2 だけに頼らないでください。R2 がそこそこ良くても、重要なケースで許容できない誤差を出すことがあります。

実用的な指標選択

タスク最初に見るその後に確認
バランスした分類accuracy、F1混同行列
不均衡分類precision、recall、F1PR 曲線、しきい値表
スクリーニング / 検知recallアラート量と偽陽性
最終承認 / ブロックprecision見逃しと人手レビュー方針
ランキングROC AUC、average precisiontop-k precision
回帰MAE、RMSE残差図とセグメント別誤差

経験者向け:セグメント別に評価してください。全体指標は、地域、顧客群、言語、デバイス種別、希少クラスでの失敗を隠すことがあります。

よくあるトラブル

症状よくある原因修正
accuracy は高いが recall がゼロクラス不均衡混同行列と recall を見る
ROC AUC は良いがアラートが悪いしきい値不適切、または正例が少ないPR 曲線とアラート量を見る
F1 は上がったがプロダクトは悪化指標が業務コストに合っていないFP/FN コストを明確に定義する
回帰の平均誤差は良い特定セグメントの大誤差が隠れているセグメント別に残差を見る
本番でオフライン指標が下がる分布シフトデータと指標のドリフトを監視する

練習

  1. クラス比を [0.98, 0.02] に変えてください。accuracy と recall はどう変わりますか?
  2. しきい値 [0.1, 0.3, 0.7, 0.9] を追加してください。スクリーニング用途ならどれを出しますか?
  3. 各しきい値で tpfpfntn を表示してください。
  4. 木モデルを追加し、ROC AUC と average precision を比較してください。
  5. 回帰で絶対誤差が最大の 5 件を表示し、入力を確認してください。

合格チェック

次を説明できれば、この節はクリアです。

  • 不均衡データでは accuracy が誤解を招くことがある;
  • precision と recall は異なる誤りコストを表す;
  • しきい値選択はプロダクト設計の一部;
  • ROC AUC と PR 指標は別の問いに答える;
  • 回帰指標は残差とセグメント確認と合わせて読む。