【機械学習】交差検定(クロスバリデーション)によるモデル評価について解説します




こんにちは。みなさん、機械学習していますか?していますよね!

機械学習を行う上で一番大切なことは、どのくらいの予測精度が出るかということです。作業だけを見ると、統計モデリングをしている人と機械学習をしている人は同じように回帰直線を引いているように見えるでしょう。

しかし、データを説明するために近似直線を引いているのか、未来を予測するために近似直線を引いているのか目的が異なっているのです。そのためモデルの評価方法も、統計モデリングと機械学習では若干異なります。そこで、この記事では「機械学習」の評価に有用な交差検定(クロスバリデーション)について解説していきたいと思います。

ここではPythonのライブラリscikit-learnを利用して解説していきます。

目次

交差検定(クロスバリデーション)とはなにか

交差検定とは標本データを訓練データとテストデータに分割し、訓練データでモデル作成した後に、テストデータを使ってモデルの評価をする方法です。ここからは具体的なコードで、手順の流れを解説していきます。

手順①:データの用意

まずはデータを用意します。今回はscikit-learnに付属しているボストンの住宅価格に関する有名なデータセットを利用します。このデータセットは、あらかじめ欠損値が落とされているのでデータクレンジングは省略します。

#①ライブラリのインポートとデータセット準備
import numpy as np
import pandas as pd
from pandas import Series,DataFrame
from sklearn.datasets import load_boston

boston = load_boston()

手順②:データセットを説明変数と目的変数に分ける

#②説明変数と目的変数に分離
X = DataFrame(boston.data, columns=boston.feature_names)
Y = DataFrame(boston.target, columns=['Price'])

次に、用意したデータを訓練用とテスト用に分割します。Xが説明変数、Yが目的変数です。

手順③:さらに訓練用とテスト用に分ける

#③交差検定用にデータを分割
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(X,Y)

scikit-learnには交差検定(クロスバリデーション)用の機能が既に用意されています。

train_test_splitに(説明変数, 目的変数)を渡すことで、返り値として(説明変数の訓練データ, 説明変数のテストデータ, 目的変数の訓練データ, 目的変数のテストデータ)が順に得られます。

train_test_splitのオプション
  • test_size:テストデータのサイズを0〜1で指定する。0.2の場合、訓練データが80%・テストデータが20%に分割される。
  • train_size:訓練データのサイズを0〜1で指定する。0.7の場合、訓練データが70%・テストデータが30%に分割される。
  • random_state: 何らかの整数かrandom_stateインスタンスを指定する。デフォルトはNone。擬似乱数のシードを設定する。指定しなかった場合はnp.randomが使われる。
  • shuffle:TrueかFalseを入れる。デフォルトはTrue。分割前にデータをシャッフルするかどうかを決める。
  • stratify : 層化サンプリングを行う場合に、クラスを示す行列を設定する。デフォルトはNone。

手順④:学習を行う

# ④学習を行う
from sklearn.linear_model import LinearRegression
lreg = LinearRegression()
lreg.fit(x_train, y_train)

次に、訓練用データx_trainとy_trainで学習を行いモデルを作成します。まず、sklearn.linear_modelからLinearRegressionをインポートして、lregという名前のオブジェクトを生成します。

このlregのfitメソッドに(説明変数, 目的変数)を渡すことによって機械学習モデルが作られます。

手順⑤:テストデータで評価する

#⑤テストデータで評価する
y_pred  = lreg.predict(x_test)
np.mean(np.abs((y_pred - y_test) / y_test))

最後に、モデルを評価します。lregのpredictメソッドに説明変数を渡すことで、目的変数の予測値y_predが得られます。真の値はy_testに格納されているので、y_predとy_testを見比べることでモデルの精度を確かめることが出来ます。

この場合は、(予測値 – 真の値) / 真の値という計算式で、残差が真の値に対してどのくらいの割合で存在するかを調べました。結果は 0.169435だったので、おおよそ17%でした。

③〜⑤を何度か繰り返すことで、おおよそどのくらいの精度が出るかを確認することが出来ます。

なぜ交差検定をするのか

では交差検定のメリットは何かと言うと、未知のデータに対する予測精度を判定しやすいというものがあります。よく初心者が陥りやすいのですが、手持ちのデータをすべて訓練データにしてしまうことがあります。

しかし、訓練に利用したデータをテストにも利用するのはカンニングしているのと同じです。自分自身をデータとして作られたモデルなのだから、良い予測値が出て当然です。訓練用データをテストにも使うことは、モデルの過大評価につながる危険性があるのです。

だからこそ、前もって訓練データとテストデータを分けておく必要があります。

また、訓練データとテストデータの分け方を毎回変えることで訓練データの偏りを少なくすることが出来ます。偏ったデータで学習しても偏ったモデルしかつくれないので、サンプル選びにおけるランダム性は重症です。

訓練データとテストデータの割合は

sklearnのtrain_test_splitのデフォルトで訓練データとテストのデータ比率は75:25に設定されています。どのくらいの比率が良いのかは一概には言えないので、個々の裁量に任されています。

テストデータ数が少ない(<100くらい?)ときは訓練データが少なすぎると精度が出にくいので85:15にしたり、あるいは精度評価をより厳しく行う必要があるときは60:40にしたりと場合によってさまざま使い分けています。

まとめ

交差検定は、訓練データとテストデータを分けることで未知のデータに対する予測精度を測定しようという方法でした。実は、一口に交差検定と言っても今回サンプルで示した交差検定だけではなく、K分割交差検定や、ホールドアウト交差検定などのバリエーションが存在します。(「交差検証」wikipediaより)

いずれも使いこなせると非常に有用なテクニックですので、別の記事で紹介していきたいと思います。

(参考)上のコード全文をまとめて

#①ライブラリのインポートとデータセット準備
import numpy as np
import pandas as pd
from pandas import Series,DataFrame
from sklearn.datasets import load_boston

boston = load_boston()

#②説明変数と目的変数に分離
X = DataFrame(boston.data, columns=boston.feature_names)
Y = DataFrame(boston.target, columns=['Price'])

#③交差検定用にデータを分割
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(X,Y)

# ④学習を行う
from sklearn.linear_model import LinearRegression
lreg = LinearRegression()
lreg.fit(x_train, y_train)

#⑤テストデータで評価する
y_pred  = lreg.predict(x_test)
np.mean(np.abs((y_pred - y_test) / y_test))