一般的な機械学習では,データセットに対して様々なモデルを学習させ,その中から最も性能の良いものを選択する.しかし、アルゴリズムの性能を評価するのは必ずしも簡単な作業ではない。どのアルゴリズムが最も優れているかを判断するのに役立ついくつかの要因がある。その1つがクロスバリデーションでの性能であり、もう1つがアルゴリズムのパラメータの選択である。
この記事では、この2つの要因について詳しく見ていきます。まず、クロスバリデーションとは何か、なぜ必要なのか、そしてPythonのScikit-Learnライブラリを使ってどのように実行するのかについて学びます。その後、グリッド探索アルゴリズムに移り、アルゴリズムの最適なパラメータを自動的に選択するために、どのように使用できるかを見ていきます。
クロスバリデーション
通常、機械学習では、データをトレーニングセットとテストセットに分け、トレーニングセットでモデルの学習を行い、テストセットでモデルの性能を評価する。しかし、この方法は分散問題につながる可能性がある。簡単に言うと、あるテストで得られた精度が、同じアルゴリズムを使った別のテストセットで得られた精度と大きく異なるというシナリオが、分散問題です。
この問題を解決するには、性能評価にK-Foldクロスバリデーションを使用することです。K-フォールド・クロス・バリデーションのプロセスは簡単です。データをK個のフォルドに分割する。K個のフォルドのうち、K-1個のフォルドがトレーニングに使われ、残りのフォルドがテストに使われる。アルゴリズムはK回学習とテストを行い、毎回新しいセットがテストセットとして使用され、残りのセットが学習に使用される。最後に,K-Fold クロスバリデーションの結果は,各集合で得られた結果の平均となる.
例えば、5重クロスバリデーションを行いたいとする。そのために、データを5つのセット、例えばSET A, SET B, SET C, SET D, SET Eに分割し、アルゴリズムをK回学習しテストします。1回目は、下図に示すように、SET AからSET Dをトレーニングセットとして、SET Eをテストセットとして使用します。
2 回目は、SET A、SET B、SET C、SET E をトレーニングに使用し、SET D をテストに使用します。このプロセスは、すべてのセットが少なくとも1回はトレーニングに使われ、1回はテストに使われるまで続けられる。最終的な結果は、すべてのフォールドを使用して得られた結果の平均である。この方法で、分散を取り除くことができます。各折れ線から得られた結果の標準偏差を用いれば、実際、全体の結果の分散を求めることができます。
Scikit-Learnによるクロスバリデーション
このセクションでは、分類のためのランダムフォレストアルゴリズムのパフォーマンスを評価するために、クロスバリデーションを使用します。我々が解決しようとする問題は、12の属性に基づいてワインの品質を予測することである。データセットの詳細は以下のリンクから入手可能です。
この記事では、赤ワインのデータのみを使用します。
Scikit-Learnを使ってクロスバリデーションを実装するには、以下のステップに従います。
1. 必要なライブラリのインポート
以下のコードでは、必要なライブラリの一部をインポートしています。
import pandas as pd
import numpy as np
2. データセットのインポート
このリンクからオンラインで入手できるデータセットをダウンロードする。

