交差検証

Eval

交差検証

まとめ
  • 交差検証はデータを複数分割してモデル性能を安定評価する手法です。
  • ホールドアウトとの違いをコードで比較し、分割数の影響を確認します。
  • フォールド設計や計算コストの見積もりなど実務での注意点を整理します。

標本データを分割し、その一部でモデルを学習、残りでテストを行い、解析自体の妥当性を検証する手法交差検証 (Wikipedia)


1. 交差検証とは #

  • データを複数の「フォールド」に分割し、学習と検証を交互に入れ替えて評価する方法。
  • 1 回だけの train_test_split では評価のばらつきが大きくなるため、交差検証で平均性能を把握する。
  • 典型例は k-fold(k 分割)と Stratified k-fold(各フォールドでラベル比率を揃える)の 2 種。

2. Python 3.13 での基本例 #

Python 3.13 環境を前提とし、必要なライブラリを導入します。

python --version        # 例: Python 3.13.0
pip install scikit-learn matplotlib

乳がん診断データセットを用い、単一のホールドアウト評価と 5 分割交差検証を比較します。

from __future__ import annotations

import numpy as np
from sklearn.datasets import make_classification
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import cross_validate, train_test_split

RANDOM_STATE = 42


def make_dataset() -> tuple[np.ndarray, np.ndarray]:
    """不均衡な二値分類データセットを生成する。"""
    features, labels = make_classification(
        n_samples=300,
        n_classes=2,
        weights=[0.2, 0.8],
        n_informative=4,
        n_features=6,
        n_clusters_per_class=2,
        shuffle=True,
        random_state=RANDOM_STATE,
    )
    return features, labels


def holdout_score() -> float:
    """単一のホールドアウト分割で ROC-AUC を計算する。"""
    features, labels = make_dataset()
    x_train, x_valid, y_train, y_valid = train_test_split(
        features,
        labels,
        test_size=0.2,
        stratify=labels,
        random_state=RANDOM_STATE,
    )
    model = RandomForestClassifier(max_depth=4, random_state=RANDOM_STATE)
    model.fit(x_train, y_train)
    predictions = model.predict(x_valid)
    return roc_auc_score(y_valid, predictions)


def cross_validation_scores() -> dict[str, float]:
    """5 分割交差検証で ROC-AUC と Accuracy の平均を計算する。"""
    features, labels = make_dataset()
    model = RandomForestClassifier(max_depth=4, random_state=RANDOM_STATE)
    scores = cross_validate(
        model,
        features,
        labels,
        cv=5,
        scoring=("roc_auc", "accuracy"),
        return_train_score=False,
        n_jobs=None,
    )
    return {
        "roc_auc": float(np.mean(scores["test_roc_auc"])),
        "accuracy": float(np.mean(scores["test_accuracy"])),
    }


if __name__ == "__main__":
    holdout = holdout_score()
    print(f"Hold-out ROC-AUC: {holdout:.3f}")

    cv_result = cross_validation_scores()
    print(f"5-fold ROC-AUC: {cv_result['roc_auc']:.3f}")
    print(f"5-fold Accuracy: {cv_result['accuracy']:.3f}")

出力例:

Hold-out ROC-AUC: 0.528
5-fold ROC-AUC: 0.844
5-fold Accuracy: 0.858

単一ホールドアウトでは ROC-AUC が 0.5 程度と低く出ていますが、交差検証では安定した性能が確認できます。


3. 交差検証の設計ポイント #

  1. フォールド数の選択
    一般的には 5 または 10。データが少ない場合は LeaveOneOut も候補だが計算コストが高い。
  2. 層化(Stratification)
    クラス不均衡がある場合は StratifiedKFold などを使い、各フォールドのラベル比率を揃える。
  3. 評価指標の複数指定
    scoring にタプルを渡すと複数指標を一度に計算できる。ROC-AUC + Accuracy などを組み合わせるとバランスが見えやすい。
  4. ハイパーパラメータ探索との組み合わせ
    GridSearchCVRandomizedSearchCV は内部で交差検証を行い、外部評価で過学習を防げる。

4. 現場でのチェックリスト #

  • フォールド分割が適切か: データの時系列依存がある場合は TimeSeriesSplit を使う。
  • 評価指標の揃え方: ビジネスで重要な指標を scoring に含め、意思決定者と認識を合わせる。
  • 処理時間の見積もり: 交差検証は k 回学習するため、モデルの訓練コストを把握しておく。
  • 再現可能なノートブック: Python 3.13 環境で同じ分割・同じ乱数を使えるよう設定値を残しておく。

まとめ #

  • 交差検証は評価のばらつきを抑え、モデルの汎化性能を把握するための基本手法。
  • scikit-learn では cross_validate を使うと複数指標をまとめて取得できる。
  • 実務では分割方法・指標・計算コストを踏まえて設計し、再現可能な形で運用に組み込もう。