[機械学習のはじめ方] Part16: ランダムフォレストとバギング

機械学習

はじめに:一人よりみんなの力!アンサンブル学習

機械学習にはたくさんのモデルがありますが、一つのモデルだけで完璧な予測をするのは難しいことがあります🤔。そこで登場するのが「アンサンブル学習」という考え方です。

アンサンブル学習は、複数のモデル(学習器)を組み合わせて、それぞれのモデルの弱点を補い合い、より強力で安定した予測性能を目指す手法です。まるで、一人で悩むよりも、みんなで知恵を出し合った方が良いアイデアが出るのと同じですね!

今回は、アンサンブル学習の中でも特に有名で強力な「バギング」と、それをさらに進化させた「ランダムフォレスト」について学んでいきましょう。これらは、決定木というモデルをベースにしていますが、決定木単体よりも高い精度を出すことが期待できます✨。

バギング (Bagging): 弱点を補い合うチーム作り🤝

バギング (Bagging) は、「Bootstrap Aggregating」の略で、アンサンブル学習の基本的な手法の一つです。名前の通り、「ブートストラップサンプリング」と「アグリゲーティング(集約)」という2つの要素から成り立っています。

  1. ブートストラップサンプリング (Bootstrap Sampling)
    元の学習データから、ランダムにデータを復元抽出し(同じデータを何度も選んでOK)、元のデータと同じサイズの新しいデータセットを複数作成します。これにより、少しずつ異なるデータセットがたくさんできます。🎒
  2. モデルの学習
    作成したそれぞれのデータセットを使って、個別のモデル(通常は同じ種類のモデル、例えば決定木)を学習させます。データセットが少しずつ違うので、学習されるモデルも少しずつ個性が出ます。
  3. アグリゲーティング (Aggregating)
    すべてのモデルの予測結果を集約します。
    • 分類問題の場合: 各モデルの予測結果で多数決を取ります🗳️。
    • 回帰問題の場合: 各モデルの予測値の平均を取ります📊。

バギングの主な目的は、モデルのバリアンス(予測のばらつき)を減らすことです。特に、決定木のようにデータの一部が変わると結果が大きく変わりやすい(不安定な)モデルに対して効果的で、過学習(学習データに適合しすぎて未知のデータに対応できない状態)を抑制する効果があります。

バギングのメリット・デメリット

メリット 👍デメリット 👎
過学習を抑制しやすいモデルの解釈が難しくなる(単体の決定木より)
予測精度が向上することが多い計算コストが増加する(複数のモデルを学習するため)
不安定なモデル(決定木など)の性能を安定させられる元々安定しているモデル(線形回帰など)には効果が薄いことがある

バギングは、複数のモデルを並行して学習できるため、計算資源があれば効率的に学習を進めることができます。

ランダムフォレスト (Random Forest): バギングの進化版!🌳🌲

ランダムフォレストは、バギングをさらに強力にしたアルゴリズムで、2001年にLeo Breimanによって提案されました。現在でも非常に人気があり、多くの場面で高い性能を発揮します。

ランダムフォレストの基本的な考え方はバギングと同じで、複数の決定木を学習させて結果を集約します。しかし、バギングとの大きな違いが一つあります。それは、「特徴量のランダム選択」です。

通常の決定木やバギングでは、ノード(データを分割する点)でデータを分割する際に、すべての特徴量の中から最適な分割点を探します。しかし、ランダムフォレストでは、ノードごとにランダムに選ばれた一部の特徴量の中から最適な分割点を探します。

なぜこのようなことをするのでしょうか?🤔 バギングだけだと、もし非常に強力な特徴量(予測にすごく役立つ特徴量)があった場合、多くの決定木がその特徴量を初期の段階で使ってしまい、結果として似たような決定木がたくさんできてしまう可能性があります。木々の相関が高くなってしまうのです。

ランダムフォレストでは、特徴量をランダムに制限することで、各決定木が使う特徴量に多様性を持たせます。これにより、個々の決定木の相関が低くなり、それぞれの木が異なる側面からデータを学習するようになります。結果として、アンサンブル全体の汎化性能(未知のデータへの対応力)がさらに向上し、より頑健なモデルになります💪。

ランダムフォレストの仕組みまとめ

  1. 元の学習データからブートストラップサンプリングで複数のデータセットを作成(バギングと同じ)。
  2. 各データセットで決定木を学習させる。
  3. ただし、各ノードで分割を行う際、ランダムに選ばれた一部の特徴量の中から最適な分割点を探す(ここがバギングとの違い!)。
  4. できた複数の決定木の予測結果を多数決(分類)または平均(回帰)で集約する(バギングと同じ)。

