中野智文のブログ

データ・マエショリストのメモ

scikit learn の Kfold, StratifiedKFold, ShuffleSplit の違い

背景

scikit learn の cross validation にて、テスト事例の分割方法に Kfold, StratifiedKFold, ShuffleSplit, StratifiedShuffleSplit というのがある(他にもある)。 その違いがわかりにくい。

Kfold と StratifiedKFold の違い

Kfold は知っているという前提で、StratifiedKFold は、その説明にある通り、

The folds are made by preserving the percentage of samples for each class.

その分割は、サンプルのそれぞれのクラスの割合を保ったまま作られる(超意訳)。

ということらしい。100個のデータがあって、クラス1とクラス0に、それぞれ5個と95個属するとき、それぞれのクラスの割合は、5%と95%である。 よって、その5%と10%を保ったまま分割されるということだ。

でもこのデータを10-Fold にする場合はどうなるのだろうか? 10個づつになるわけだから、0.5個 と 9.5個 に分割しないとクラスの割を保ったままに出来ないはずだが、そのような分割はできない。 だから、そもそもこのようなマイナーなクラスが小さなデータの場合、理想的にクラスの割合が等しく分割することは出来ない。 マイナーなクラスのための機能のような気がするのに、だ。 結果として、

The least populated class in y has only 5 members, which is too few. The minimum number of labels for any class cannot be less than n_folds=10.

といったようなメッセージを見るかもしれない。 これはコード内のコメントを読むと、例外を出す代わりに trim すると言っている。 コードを読み切れていないが、すでに k-fold とはよべないような状況が起きている気がする。 (例えばマイナーなクラスの事例が別の分割(fold)にも重複して使われたり…)

KFold と ShuffleSplit の違い

こちらも、 KFold は知っているという前提で話をすすめる。 KFoldのとの大きな違いは ShuffleSplit は繰り返し再サンプリングする。 よって、k 回行うと重複して同じ事例がでてくるかもしれない。 この ShuffleSplit は事例の数を減らして(ダウンサンプリングして)学習させる際に、別のダウンサンプリングでも結果がそれほど変わらないかを検証する際に使うらしい。

だから、KFold の オプション shuffle=True と同じ結果になるわけではないことに注意。

ちなみに shuffle オプションはデフォルトで、False なので、 shuffle=True をつけないと、事例をランダムにソートしてくれない。

まとめ

  • クラスの割合を保ったまま分割したときは、StratifiedKFold を使う。
  • ただし、マイナーなクラスの事例数が少ない(特に分割数より少ない)と警告が出て、その場合は想定外の結果となるだろう。
  • ShuffleSplit は KFold の shuffle=True ではなく、特にデータが大きい場合のダウンサンプリングのばらつきなどを検証するために使う(複数の分割において重複するかもしれない)

なお、GridSearchCVの説明 によると、推定器か教師データが二値か多クラスの場合、デフォルトで、StratifiedKFold になるそうである。 もちろん、shuffle は Falseになっている。 scikit learn は初心者向けのようで実は…

参考

stackoverflow.com

https://www.kaggle.com/ogrellier/kfold-or-stratifiedkfold