はじめに
この実験では、複数の候補から逐次的に最適なパラメータコンビネーションを選択するための逐次半分探索法を学びます。この方法は、Scikit-learn ライブラリのHalvingGridSearchCVとHalvingRandomSearchCVクラスで実装されています。この実験ではHalvingRandomSearchCVクラスを使用します。
VM のヒント
VM の起動が完了したら、左上隅をクリックしてノートブックタブに切り替え、Jupyter Notebook を使って練習しましょう。
時々、Jupyter Notebook が読み込み終わるまで数秒待つ必要がある場合があります。Jupyter Notebook の制限により、操作の検証を自動化することはできません。
学習中に問題に遭遇した場合は、Labby にお問い合わせください。セッション後にフィードバックを提供してください。すぐに問題を解決いたします。
必要なライブラリのインポート
この実験では、以下のライブラリを使用します:pandas、numpy、matplotlib、sklearn.datasets、RandomForestClassifier、randint、およびHalvingRandomSearchCV。以下のコードを使ってインポートしましょう:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.ensemble import RandomForestClassifier
from scipy.stats import randint
from sklearn.experimental import enable_halving_search_cv
from sklearn.model_selection import HalvingRandomSearchCV
データセットの読み込み
sklearn.datasetsモジュールのmake_classification関数を使って分類用のデータセットを生成します。このデータセットは 12 個の特徴量を持つ 400 個のサンプルで構成されています。データセットを読み込むコードは以下の通りです:
rng = np.random.RandomState(0)
X, y = datasets.make_classification(n_samples=400, n_features=12, random_state=rng)
パラメータ空間の定義
探索するハイパーパラメータとそれぞれの値を含む辞書param_distを定義します。ハイパーパラメータはmax_depth、max_features、min_samples_split、bootstrap、およびcriterionです。max_featuresとmin_samples_splitの探索範囲は、scipy.statsモジュールのrandint関数を使って定義されます。パラメータ空間を定義するコードは以下の通りです:
param_dist = {
"max_depth": [3, None],
"max_features": randint(1, 6),
"min_samples_split": randint(2, 11),
"bootstrap": [True, False],
"criterion": ["gini", "entropy"],
}
逐次半分ランダム探索オブジェクトの作成
パラメータ空間を探索するためのHalvingRandomSearchCVオブジェクトを作成します。このオブジェクトには以下の引数が必要です:
estimator:最適化する推定器param_distributions:探索するパラメータ空間factor:各反復で候補の数を減らす割合random_state:探索に使用する乱数シード
オブジェクトを作成するコードは以下の通りです:
clf = RandomForestClassifier(n_estimators=20, random_state=rng)
rsh = HalvingRandomSearchCV(
estimator=clf, param_distributions=param_dist, factor=2, random_state=rng
)
逐次半分ランダム探索オブジェクトの適合
fitメソッドを使ってHalvingRandomSearchCVオブジェクトをデータセットに適合させます。オブジェクトを適合させるコードは以下の通りです:
rsh.fit(X, y)
結果の分析
探索オブジェクトのcv_results_属性には探索の結果が含まれています。以下のコードを使ってそれを pandas のデータフレームに変換します:
results = pd.DataFrame(rsh.cv_results_)
params_str列はparams列を文字列に変換することで作成されます。同じparams_strとiter値を持つ重複行を削除します:
results["params_str"] = results.params.apply(str)
results.drop_duplicates(subset=("params_str", "iter"), inplace=True)
次に、平均テストスコアをpivotメソッドを使って反復回数とパラメータの組み合わせに対してピボットします:
mean_scores = results.pivot(
index="iter", columns="params_str", values="mean_test_score"
)
最後に、以下のコードを使って反復回数に対する平均テストスコアをプロットします:
ax = mean_scores.plot(legend=False, alpha=0.6)
labels = [
f"iter={i}\nn_samples={rsh.n_resources_[i]}\nn_candidates={rsh.n_candidates_[i]}"
for i in range(rsh.n_iterations_)
]
ax.set_xticks(range(rsh.n_iterations_))
ax.set_xticklabels(labels, rotation=45, multialignment="left")
ax.set_title("Scores of candidates over iterations")
ax.set_ylabel("mean test score", fontsize=15)
ax.set_xlabel("iterations", fontsize=15)
plt.tight_layout()
plt.show()
結果の解釈
このグラフは、反復回数に対する候補の平均テストスコアを示しています。最初の反復では、すべての候補が少量のリソースで評価されます。2 番目の反復では、候補の上位半分のみが 2 倍のリソースで評価されます。このプロセスは、最後の反復まで繰り返され、そこでは 2 つの候補のみが残ります。最良の候補は、最後の反復で平均テストスコアが最も高いものです。
まとめ
この実験では、逐次半分探索法を使って複数の候補の中から最適なパラメータの組み合わせを反復的に選ぶ方法を学びました。Scikit-learn ライブラリのHalvingRandomSearchCVクラスを使って探索法を実装しました。探索の結果は、反復回数に対する平均テストスコアのグラフを使って分析および解釈しました。