ランダムフォレストのメリット・デメリット

メリット 👍デメリット 👎
高い予測精度を発揮することが多いモデルの解釈性が低い(多数の木が複雑に絡み合うため)
過学習しにくい(バギングよりさらに抑制)計算コスト・メモリ使用量が大きい(特に木の数が多い場合)
特徴量の重要度を評価できるパラメータチューニングが不要なわけではない
欠損値や外れ値に対して比較的頑健
並列処理が可能で学習を高速化できる

主なハイパーパラメータ

scikit-learnのRandomForestClassifierRandomForestRegressorでよく調整されるハイパーパラメータには以下のようなものがあります。

  • n_estimators: 作成する決定木の数。多いほど性能は安定する傾向がありますが、計算コストが増えます。デフォルトは100。
  • max_depth: 各決定木の最大の深さ。深くしすぎると過学習のリスクがあります。None(制限なし)がデフォルト。
  • max_features: ノード分割時に考慮する特徴量の最大数(または割合)。’sqrt’(特徴量の平方根)、’log2’、数値、割合などで指定します。分類では’sqrt’、回帰ではNone(全ての特徴量)がデフォルトの場合があります(バージョンにより異なる)。ランダムフォレストの重要なパラメータです。
  • min_samples_split: ノードを分割するために必要な最小サンプル数。
  • min_samples_leaf: 葉ノード(末端のノード)に必要な最小サンプル数。
  • bootstrap: ブートストラップサンプリングを行うかどうか。デフォルトはTrue。
  • criterion: 分割の品質を測る基準。分類では’gini’(ジニ不純度)または’entropy’(情報利得)、回帰では’squared_error’(MSE)などが使われます。

Python (scikit-learn) での実装例 🐍

それでは、scikit-learnを使ってランダムフォレスト(分類)を実装してみましょう。ここでは、有名なアヤメ(iris)データセットを使います。


# 必要なライブラリをインポート
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_iris
from sklearn.metrics import accuracy_score

# 1. データの準備
iris = load_iris()
X = iris.data  # 特徴量 (がく片の長さ・幅、花びらの長さ・幅)
y = iris.target # 目的変数 (アヤメの種類: 0, 1, 2)

# データを訓練用とテスト用に分割 (例: 70%を訓練用、30%をテスト用)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42, stratify=y)

print(f'訓練データのサイズ: {X_train.shape}')
print(f'テストデータのサイズ: {X_test.shape}')

# 2. モデルの選択と学習
# ランダムフォレスト分類器を作成 (決定木の数=100)
# random_stateを設定すると、毎回同じ結果が得られる(再現性のため)
rf_clf = RandomForestClassifier(n_estimators=100, random_state=42)

# 訓練データでモデルを学習させる
rf_clf.fit(X_train, y_train)
print("\nモデルの学習が完了しました!")

# 3. 予測と評価
# テストデータを使って予測を行う
y_pred = rf_clf.predict(X_test)

# 精度 (Accuracy) を計算して表示
accuracy = accuracy_score(y_test, y_pred)
print(f'\nテストデータでの精度 (Accuracy): {accuracy:.4f}')

# 特徴量の重要度を表示 (どの特徴量が予測に寄与したか)
importances = rf_clf.feature_importances_
feature_names = iris.feature_names

print("\n特徴量の重要度:")
for name, importance in zip(feature_names, importances):
    print(f'  {name}: {importance:.4f}')
      

このコードを実行すると、ランダムフォレストモデルが学習され、テストデータに対する予測精度と、各特徴量が予測にどれだけ貢献したか(特徴量重要度)が出力されます。ランダムフォレストは、このように比較的少ないコードで実装でき、高い性能が期待できる便利な手法です。

まとめ 💡

今回は、アンサンブル学習の代表的な手法であるバギングとランダムフォレストについて学びました。

  • バギングは、ブートストラップサンプリングでデータセットを複数作り、それぞれで学習したモデルの結果を集約する手法で、主にモデルのバリアンスを低減します。
  • ランダムフォレストは、バギングに加えて、ノード分割時に特徴量をランダムに選択することで、モデル間の相関をさらに下げ、より高い汎化性能を目指す手法です。

ランダムフォレストは、実装が容易でありながら高い精度を出すことが多く、特徴量の重要度も評価できるため、データ分析の現場で広く使われています。ハイパーパラメータの調整によってさらに性能を向上させることも可能です。

次のステップでは、他のアンサンブル手法(ブースティングなど)や、作成したモデルを評価するための様々な指標について学んでいきましょう!💪

コメント

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