ソムリAI(ワインの評価を機械学習で当てる「ソムリエ+AI」)の改良として前回は正規化を試しました(大した効果なし)。今回は「アンサンブル学習」と「交差検証」というものを試してみようと思います。
訓練データでの精度に比べて検証データでの精度が高い場合は訓練データに個別最適化された過学習なモデルということになります。一方で、訓練データと検証データでの精度があまり変わらない場合は汎化性能の高いよいモデルということになります。
交差検証(Cross Validation)は、訓練データをさらにn個に分けて訓練することで過学習を防ぎつつモデルの精度を上げる手法です。例えば、3個に分ける場合こんなイメージです。複数のモデルを使ってよりよいものを作るので、アンサンブル学習の1手法ともいえます。
ランダムフォレストは決定木を複数作って統合して、よりよい決定木を見つける手法です。木を集めるからフォレストっていう名前もおしゃれですね。
早速やってみます。機械学習の汎用ライブラリであるscikit-learnにはランダムフォレストなど機械学習で使うモデルがあらかじめ用意されているのでとっても簡単にできます。決定木の数は多ければ多いほどよいので、とりあえず100本にしてみます(n_estimators=100)。また、決定木では正規化の効果は無いので正規化せずに実行しています。
まずは、訓練データでのモデル作成から。
MajorityVoteClassifierの中身を知りたい方はこちらをどうぞ。
気を取り直して検証データで精度を測定します。
足を引っ張っていそうな決定木をはずして多数決してみます。
検証データで精度を測定します。
とりあえずソムリAIはこれでおしまいにしようと思います。面白そうなネタを見つけたらまた投稿しようと思います!
アンサンブル学習とは
ざっくりいうと、複数の機械学習モデルのいいとこどりをしてより精度の高いモデルを作るということです。「アンサンブル」っていう表現がおしゃれですよね。複数のモデルを組み合わせることで過学習を防ぐ効果もあるそうです。交差検証とは
今までのソムリAIでは、データを訓練用と検証用に分けて訓練データでモデルを作成し、検証データ(モデルにとっては未知のデータ)でモデルの精度を測定していました。訓練データでの精度に比べて検証データでの精度が高い場合は訓練データに個別最適化された過学習なモデルということになります。一方で、訓練データと検証データでの精度があまり変わらない場合は汎化性能の高いよいモデルということになります。
交差検証(Cross Validation)は、訓練データをさらにn個に分けて訓練することで過学習を防ぎつつモデルの精度を上げる手法です。例えば、3個に分ける場合こんなイメージです。複数のモデルを使ってよりよいものを作るので、アンサンブル学習の1手法ともいえます。
実際にやってみる
毎度おなじみですが、まずワインデータを読み込んで、訓練データ・検証データに分割します(データの正規化は後でやります)。#入力データセットを読み込み import pandas as pd #データハンドリング用ライブラリ呼び出し data = pd.read_csv('winequality-red.csv', encoding='SHIFT-JIS') #機械学習で求める解である「評価」以外の項目をdata_Xに、「評価」をdata_Yに格納 data_X = data.copy() del data_X['評価'] data_Y = data['評価'] data.head() #読み込んだデータの先頭5行を出力
#入力データセットの70%を訓練データ・30%を検証データに分割 from sklearn.model_selection import train_test_split #機械学習用ライブラリ呼び出し X_train, X_test, Y_train, Y_test = train_test_split(data_X, data_Y,random_state=0, test_size=0.3)
ランダムフォレスト
1つ目のアンサンブル学習として決定木の応用版であるランダムフォレストというものを使ってみようと思います。決定木では学習用データを分類するために、データの各項目の優先度を探索し、優先度の高い項目から順に分類しました(樹形図のようなものです)。ランダムフォレストは決定木を複数作って統合して、よりよい決定木を見つける手法です。木を集めるからフォレストっていう名前もおしゃれですね。
早速やってみます。機械学習の汎用ライブラリであるscikit-learnにはランダムフォレストなど機械学習で使うモデルがあらかじめ用意されているのでとっても簡単にできます。決定木の数は多ければ多いほどよいので、とりあえず100本にしてみます(n_estimators=100)。また、決定木では正規化の効果は無いので正規化せずに実行しています。
from sklearn.ensemble import RandomForestClassifier #ランダムフォレストで機械学習 forest = RandomForestClassifier(n_estimators=100, min_samples_leaf=3, random_state=0) forest.fit(X_train, Y_train) #結果表示 print(forest.score(X_train, Y_train)) print(forest.score(X_test, Y_test))お、検証精度65.8%!!今までのソムリAIは62%台で頭打ちだったので最高記録です。ただし、訓練データでの精度が92%なので過学習の傾向があります。
交差検証
続いて交差検証です。いろいろ試したところ、訓練データを7分割するのがよさそうだったので、そのときの結果を載せます。これまで使ってきた決定木・ロジスティック回帰・ニューラルネットワーク・ランダムフォレストの4つの機械学習モデルに対してまとめて交差検証を行いました。まずは、訓練データでのモデル作成から。
import numpy as np from sklearn.preprocessing import StandardScaler from skyline.tree import DecisionTreeClassifier from sklearn.linear_model import LogisticRegression from sklearn.neural_network import MLPClassifier from sklearn.ensemble import RandomForestClassifier from sklearn.pipeline import Pipeline from sklearn.model_selection import cross_val_score #モデル1:決定木 clf1 = DecisionTreeClassifier(max_depth=4,random_state=0) #モデル2:ロジスティック回帰 clf2 = LogisticRegression(solver='lbfgs', C=0.1, random_state=0) pipe2 = Pipeline([['sc', StandardScaler()],['clf', clf2]]) #モデル3:ニューラルネットワーク clf3 = MLPClassifier(solver='lbfgs', activation='relu', random_state=0, hidden_layer_sizes=(200,200,200)) pipe3 = Pipeline([['sc', StandardScaler()],['clf', clf3]]) #モデル4:ランダムフォレスト clf4 = RandomForestClassifier(n_estimators=100, min_samples_leaf=3, random_state=0) #各モデルの名称をリストに格納 clf_labels = ['Decision Tree', 'Logistic Regression', 'Neural Network', 'Random Forest'] #各モデルに対して交差検証を行い結果を表示 for clf, label in zip([clf1, pipe2, pipe3, clf4], clf_labels): scores = cross_val_score(estimator=clf, X=X_train, y=Y_train, cv=7) print("訓練精度と標準偏差: %0.4f (+/- %0.2f) [%s]" % (scores.mean(), scores.std(), label))各モデル60%前後なので過学習は起こしていなさそうです。続いて、検証データでの精度を測定します。
from sklearn import metrics #各モデルに対して検証データでの予測精度を表示 for clf, label in zip(all_clf, clf_labels): clf.fit(X_train,Y_train) Y_pred = metrics.accuracy_score(Y_test, clf.predict(X_test)) print("検証精度: %0.4f [%s]" % (Y_pred, label))これまでのソムリAIの精度と比較してみると、ロジスティック回帰のパフォーマンスが上がりました。決定木は頭打ち・ニューラルネットワークはダウンしました。ランダムフォレストの精度が一番高いです。
多数決
最後に多数決(Majority Vote)という手法を試してみます。これは以前読んだ機械学習の本で紹介されていたものです。MajorityVoteClassifierという複数のモデルの結果を組み合わせた機械学習モデルを定義(この本の著者が自分で実装)して、よりよい学習モデルを作るという感じです。著作権的にアレなのでMajorityVoteClassifierのコードは載せず、結果だけ書きます。MajorityVoteClassifierの中身を知りたい方はこちらをどうぞ。
#MajorityVoteClassifierを使って多数決してみる #モデルの定義 mv_clf = MajorityVoteClassifier(classifiers=[clf1, pipe2, pipe3, clf4]) #多数決モデルをループさせるリストに追加 clf_labels += ['Majority Voting'] all_clf = [clf1, pipe2, pipe3, clf4, mv_clf] #各モデルに対して交差検証を行い結果を表示 for clf, label in zip(all_clf, clf_labels): scores = cross_val_score(estimator=clf, X=X_train, y=Y_train, cv=7) print("訓練精度と標準偏差: %0.4f (+/- %0.2f) [%s]" % (scores.mean(), scores.std(), label))訓練モデルの精度は61.86%とまずまずですが、ランダムフォレストの64.17%を下回っています。多数決は各モデルのいいとこどりをして各モデルよりも高い精度を出すことを目指すモデルなので、いまいちな結果です。精度50%台の決定木とロジスティック回帰が足を引っ張っているように見えます。
気を取り直して検証データで精度を測定します。
from sklearn import metrics #各モデルに対して検証データでの予測精度を表示 for clf, label in zip(all_clf, clf_labels): clf.fit(X_train,Y_train) Y_pred = metrics.accuracy_score(Y_test, clf.predict(X_test)) print("検証精度: %0.4f [%s]" % (Y_pred, label))検証データでの精度は65.42%となかなかいい値ですが、やはりランダムフォレストの65.83%を下回っています。
足を引っ張っていそうな決定木をはずして多数決してみます。
#MajorityVoteClassifierを使って多数決してみる #モデルの定義 mv_clf = MajorityVoteClassifier(classifiers=[pipe2, pipe3, clf4]) #使用するモデルをリストに格納 clf_labels = ['Logistic Regression', 'Neural Network', 'Random Forest', 'Majority Voting'] all_clf = [pipe2, pipe3, clf4, mv_clf] #各モデルに対して交差検証を行い結果を表示 for clf, label in zip(all_clf, clf_labels): scores = cross_val_score(estimator=clf, X=X_train, y=Y_train, cv=7) print("訓練精度と標準偏差: %0.4f (+/- %0.2f) [%s]" % (scores.mean(), scores.std(), label))訓練データでの精度は63.91%であり、あいかわらずランダムフォレストを下回っています。
検証データで精度を測定します。
from sklearn import metrics #各モデルに対して検証データでの予測精度を表示 for clf, label in zip(all_clf, clf_labels): clf.fit(X_train,Y_train) Y_pred = metrics.accuracy_score(Y_test, clf.predict(X_test)) print("検証精度: %0.4f [%s]" % (Y_pred, label))お!!多数決の精度が過去最高の66.46%であり、かつ各モデルの精度を上回っています。ようやく多数決の成果が出ました!
まとめ
各ソムリAIの性能をまとめるとこんな感じです。
アンサンブル学習をすることでわずか4%ではありますが、初期型より性能を改善することができました。今回使った多数決のようなアンサンブル学習は各モデルのいいとこどりをする一方で、精度の悪いモデルが混在していると足を引っ張られることがわかりました。とりあえずソムリAIはこれでおしまいにしようと思います。面白そうなネタを見つけたらまた投稿しようと思います!