【Python】Scikit-learn RandomizedSearchCVの使い方!GridSearchCVとの違いや実装例を徹底解説

Python

機械学習モデルの精度を向上させるために、「ハイパーパラメータチューニング」は避けて通れない重要なステップです。

しかし、すべてのパラメータの組み合わせを試す手法(GridSearchCV)では、膨大な計算時間がかかってしまい、途方に暮れた経験がある方も多いのではないでしょうか。

この記事では、Pythonの機械学習ライブラリ「Scikit-learn(サイキットラーン)」に搭載されている、高速かつ効率的なチューニング手法である**「RandomizedSearchCV」**の使い方を、初心者から中級者に向けてわかりやすく解説します。

この記事を読むことで、限られた時間の中でモデルの性能を最大化する実践的なスキルが身につきます。ぜひ、ご自身のプロジェクトに取り入れてみてください。本記事で解説している内容の公式ドキュメントはこちらです。

RandomizedSearchCVとは?基本概念を理解する

結論:RandomizedSearchCVは、指定したパラメータの範囲から「ランダム」に組み合わせを抽出して評価する探索手法です。

機械学習アルゴリズムには、人間が手動で設定しなければならない「ハイパーパラメータ」が多数存在します。これらを最適化するためのツールとして、Scikit-learnには複数の手法が用意されていますが、その中でも近年主流となっているのがこのRandomizedSearchCVです。

ハイパーパラメータチューニングの重要性

結論:モデルの予測精度や汎化性能を限界まで引き上げるために、チューニングは必須の作業です。

機械学習モデルは、デフォルトの設定のままではデータに対して最適なパフォーマンスを発揮できないことがほとんどです。

例えば、ランダムフォレストにおける「決定木の深さ」や、サポートベクターマシンにおける「ペナルティパラメータ」など、データセットの特性に合わせて最適な値を調整することで、初めて実用的な精度を叩き出すことができます。この最適な設定値を探す旅こそが、ハイパーパラメータチューニングなのです。

GridSearchCVとの決定的な違い

結論:すべての組み合わせを試すのがGridSearchCV、指定回数だけランダムに試すのがRandomizedSearchCVです。

従来よく使われてきたGridSearchCV(グリッドサーチ)は、あらかじめ指定したパラメータのリストの「全組み合わせ」を網羅的に検証します。確実性は高いですが、パラメータの種類が増えると計算量が指数関数的に爆発し、実行に何日もかかってしまうことがあります。

一方、RandomizedSearchCV(ランダムサーチ)は、全組み合わせの中からランダムに指定した回数(n_iter)だけをピックアップして検証します。すべてのパターンを試さないため不安に感じるかもしれませんが、実は「重要なパラメータの最適解は、ランダム探索でも十分な確率で見つけられる」ことが研究によって証明されており、実戦では非常に強力な武器となります。

RandomizedSearchCVのメリットとデメリット

結論:圧倒的なスピードが最大の武器ですが、必ずしも絶対的な最適解が出るとは限らない点に注意が必要です。

どのようなアルゴリズムにも一長一短があります。実務で正しく使いこなすために、メリットとデメリットを正しく把握しておきましょう。

メリット:計算時間を圧倒的に短縮できる

結論:n_iter(試行回数)を指定できるため、計算リソースや期限に合わせて柔軟にチューニングが可能です。

最大のメリットは、探索にかかる「時間」を自分でコントロールできる点です。

例えば、10種類のパラメータの組み合わせが合計10万通りあったとします。GridSearchでは10万回の学習と評価が必要ですが、RandomizedSearchであれば「今回は時間がないから100回(n_iter=100)だけランダムに試す」という指示が可能です。これにより、少ない計算コストで、そこそこ良い(実用上問題のないレベルの)ハイパーパラメータを素早く見つけることができます。

デメリット:最適解を逃すリスクがある

結論:ランダム抽出の性質上、ピンポイントで存在する「最高精度のパラメータ」を引き当てられない可能性があります。

全探索を行わないため、偶然にも最適なパラメータの組み合わせをスキップしてしまうリスクは常に存在します。

