クロスバリデーションとは?
前回は予測モデルを構築しました。しかし、モデルを作るのに利用したデータと、精度を計測するデータが同じになってしまうため、「予測がどのくらい正確にできているか」がわからないのが問題でした。
本番における精度がどの程度であるか、手元にあるデータだけで確認する方法を考えないといけません。
そこで役立つのが、クロスバリデーションという方法です!
・クロスバリデーション 3セットに分割した例
まず、全部で10レコードのデータを3分割に分けるとします。
*何セットに分割するかはデータ量や予測モデルの学習に必要な時間によって異なりますが、3、5、10分割のいずれかであることが多いです。ここでは3セットに分割したとして説明をします。
それぞれのグループは3レコード、3レコード、4レコードとなります。これらのセットにグループ1、グループ2,グループ3と名前をつけます。
次に、これらのグループの組み合わせを変えながら、モデルの学習と精度の計測をします。
・学習に使うデータを、学習データ(または訓練データ)
・計測に使うデータを、検証データ
と呼びます。
グループの組み合わせとしては、次のようになります。
このように、グループの組み合わせを3通り作成します。つまり、学習と精度計測を3回行います。3回の精度計測の平均を、予測モデルが持つ予測の精度として扱います。
組み合わせを変えながら学習と検証を実施できるので、全てのデータに対して学習と検証をすることができ、無駄なくデータを使うことができます。
10セットのグループに分けた場合は、学習を10回することになるので、予測精度の計測に時間がかかってしまいますが、学習データに使えるデータ量が増えるという利点があります。
また、それぞれの予測精度のバラツキを確認するとモデルの安定性を知ることができます。極端に精度が異なる場合は、データの分割数を増やしたり、異なるモデルで予測したりする必要があるでしょう。
scikit-learnでクロスバリデーションを実装してみよう
scikit-learnでは以下のようにしてクロスバリデーションを実装できます。
特徴量Xと教師ラベルyを用意しました。この記事の実行を再現するために必要なサンプルコードは、こちらで確認できます。
```
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import GridSearchCV
model = LogisticRegression()
parameters = {} # デフォルトパラメータを利用
clf = GridSearchCV(model, parameters, cv=3, scoring="accuracy")
clf.fit(X, y)
```
結果の確認は`clf.cv_results_`で表示されて、以下のようになります。
```
{'mean_fit_time': array([0.01321475]),
'std_fit_time': array([0.00103848]),
'mean_score_time': array([0.0019633]),
'std_score_time': array([0.00012035]),
'params': [{}],
'split0_test_score': array([0.71849057]),
'split1_test_score': array([0.70415094]),
'split2_test_score': array([0.70015106]),
'mean_test_score': array([0.70759752]),
'std_test_score': array([0.00787374]),
'rank_test_score': array([1], dtype=int32)}
```
情報量が多いので最初は戸惑いますが、最初にみるべきはmean_test_scoreの値です。これが全組み合わせにおける予測精度の平均値になります。
ここでは0.707...となっています。十分な精度が出ている場合は、split0_test_score、 split1_test_score、split2_test_scoreの結果を見ます。
これらの数値が平均値を求める元になっています。ここでは大きなバラツキは無いようです。モデルやデータに問題がある場合はこれらの数値が大きくなります。
クロスバリデーションを実施する際に、予測モデルが持つパラメータを変えて比較することもできます。上記との違いはparametersのみです。
```
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import GridSearchCV
model = LogisticRegression()
parameters = {"penalty": ["l1", "l2"], "solver":["liblinear"]}
clf = GridSearchCV(model, parameters, cv=3, scoring="accuracy")
clf.fit(X, y)
```
クロスバリデーションの結果は、以下のようになります。
```
{'mean_fit_time': array([0.00588147, 0.00651034]),
'std_fit_time': array([0.00076274, 0.00138428]),
'mean_score_time': array([0.00222834, 0.00160066]),
'std_score_time': array([0.00013087, 0.00026224]),
'param_penalty': masked_array(data=['l1', 'l2'],
mask=[False, False],
fill_value='?',
dtype=object),
'param_solver': masked_array(data=['liblinear', 'liblinear'],
mask=[False, False],
fill_value='?',
dtype=object),
'params': [{'penalty': 'l1', 'solver': 'liblinear'},
{'penalty': 'l2', 'solver': 'liblinear'}],
'split0_test_score': array([0.73509434, 0.71698113]),
'split1_test_score': array([0.70339623, 0.70415094]),
'split2_test_score': array([0.72432024, 0.70015106]),
'mean_test_score': array([0.72093694, 0.70709438]),
'std_test_score': array([0.01315998, 0.00717917]),
'rank_test_score': array([1, 2], dtype=int32)}
```
先程との結果の違いはmean_test_scoreなどの値が2つになっていることです。パラメータの組み合わせごとにクロスバリデーションの結果が保存されています。また、最も精度の高いパラメータでのモデルはclf.predictで呼び出せます。
クロスバリデーションは、複数のモデルを作ったうち、どれが最も優れているかを比較するときにも役立ちますよ
第1話 機械学習の仕事内容って?実はコードを書くだけじゃない!
第2話 人工知能、機械学習、ディープラーニングの違いとは?
第3話 機械学習の活用事例!建設機械や回転寿司屋でも活用されている!?
第4話 機械学習したいのにデータがない!?
第5話 集計と可視化:pandasでデータの加工をしてみよう
第6話 続!集計と可視化:Plotlyでデータをグラフ化して傾向をとらえよう
第7話 ロジスティック回帰ってなあに?紹介編
第8話 ロジスティック回帰で、翌月の購買実績を予測してみよう!実践編
わかばちゃんが登場する書籍いろいろ