ダウンロードしたら、この記事のために「D」ドライブの「Datasets」フォルダーにファイルを置く。データセット名は “winequality-red.csv “である。なお、ファイルのパスは、パソコンに保存した場所に合わせて変更する必要があります。
以下のコマンドを実行し、データセットをインポートしてください。
dataset = pd.read_csv(r"D:/Datasets/winequality-red.csv", sep=';')
データセットはセミコロンで区切られているので、sepパラメータに”; “属性を渡して、pandasがファイルを適切にパースできるようにしています。
3. データ分析
以下のスクリプトを実行し、データの概要を把握する。
dataset.head()
出力は次のようなものである。
| 固定酸度|揮発性酸度|クエン酸|残糖|塩化物|遊離二酸化硫黄|全二酸化硫黄|濃度|pH|硫酸塩|アルコール|品質|など。
| — | — | — | — | — | — | — | — | — | — | — | — | — |
| 0 | 7.4 | 0.70 | 0.00 | 1.9 | 0.076 | 11.0 | 34.0 | 0.9978 | 3.51 | 0.56 | 9.4 | 5 |
| 1 | 7.8 | 0.88 | 0.00 | 2.6 | 0.098 | 25.0 | 67.0 | 0.9968 | 3.20 | 0.68 | 9.8 | 5 |
| 2 | 7.8 | 0.76 | 0.04 | 2.3 | 0.092 | 15.0 | 54.0 | 0.9970 | 3.26 | 0.65 | 9.8 | 5 |
| 3 | 11.2 | 0.28 | 0.56 | 1.9 | 0.075 | 17.0 | 60.0 | 0.9980 | 3.16 | 0.58 | 9.8 | 6 |
| 4 | 7.4 | 0.70 | 0.00 | 1.9 | 0.076 | 11.0 | 34.0 | 0.9978 | 3.51 | 0.56 | 9.4 | 5 |
4. データの前処理
以下のスクリプトを実行し、データをラベルセットと特徴量セットに分割する。
X = dataset.iloc[:, 0:11].values
y = dataset.iloc[:, 11].values
今回はクロスバリデーションを行うので、データをトレーニングセットとテストセットに分ける必要はない。クロスバリデーションを適用するために、すべてのデータをトレーニングセットで使用します。一番簡単な方法は、test_size
パラメータの値を0にすることです。これにより、以下のようにトレーニングセットのすべてのデータが返されます。
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0, random_state=0)
5. データのスケーリング
データセットを見てみると、うまくスケーリングされていないことに気がつくだろう。例えば、「揮発性酸度」と「クエン酸」の列は0から1の間の値を持ち、残りのほとんどの列は高い値を持つ。したがって、アルゴリズムを学習する前に、データをスケールダウンする必要がある。
ここでは、StandardScalar
クラスを使用します。
from sklearn.preprocessing import StandardScaler
feature_scaler = StandardScaler()
X_train = feature_scaler.fit_transform(X_train)
X_test = feature_scaler.transform(X_test)
6. 学習とクロスバリデーション
学習とクロスバリデーションの最初のステップは簡単です。以下のように、sklearn
ライブラリからアルゴリズムクラスをインポートするだけである。
from sklearn.ensemble import RandomForestClassifier
classifier = RandomForestClassifier(n_estimators=300, random_state=0)
次に、クロスバリデーションを行うために、sklearn.model_selection
ライブラリの cross_val_score
メソッドを使用します。cross_val_scoreは全てのフォールドの精度を返します。cross_val_score
クラスには4つのパラメータが必要である。最初のパラメータは estimator であり、基本的にはクロスバリデーションに用いるアルゴリズムを指定する。2 番目と 3 番目のパラメータ X
と y
には、それぞれ X_train
と y_train
のデータ、つまり特徴量とラベルを指定する。最後に、次のコードに示すように、 cv
パラメータにフォルド数を渡します。
from sklearn.model_selection import cross_val_score
all_accuracies = cross_val_score(estimator=classifier, X=X_train, y=y_train, cv=5)
このように実行したら、cross_val_score
メソッドが返す5つのフォルドの精度を、 all_accuracies
に対して print
をコールして表示してみましょう。
print(all_accuracies)
出力されます。
[ 0.72360248 0.68535826 0.70716511 0.68553459 0.68454259 ]
すべての精度の平均を求めるには、以下のように cross_val_score
メソッドから返されたオブジェクトの mean()
メソッドを使用します。
print(all_accuracies.mean())
平均値は0.6972、つまり69.72%です。
最後に、データの標準偏差を求め、モデルによって得られた結果の分散度合いを見てみましょう。これを行うには、all_accuracies
オブジェクトの std()
メソッドを呼び出します。
print(all_accuracies.std())
結果は 0.01572で、1.57%です。これは非常に低く、我々のモデルの分散が非常に低いことを意味します。これは、あるテストセットで得られた予測が偶然ではないことを意味するので、実際には非常に良いことです。むしろ、このモデルはすべてのテストセットで多かれ少なかれ似たようなパフォーマンスを示すでしょう。
パラメータ選択のためのグリッドサーチ
機械学習モデルには2種類のパラメータがある。1つ目のパラメータは機械学習モデルを通して学習されるパラメータであり、2つ目のパラメータは我々が機械学習モデルに渡すハイパーパラメータである。
前節では、ワインの品質を予測する際に、Random Forest アルゴリズムを用いた。このアルゴリズムで使用した推定量の数は 300 である。同様に、KNN アルゴリズムでは K の値を、SVM アルゴリズムではカーネルの種類を指定する必要がある。これらの推定量であるKの値やカーネルは,いずれもハイパーパラメータの一種である.
通常、これらのハイパーパラメータの値をランダムに設定し、どのパラメータが最も良い性能になるかを見ます。しかし、アルゴリズムのパラメータをランダムに選択することは、疲弊してしまう可能性があります。
また、あるアルゴリズムが異なるパラメータを設定した場合に、他のアルゴリズムよりも優れた性能を発揮する可能性があるため、ハイパーパラメータをランダムに設定して異なるアルゴリズムの性能を比較することは容易ではありません。また、パラメータを変更した場合、そのアルゴリズムは他のアルゴリズムよりも性能が悪くなる可能性がある。
したがって、パラメータの値をランダムに選択するのではなく、特定のモデルに最適なパラメータを自動的に見つけるアルゴリズムを開発することがより良いアプローチであると考えられる。グリッドサーチはそのようなアルゴリズムの一つである.
Scikit-Learnによるグリッド検索
例題を使ってグリッド検索アルゴリズムを実装してみよう。このセクションのスクリプトは、前セクションで作成したスクリプトの後に実行する必要がある。
グリッド検索アルゴリズムを実装するためには、sklearn.model_selection
ライブラリから GridSearchCV
クラスをインポートする必要があります。
最初に行うべきことは、最高のパフォーマンスを得るためにテストしたいすべてのパラメータとそれに対応する値のセットの辞書を作成することです。辞書の項目名はパラメータ名に対応し、値はそのパラメータの値のリストに対応します。
ここでは、ランダムフォレストアルゴリズムのパラメータとそれに対応する値の辞書を作成してみましょう。ランダムフォレストアルゴリズムのすべてのパラメータの詳細は、Scikit-Learnのドキュメントに記載されています。
そのために、以下のコードを実行します。
grid_param = {
'n_estimators': [100, 300, 500, 800, 1000],
'criterion': ['gini', 'entropy'],
'bootstrap': [True, False]
}
上のコードをよく見てください。ここでは、n_estimators
、criterion
、bootstrap
の3つのパラメータを持つ grid_param
辞書を作成しています。その中に、試したいパラメータの値が渡されます。例えば、上記のスクリプトでは、(100、300、500、800、1000のうち)どの値が最も高い精度を提供するかを見つけたいとします。
同様に、criterion
パラメータについても、どの値が最も高い性能をもたらすかを見つけたいのです。「gini “と “entropy “のどちらでしょうか?グリッド探索アルゴリズムは、基本的にパラメータ値のすべての可能な組み合わせを試し、最も精度の高い組み合わせを返します。例えば、上記の場合、アルゴリズムは20の組み合わせをチェックします(5 x 2 x 2 = 20)。
グリッド探索アルゴリズムは、テストする組み合わせの数が膨大になる可能性があるため、非常に遅くなることがあります。さらに、クロスバリデーションは、実行時間と複雑さをさらに増加させます。
パラメータ辞書を作成したら、次は GridSearchCV
クラスのインスタンスを作成します。パラメータ estimator
には値を渡す必要があります。これは基本的に実行したいアルゴリズムになります。param_gridパラメータには先ほど作成したパラメータ辞書を、
scoringパラメータにはパフォーマンスメトリクスを、
cvパラメータにはフォルド数(この例では 5)を、そして最後に
n_jobsパラメータには実行に使用する CPU の数を指定します。n_jobs
パラメータに -1 を指定すると、利用可能なすべての計算能力を使用することになります。これは、大量のデータがある場合に便利です。
次のコードを見てください。
gd_sr = GridSearchCV(estimator=classifier,
param_grid=grid_param,
scoring='accuracy',
cv=5,
n_jobs=-1)
GridSearchCVクラスが初期化されたら、次のコードに示すように、クラスの
fit` メソッドを呼び出して、トレーニングセットとテストセットを渡すのが最後のステップになります。
gd_sr.fit(X_train, y_train)
このメソッドの実行には時間がかかります。なぜなら、パラメータの組み合わせが20通りあり、5重のクロスバリデーションが行われるからです。したがって、このアルゴリズムは合計100回実行されることになります。
メソッドの実行が完了したら、次のステップは、最も高い精度を返すパラメータをチェックすることです。これを行うには、以下のように GridSearchCV
オブジェクトの sr.best_params_
属性を出力します。
best_parameters = gd_sr.best_params_
print(best_parameters)
出力してください。
{'bootstrap': True, 'criterion': 'gini', 'n_estimators': 1000}
この結果から、n_estimators
が1000、bootstrap
が True
、criterion
が “gini” の時に最も高い精度が得られることがわかります。
注意:n_estimators
の許容値を最高値に設定したため、より多くの推定量を追加して性能がさらに向上するかどうかを確認するのも良いアイデアでしょう。
グリッドサーチアルゴリズムの最後のステップは、最適なパラメータを使用して得られた精度を求めることです。前回は、300人の n_estimators
で69.72%の平均精度を得ました。
最高の精度を得るには、以下のコードを実行します。
best_result = gd_sr.best_score_
print(best_result)
達成された精度は、69.85%の0.6985で、69.72%より少し良いだけです。これをさらに改善するには、精度がさらに向上するかどうかを確認するために、max_features
、max_depth
、max_leaf_nodes
など、Random Forestアルゴリズムの他のパラメータに対する値をテストするのがよいでしょう。
さらに上を目指す – 手作りのEnd to Endプロジェクト
好奇心旺盛なあなたは、もっと先を目指したいと思っていませんか?そんなあなたには、ガイド付きプロジェクトがおすすめです。「ハンズオン住宅価格予測 – Pythonによる機械学習” をご覧ください。
をご覧ください。
このプロジェクトでは、Scikit-LearnとKerasのモデルから住宅価格を予測するために、従来の機械学習モデルや深層学習モデル、アンサンブル学習、メタラーを利用した強力な構築方法を学ぶことができます。
>
>
>
Tensorflowの上に構築された深層学習APIであるKerasを使って、アーキテクチャを試し、積み重ねたモデルのアンサンブルを構築し、メタラーナーのニューラルネットワーク(レベル1モデル)を訓練して、家の価格を割り出すことにします。
ディープラーニングは素晴らしいものですが、それに頼る前に、浅い学習アルゴリズムのような、より単純な技術で問題を解決することも試みることをお勧めします。ベースラインの性能は、ランダムフォレスト回帰アルゴリズムに基づくものです。さらに、Scikit-Learnを使用して、バギングや投票などの手法により、モデルのアンサンブルを作成することも検討します。
これはエンドツーエンドのプロジェクトであり、他の機械学習プロジェクトと同様に、探索的データ分析から始まり、データ前処理を経て、最後に浅い学習と深い学習のモデルを構築して、以前に探索しクリーニングしたデータに適合させることになります。
結論
この記事では、アルゴリズムの性能評価とモデル選択のために非常によく使われる2つの技法について研究しました。K-Fold Cross-Validationは、結果集合の分散問題を扱うことで、モデルの性能を評価するために使用することができます。さらに、最適なアルゴリズムと最適なパラメータを特定するために、グリッドサーチアルゴリズムを使用することができる。