しかし、実務において「100点満点」のパラメータを探すために1週間待つよりも、「95点」のパラメータを10分で見つけて次の実験に進む方が、プロジェクト全体の進行としては価値が高いことが大半です。このトレードオフを理解した上で活用することが重要です。

RandomizedSearchCVの基本的な使い方【Pythonコード例】

結論:Scikit-learnを使えば、数行のコードで簡単にRandomizedSearchCVを実装できます。

それでは、実際にPythonのコードを書きながら使い方を学んでいきましょう。今回は、機械学習の定番データセットである「乳がんデータセット(Breast Cancer dataset)」を使用し、ランダムフォレスト(RandomForestClassifier)のパラメータをチューニングします。

必要なライブラリとデータセットの準備

結論:Scikit-learnから、データセット、モデル、評価指標、そしてRandomizedSearchCVをインポートします。

まずは必要なモジュールを読み込み、データを学習用とテスト用に分割します。

import pandas as pd
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split, RandomizedSearchCV
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score

# 乳がんデータセットの読み込み
data = load_breast_cancer()
X = data.data
y = data.target

# データを学習データとテストデータに分割 (80%を学習用、20%をテスト用に)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

print(f"学習データのサイズ: {X_train.shape}")
print(f"テストデータのサイズ: {X_test.shape}")

モデルと探索空間(パラメータ)の定義

結論:ディクショナリ(辞書)型を使って、試したいパラメータ名と値のリストを定義します。

次に、ベースとなる機械学習モデルと、探索したいハイパーパラメータの範囲を設定します。

# ランダムフォレストモデルの初期化
rf_model = RandomForestClassifier(random_state=42)

# 探索したいハイパーパラメータの空間(範囲)を定義
# リスト形式で候補となる値を複数用意します
param_distributions = {
    'n_estimators': [50, 100, 200, 300],          # 決定木の数
    'max_depth': [None, 5, 10, 15, 20],           # 木の深さ
    'min_samples_split': [2, 5, 10],              # ノードを分割するための最小サンプル数
    'min_samples_leaf': [1, 2, 4]                 # 葉を構成するための最小サンプル数
}

この例では、4つのパラメータを指定しています。GridSearchCVの場合はすべての組み合わせ(4 × 5 × 3 × 3 = 180通り)を試すことになりますが、今回はRandomizedSearchCVで回数を絞って探索します。

探索の実行とベストパラメータの確認

結論:fit()メソッドを実行するだけで、指定した回数分のランダム探索と交差検証(クロスバリデーション)が自動で行われます。

いよいよRandomizedSearchCVを実行します。ここで重要なのが n_iter パラメータです。

# RandomizedSearchCVの設定
# n_iter=20: ランダムに20パターンの組み合わせを試す
# cv=5: 5分割交差検証を行う
# n_jobs=-1: 利用可能なすべてのCPUコアを使って並列処理を行う
random_search = RandomizedSearchCV(
    estimator=rf_model,
    param_distributions=param_distributions,
    n_iter=20,               # 探索する回数
    cv=5,                    # 交差検証の分割数
    scoring='accuracy',      # 評価指標(今回は正解率)
    random_state=42,         # 乱数のシード固定(結果の再現性のため)
    n_jobs=-1                # 並列処理による高速化
)

# 探索の実行(学習データを使ってチューニング)
print("ハイパーパラメータの探索を開始します...")
random_search.fit(X_train, y_train)

# 最適なパラメータの表示
print("\n見つかった最適なパラメータ:")
print(random_search.best_params_)

# 最適なパラメータでの交差検証スコア
print(f"\n学習時のベストスコア(正解率): {random_search.best_score_:.4f}")

# 最適なモデルを取得し、テストデータで最終評価
best_model = random_search.best_estimator_
y_pred = best_model.predict(X_test)
test_accuracy = accuracy_score(y_test, y_pred)

print(f"\nテストデータでの最終スコア(正解率): {test_accuracy:.4f}")

このように、非常に短いコードで高度なチューニングとモデル評価が完了します。best_params_ を呼び出すことで、見つけ出した最良の組み合わせを簡単に確認できます。

