交差検証(cross-validation)
Overview
交差検証は汎化性能を評価する統計的手法で、ただ訓練セットとテストセットを分割する方法と比べて、より安定で徹底した手法です。交差検証では、データの分割を何度も繰り返して行い、複数のモデルを訓練します。
最もよく用いられる交差検証手法はk分割交差検証(k-fold cross-validation)です。kはユーザが定める数で、多くの場合は5から10程度です。5分割の交差検証を行う場合、まずデータを5つの(おおよそ)同じサイズに分割します。次に一連のモデルを訓練します。最初のモデルは最初の分割をテストセットとして使い、残りの分割(2-5)を訓練セットに使います。次のモデルは、分割2をテストセットとし、分割1, 3, 4, 5を訓練セットとして使います。これを繰り返すと最終的に5つの精度が手に入ります。
https://gyazo.com/cbe6a248589d256c6e0573ab47ab14f9
Coding
Irisデータセットでロジスティック回帰モデルを構築・学習し交差検証で評価する
code: Python
from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
iris = load_iris()
logreg = LogisticRegression()
# cross_val_scoreは、デフォルトで3分割交差検証を行い、3つの精度を返す
scores = cross_val_score(logreg, iris.data, iris.target)
print('Cross-validation scores: {}'.format(scores))
--------------------------------------------------------------------------
--------------------------------------------------------------------------
cross_val_scoreは、デフォルトで3分割交差検証を行い、3つの精度を返します。パラメータcvで分割数を変更することができます。
code: Python
scores = cross_val_score(logreg, iris.data, iris.target, cv=5)
print('Cross-validation scores: {}'.format(scores))
--------------------------------------------------------------------------
--------------------------------------------------------------------------
交差検証の精度をまとめるには、一般に平均値を用います。
code: Python
print('Average cross-validation score: {:.2f}'.format(scores.mean()))
--------------------------------------------------------------------------
Average cross-validation score: 0.96
--------------------------------------------------------------------------
このようにこのモデルは平均でおよそ96%の割合で正しいだろうと結論を出すことができます。5分割交差検証の結果の5つの精度を見ると、90%から100%と、分割間で精度のバラつきが比較的大きいことがわかります。このことは、このモデルは訓練に用いられた特定の分割に強く依存していることを示唆しますが、データセットのサイズがただ小さすぎるだけかもしれません。
train_test_splitがランダムにデータを分割するのに対し、cross_val_scoreはすべてのデータが正確に1度だけテストに用いられるので、モデルが高い汎化性能を持っていないと良い精度がでません。
Advanced
層化k分割交差検証
データセットをk個に分割する際に、データセットの先頭から1/kを取る方法は、いつもうまくいくとは限りません。データが先頭から順に「0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2」のように整列している場合があるためです。単純なk分割交差検証ではうまくいかないので、クラス分類器に関しては、層化k分割交差検証(stratified k-fold cross-validation)を用います。層化k分割交差検証では、各分割内でのクラスの比率が全体の比率と同じになるように分割します。
https://gyazo.com/f38bf09895d4597f04dbdc02b755e2d1
交差検証のより詳細な制御
scikit-learnでは、cvパラメータに交差検証分割器(cross-validation splitter)を与えることで、データの分割方法をより詳細に制御することができます。これを行うには、KFold分割器クラスを使います。
code: Python
from sklearn.model_selection import KFold
kfold = KFold(n_splits=3, shuffle=True, random_state=0)
print('Cross-validation scores:\n{}'.format(cross_val_score(logreg, iris.data, iris.target, cv=kfold)))
--------------------------------------------------------------------------
Cross-validation scores:
--------------------------------------------------------------------------
1つ抜き交差検証(leave-one-out)
別のよく用いられる交差検証手法として1つ抜き交差検証があります。1つ抜き交差検証は、毎回データセット中の1サンプルだけをテストセットとして検証します。大規模データセットに対しては非常に時間がかかりますが、小規模データセットには良い推定が可能になります。
code: Python
from sklearn.model_selection import LeaveOneOut
loo = LeaveOneOut()
scores = cross_val_score(logreg, iris.data, iris.target, cv=loo)
print('Number of cv iterations:', len(scores))
print('Mean accuracy: {:.2f}'.format(scores.mean()))
--------------------------------------------------------------------------
Number of cv iterations: 150
Mean accuracy: 0.95
--------------------------------------------------------------------------
シャッフル交差検証(shuffle-split cross-validation)
シャッフル交差検証という非常に柔軟な交差検証手法もあります。この手法では、毎回train_size個の点を選び出して訓練セットとし、test_size個の(訓練セットとは重複しない)点を選び出してテストセットとします。これをn_iter回繰り返します。
https://gyazo.com/d425009dd6dc85e34d09af3c04224e71
次のコードは、データセットの50%を訓練セットに、50%をテストセットにして10回分割を繰り返す例です。
code: Python
from sklearn.model_selection import ShuffleSplit
shuffle_split = ShuffleSplit(test_size=.5, train_size=.5, n_splits=10)
scores = cross_val_score(logreg, iris.data, iris.target, cv=shuffle_split)
print('Cross-validation scores:\n{}'.format(scores))
--------------------------------------------------------------------------
Cross-validation scores:
[0.93333333 0.97333333 0.88 0.93333333 0.98666667 0.94666667
0.94666667 0.89333333 0.97333333 0.96 ]
--------------------------------------------------------------------------
グループ付き交差検証
グループ付き交差検証は、データセットの中に、密接に関係するグループがある場合に用いられる交差検証です。
code: Python
from sklearn.model_selection import GroupKFold
X, y = make_blobs(n_samples=12, random_state=0)
# 最初の3サンプルが同じグループに、次の4つが同じグループに、というようにする
groups = 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 3 scores = cross_val_score(logreg, X, y, groups, cv=GroupKFold(n_splits=3))
print("Cross-validation scores:\n{}".format(scores))
--------------------------------------------------------------------------
Cross-validation scores:
--------------------------------------------------------------------------
Summary
多くの場合には、標準のKFold、StratifiedKFold、GroupKFoldを用いるのがよいです。