Skip to main content

交差検証

交差検証とは,「機械学習モデルを構築する際に,モデルがデータに正確に当てはまって いるかを確認し,過度に適合(過学習)していないかどうかを確認すること」である.

メリット

汎化性能の担保:汎化性のある評価精度を得られる

利便性:データを分割して比較的簡単にモデルの精度を評価できる

デメリット

計算コスト:モデルの学習と検証を k 回繰り返してその性能の平均を取るため,計算 コストが増大する

交差検証が必要な理由#

交差検証が必要な理由は,モデルの汎化性能(未知データに対する予測性能)の評価を行 うために有用な手法であり,その汎化性能がモデルの構築に置いて重要だからだ.

汎化性能が高いことは,未知のデータに対するデータの当てはまりが良いことを示す.

学習データに特化されたモデル(過学習したモデル)は,実世界では使えないと言っても 過言ではない.

交差検証を行うことで,モデルが過学習しているかどうかを確認できる.過学習の発生有 無を確認することは,言い換えれば汎用性の高いモデル構築を行えているかどうかを確認 すること言えるだろう.

「Kaggle で勝つデータ分析の技術」には,バリデーションを行う目的として以下の2つ が挙げられている.

  • モデルを改善していく上での指針となるスコアを示す
  • テストデータに対するスコアやそのばらつきを見積もる

交差検証の手法#

ここでは,代表的な交差検証の手法をいくつか紹介する.

k-fold(k 分割)#

利用するデータセットを,学習用と検証用の k 個の異なるデータセットに分割する.

k = 5 の場合,以下のプロセスを 5 回繰り返し,性能評価の平均をとる.

  1. データセットを 5 分割して,学習用データセット(4 つ)・検証用データセット(1 つ)とする
  2. 学習用データセット(4 つ)を用いて,モデルの学習を行う
  3. 検証用データセット(1 つ)を用いて,モデルの性能を評価する
交差検証

k-fold交差検証の図(k=5).scikit-learnドキュメントより引用

以下のコードは ,ghmagazine/kagglebook からの引用である.

from sklearn.metrics import log_lossfrom sklearn.model_selection import KFold
# Modelクラスを定義しているものとする# Modelクラスは、fitで学習し、predictで予測値の確率を出力する
scores = []
# KFoldクラスを用いてクロスバリデーションの分割を行うkf = KFold(n_splits=4, shuffle=True, random_state=71)for tr_idx, va_idx in kf.split(train_x):    tr_x, va_x = train_x.iloc[tr_idx], train_x.iloc[va_idx]    tr_y, va_y = train_y.iloc[tr_idx], train_y.iloc[va_idx]
    # 学習の実行、バリデーションデータの予測値の出力、スコアの計算を行う    model = Model()    model.fit(tr_x, tr_y, va_x, va_y)    va_pred = model.predict(va_x)    score = log_loss(va_y, va_pred)    scores.append(score)
# 各foldのスコアの平均をとるprint(np.mean(scores))

stratified k-fold(層化 k 分割)#

stratified k-fold は,分布の比率を維持したまま,交差検証を行うための手法です.

90%の正のサンプルと 10%の負のサンプルのように偏ったデータセットを扱うことがある .このような分布に大きな不均衡のあるデータセットを用いて,予測を行う際,通常の k-fold 交差検証を利用すると負のサンプルが全くない(分割された)データセットなど が生まれてしまいかねない.

こうした偏りのある分布に対しては,分布の比率を保ちながら交差検証を行う ,stratified k-fold が有用である.

from sklearn.model_selection import StratifiedKFold
# StratifiedKFoldクラスを用いて層化抽出による分割を行うkf = StratifiedKFold(n_splits=4, shuffle=True, random_state=71)for tr_idx, va_idx in kf.split(train_x, train_y):    tr_x, va_x = train_x.iloc[tr_idx], train_x.iloc[va_idx]    tr_y, va_y = train_y.iloc[tr_idx], train_y.iloc[va_idx]

その他の手法#

ここでは時間の都合上割愛するが,以下も抑えておべき代表的な手法に含まれる.

  • hold-out
  • leave-one-hot
  • group k-fold

参考文献#