応用編:scipy.statsを使った効率的な探索空間の指定

結論:リストではなく、確率分布を指定することで、より連続的で柔軟なパラメータ探索が可能になります。

中級者へのステップアップとして押さえておきたいのが、scipy.stats を利用したパラメータ空間の定義です。

連続値や離散値の確率分布を指定する

結論:連続値には uniform、整数値には randint などの分布を使用することで、抜け漏れのない探索が実現します。

先ほどの例では [50, 100, 200] のように「決め打ちのリスト」を渡しましたが、これだと「150」や「123」といったリスト以外の値は絶対に選ばれません。

RandomizedSearchCVは、パラメータ空間として「リスト」だけでなく「確率分布」を受け取ることができます。分布を渡すことで、指定した範囲内のあらゆる数値をランダムに生成して試してくれます。

確率分布を活用した実践的なコード例

結論:scipy.statsをインポートし、パラメータの辞書に分布オブジェクトを直接割り当てます。

以下が、確率分布を用いたより高度な探索のコード例です。

import scipy.stats as stats

# scipy.statsを使ったより柔軟な探索空間の定義
param_dist_advanced = {
    # 50から300までの整数を均等な確率でランダムに選ぶ
    'n_estimators': stats.randint(50, 300),
    
    # max_depthはNone(制限なし)も含めたいのでリストと混在させることも可能ですが、
    # ここでは整数の範囲を指定します
    'max_depth': stats.randint(3, 20),
    
    # 0.01から1.0までの連続値(浮動小数点)を均等に選ぶ(例:学習率などに便利)
    # ※ランダムフォレストには学習率はありませんが、XGBoostやLightGBMなどで頻出します
    # 'learning_rate': stats.uniform(0.01, 1.0)
}

# 再度RandomizedSearchCVを実行
random_search_adv = RandomizedSearchCV(
    estimator=rf_model,
    param_distributions=param_dist_advanced,
    n_iter=30,           # 試行回数を30回に増やす
    cv=5,
    random_state=42,
    n_jobs=-1
)

random_search_adv.fit(X_train, y_train)

print("分布探索で見つかった最適なパラメータ:")
print(random_search_adv.best_params_)

この手法を使えば、事前になんとなくのアタリをつける必要がなくなり、より広大で滑らかな空間から最適なハイパーパラメータを探し出すことができます。

Scikit-learnのバージョンに関する注意点

結論:RandomizedSearchCVはScikit-learnのほぼ全てのバージョンで安定して利用可能です。

本記事で紹介した sklearn.model_selection.RandomizedSearchCV は、非常に古くから存在する安定したクラスです。Scikit-learnのバージョン 0.20 以降から最新の 1.x 系まで、幅広いバージョンで動作が変わることなく利用できます。

ただし、並列処理を指定する n_jobs=-1 に関しては、PCの環境や古いバージョンにおいてメモリ不足のエラーを引き起こすケースが稀にあります。もし実行時にパソコンが固まったりフリーズしたりする場合は、n_jobs=2 のように使用するコア数を明示的に制限してみてください。

まとめ:RandomizedSearchCVで効率的なモデル構築を

結論:時間を賢く使い、実用的な高精度モデルを最速で構築するために、RandomizedSearchCVをマスターしましょう。

この記事では、PythonのScikit-learnを用いたハイパーパラメータチューニング手法である「RandomizedSearchCV」について解説しました。

  • GridSearchCVとの違い: 全探索ではなく、ランダムに指定回数だけ探索を行う。(GridSearchCVに関する記事はこちら)
  • 最大のメリット: 探索時間(n_iter)をコントロールでき、圧倒的に高速。
  • 実践的なテクニック: scipy.stats の確率分布を使うことで、より網羅的で柔軟な探索が可能。

機械学習の実務では、「スピード」と「精度」のバランスが常に求められます。GridSearchCVの待ち時間に悩まされていた方は、今日からぜひRandomizedSearchCVを導入し、爆速で快適なモデルチューニングを体験してみてください。

コメント

タイトルとURLをコピーしました