前回は、実際の機械学習モデルの構築を行いました。
今回は機械学習を行う上で生じる問題「過学習」についての説明と、それに対する対応策をまとめていきます。
例によって初心者のメモレベルなので、何か誤りなどがあれば指摘していただけると幸いです。
過学習とは
過剰適合(かじょうてきごう、英: Overfitting)とは、統計学や機械学習において、訓練データに対して学習されているが、未知データ(テストデータ)に対しては適合できていない、汎化できていない状態を指す。汎化能力の不足に起因する。
その原因の一つとして、統計モデルへの適合の媒介変数が多すぎる等、訓練データの個数に比べて、モデルが複雑で自由度が高すぎることがある。不合理で誤ったモデルは、入手可能なデータに比較して複雑すぎる場合、完全に適合することがある。(Wikipedia)
前回、教師あり学習のモデルを作成し予測値を算出したときには、以下のような手順を踏みました。
- 1. 線形回帰モデルを生成する
model = LinearRegression()
- 2. モデルに学習データと正解データを渡して訓練させる
model.fit(practice_x, correct_y)
- 3. モデルに未知データを渡して、予測値を求める
result = model.predict(raw_z)
ここで訓練作業を行うとき、手持ちの標本データ(practice_x)を全て渡しています。
これにより、手持ちのデータに対しては高い精度で予測を行うことができるモデルが作成されますが、未知のデータに対して高い精度を保つことができるかはわかりません。
あるいは完全な予測を行うことができるかもしれないし、あるいはできないかもしれません。
このように、訓練データに対しては学習されているが未知データへの適合を考慮していない場合に起こってしまうのが、「過学習」というものです。
「訓練データについて学びすぎた」というくらいの意味でしょうか。
それを回避するための方法の一つが、「交差検証」と呼ばれるものです。
過学習を回避するための「交差検証」とは
交差検証(交差確認)(こうさけんしょう、英: Cross-validation)とは、統計学において標本データを分割し、その一部をまず解析して、残る部分でその解析のテストを行い、解析自身の妥当性の検証・確認に当てる手法を指す。データの解析(および導出された推定・統計的予測)がどれだけ本当に母集団に対処できるかを良い近似で検証・確認するための手法である。
最初に解析するデータを「訓練事例集合(training set)」などと呼び、他のデータを「テスト事例集合(testing set、テストデータ)」などと呼ぶ。(Wikipedia)
過学習とは、標本データの全てを訓練に用いてしまうがために生じてしまう問題でした。
そこで、はじめに手元の標本データを訓練用データのとテスト用データに分割し、前者を使用してモデルを訓練させた上で、テスト用データを用いてテストを行うことで過学習を回避しようとするのが、「交差検証」です。
標本の分割の仕方により、交差検証もいくつかの種類に派生します。
・ホールドアウト検証
・K- 分割交差検証
・leave-one-out検証
この中ではもっとも簡単なホールドアウト検証について、次の項で実践してみます。
交差検証の実践 //ホールドアウト検証
ここではホールドアウト検証によるデータ分割を試行します。
ホールドアウト検証では、標本データから無作為に抽出したデータを学習用とし、残りをテスト用データとする方法です。2つのデータ数の比率は、だいたい7:3くらいが主流のようです。
では、実践していきます。
import pandas as pd
from sklearn.datasets import load_boston
from sklearn.linear_model import LinearRegression
dataset = load_boston()
#標本データ全体
data_x = pd.DataFrame(dataset.data, columns=dataset.feature_names)
#正解データ全体
data_y = pd.DataFrame(dataset.target, columns=['y'])
#データ数の確認
print('標本データ数と列数 : %i,%i' %data_x.shape)
print('正解データ数と列数 : %i,%i' %data_y.shape)
#出力結果:
#標本データ数と列数 : 506,13
#正解データ数と列数 : 506,1
今回扱うデータセットは、506個のデータを持っています。
これを分割していきます。
from sklearn.model_selection import train_test_split
#訓練データとテストデータに分割
train_x, test_x, train_y, test_y = train_test_split(data_x, data_y)
#訓練データとテストデータの数を確認
print('標本データ(訓練用)の数と列数 : %i,%i' %train_x.shape)
print('標本データ(テスト用)数と列数 : %i,%i' %test_x.shape)
print('正解データ(訓練用)の数と列数 : %i,%i' %train_y.shape)
print('正解データ(テスト用)数と列数 : %i,%i' %test_y.shape)
#出力結果
#標本データ(訓練用)の数と列数 : 379,13
#標本データ(テスト用)数と列数 : 127,13
#正解データ(訓練用)の数と列数 : 379,1
#正解データ(テスト用)数と列数 : 127,1
sklearnライブラリのtrain_test_split
というメソッドを用いて
データを分割してます。このメソッドはデフォルトで、与えられた
引数を 0.75 : 0.25 の比率で二つのデータに分割してくれます。
ので、今回は 506 のデータが 379 : 127 (= 0.75 : 0.25) で分割されました。
このデータを用いて、モデルを生成し、テストデータを渡す図が以下です。
model_validation = LinearRegression()
model_validation.fit(train_x, train_y)
# 訓練データで訓練したモデルに対して、未知データを処理させた時の決定係数
print('ホールドアウト法を用いたときの決定係数 : %.3f' %model_validation.score(test_x, test_y))
#出力結果
#ホールドアウト法を用いたときの決定係数 : 0.710
これが、ホールドアウト法によるモデル生成です。
今回は直線回帰モデルを使用しているので、非交差検証時との違いは分かりにくいですが、あくまで方法のまとめということで書かせてもらいました。
交差検証による可視的なメリットなどについては、モデルの比較を行うときに確認したいと思います。
以上。