決定樹アルゴリズムの基礎から応用まで:R および Python 実装解説

樹木モデルの概要

監督学習の手法において、樹木ベースのアルゴリズムは最も効果的で頻繁に利用されるアプローチの一つです。これらの手法は、予測モデルに高い精度と安定性をもたらすだけでなく、結果の解釈性も優れています。線形モデルとは異なり、非線形な関係性を適切に表現できる点が大きな特徴です。分類問題および回帰問題の双方に対応可能であり、データサイエンスの現場では決策樹、ランダムフォレスト、勾配ブースティングなどが広く活用されています。

本稿では、初学者向けに樹木モデルの基礎から応用までを解説します。機械学習の事前知識は必須ではありませんが、R または Python の基本的な構文を知っていると理解が深まります。

1. 決定樹の仕組み

決定樹は、主に分類タスクに用いられる監督学習アルゴリズムです。カテゴリカル変数および連続変数の双方を入力・出力として扱えます。この手法では、入力変数の中で最も重要な分割基準を用いて、サンプル全体を均質なサブグループに再帰的に分割していきます。

決定樹の基本概念図

具体例

例えば、30 人の生徒を対象に、「性別」、「クラス」、「身長」という 3 つの変数があり、そのうち 15 人が课余にクリケットをしているとします。どの生徒がクリケットをするかを予測するモデルを構築する場合、決定樹はこれら 3 つの変数を評価し、最も均質なグループを作成できる変数を選択します。以下の図では、「性別」が他の変数よりも優れた分割基準となっていることが示されています。

性別による分割例

決定樹は、最も均質な集合を生み出す変数を特定し、そこを基準に分割を行います。この選択プロセスには、後述する様々なアルゴリズムが利用されます。

決定樹の分類

目的変数のタイプにより、決定樹は以下のように分類されます。

  • 分類樹 (Classification Tree):目的変数がカテゴリカルである場合。例:クリケットをするかどうか(YES/NO)。
  • 回帰樹 (Regression Tree):目的変数が連続値である場合。例:顧客の収入予測など。

主要な用語

  • ルートノード (Root Node):サンプル全体を表す最初のノード。
  • 分割 (Splitting):ノードを複数の子ノードに分けるプロセス。
  • 決定ノード (Decision Node):さらに分割される子ノードを持つノード。
  • 葉ノード (Leaf/Terminal Node):これ以上分割されない終端ノード。
  • 剪定 (Pruning):過学習を防ぐため、不要な子ノードを削除するプロセス。
  • ブランチ (Branch/Sub-tree):樹木構造の一部。
  • 親子関係 (Parent and Child Node):分割元のノードを親、分割先を子と呼ぶ。
決定樹の構造用語

利点と欠点

利点:

  • 解釈が容易:統計的な知識がなくても理解可能な出力を提供します。
  • データ探索に有用:重要な変数や変数間の関係を迅速に特定できます。
  • 前処理の負担が少ない:外れ値や欠損値に対して比較的頑健です。
  • データ型の制約なし:数値およびカテゴリカル変数を同時に扱えます。
  • 非パラメトリック:データの分布に関する仮定を置きません。

欠点:

  • 過学習 (Overfitting):制約を設けない場合、訓練データに適合しすぎる傾向があります。
  • 連続変数の扱い:連続値を離散化する際、情報損失が発生する可能性があります。

2. 回帰樹と分類樹の違い

決定樹は通常、根を上部、葉を下部にして描画されます。

決定樹の描画例

両者の主な違いは以下の通りです。

  1. 回帰樹は連続値の目的変数に、分類樹はカテゴリカルな目的変数に使用されます。
  2. 回帰樹の葉ノードの予測値は、その領域に属する観測値の平均値となります。
  3. 分類樹の葉ノードの予測値は、その領域における最頻値(多数決)となります。
  4. どちらも予測変数空間を非重複の領域に分割します。
  5. 「再帰的二分分割」と呼ばれる貪欲なトップダウンアプローチを採用しています。
  6. ユーザー定義の停止基準(例:ノード内の最小サンプル数)に達するまで分割を続けます。
  7. 完全成長した樹木は過学習のリスクがあるため、「剪定」によって対策を行います。

3. 分割基準の決定アルゴリズム

樹木の精度は分割戦略に大きく依存します。目的変数のタイプに応じて、以下のアルゴリズムが使い分けられます。

ジニ不純度 (Gini Index)

集団からランダムに 2 つの要素を選んだ際、それらが異なるクラスに属する確率を示します。CART アルゴリズムで採用されており、二値分割に使用されます。

  • 計算手順:子ノードのジニ値を計算し、加重平均をとります。
  • 値が高いほど均质性が高いことを示します(注:文脈により不純度の定義が異なる場合があり、ここでは不純度が低い=均質が高いという文脈で扱われることが多いですが、元のテキストの記述に従い、分割後の不純度減少を重視します)。

カイ二乗 (Chi-Square)

親ノードと子ノード間の統計的有意性を検定します。CHAID アルゴリズムで利用されます。

  • 観測頻度と期待頻度の乖離を測定します。
  • 値が高いほど、分割の統計的有意性が高いことを示します。
  • 複数分割に対応可能です。

情報利得 (Information Gain)

エントロピーに基づいて分割の良さを評価します。エントロピーはシステムの不確実性を表し、値が 0 の場合完全に均質です。

計算式:Entropy = -p*log2(p) - q*log2(q)

情報利得は、分割前のエントロピーから分割後の加重エントロピーを引いた値です。この値が最大になる分割を選択します。

分散減少 (Reduction in Variance)

連続値の目的変数(回帰問題)で使用されます。分割後の分散が最小になる基準を選択します。

計算式:s^2 = Σ(xi - x̄)^2 / n

4. 過学習への対策とパラメータ調整

決定樹は制限を設けない場合、訓練データに対して 100% の精度を出してしまうほど過学習しやすいモデルです。対策として「制約の設定」と「剪定」の 2 種類があります。

決定樹のパラメータ構造

制約パラメータ

  • 最小サンプル数 (min_samples_split):分割に必要な最小サンプル数。大きい値にすると過学習を防げますが、未学習のリスクがあります。
  • 葉ノードの最小サンプル数 (min_samples_leaf):葉ノードが保持すべき最小サンプル数。
  • 最大深度 (max_depth):樹木の深さの制限。深いほど複雑な関係性を学習できます。
  • 最大葉ノード数 (max_leaf_nodes):葉ノードの総数制限。
  • 分割考慮特徴量 (max_features):分割時に検討する特徴量の数。ランダムに選択されます。

剪定 (Pruning)

制約設定が貪欲なアプローチであるのに対し、剪定は樹木を一度深く成長させた後、精度に貢献しないブランチをボトムアップで削除します。これにより、局所最適ではなく大域的な最適解に近づけることが可能です。

剪定の概念図

5. 線形モデルとの比較

線形回帰やロジスティック回帰ではなく樹木モデルを選ぶべきケースは以下の通りです。

  • 変数間に強い非線形関係や複雑な相互作用がある場合。
  • モデルの解釈性を重視し、非技術者にも説明必要がある場合。
  • 線形仮定が成り立たないデータ構造である場合。

6. R と Python での実装(決定樹)

主要な言語における基本的な実装代码如下。

R 実装

library(rpart)
# 訓練データの準備
dataset <- cbind(features_train, target_train)
# モデルの構築
tree_model <- rpart(target_var ~ ., data = dataset, method = "class")
# 結果の確認
summary(tree_model)
# 予測の実行
predictions <- predict(tree_model, features_test)

Python 実装

from sklearn.tree import DecisionTreeClassifier
# 変数の定義
X = training_features
y = target_variable
# クラシファイアの初期化
clf = DecisionTreeClassifier(criterion='entropy', max_depth=10)
# 学習
clf.fit(X, y)
# スコアの確認
accuracy = clf.score(X, y)
# 予測
results = clf.predict(test_features)

7. アンサンブル手法の概要

アンサンブル学習は、複数のモデルを組み合わせることで予測精度と安定性を向上させる手法です。樹木モデルはバイアスと分散のトレードオフの影響を受けます。単純な小树は高バイアス・低分散であり、複雑な樹木は低バイアス・高分散となります。アンサンブルはこのバランスを最適化します。

モデル複雑度和エラーの関係

代表的な手法には、バギング (Bagging)、ブースティング (Boosting)、スタッキング (Stacking) があります。

8. バギング (Bagging)

バギングは、元のデータセットから復元抽出で生成した複数のサブサンプルに対してモデルを構築し、その結果を統合することで分散を低減します。

バギングの仕組み
  1. データセットの生成:ブートストラップサンプリングにより複数のデータセットを作成。
  2. 分類器の構築:各データセットに対して独立してモデルを学習。
  3. 結果の統合:分類問題は多数決、回帰問題は平均値により予測を確定。

9. ランダムフォレスト

ランダムフォレストはバギングの拡張であり、決定樹のアンサンブルです。分類・回帰双方に対応し、特徴量の重要度評価や欠損値処理にも優れています。

動作原理

  • N 個のサンプルから復元抽出を行い、訓練セットを生成。
  • M 個の特徴量の中から、ランダムに m 個選択して最適分割点进行探索。
  • 剪定を行わず、可能な限り樹木を成長させる。
  • 予測時には、分類は多数決、回帰は平均値を出力。
ランダムフォレストのデータフロー

利点

  • 高次元データおよび大規模データセットに強い。
  • 特徴量の重要度を出力できる。
  • 欠損値に対して頑健。
  • アウトオブバッグ (OOB) 誤差により、検証セットなしで性能評価が可能。
変数重要度

実装コード

Python:

from sklearn.ensemble import RandomForestClassifier
# モデル定義
rf_model = RandomForestClassifier(n_estimators=500, max_features='sqrt')
# 学習
rf_model.fit(X_train, y_train)
# 予測
output = rf_model.predict(X_test)

R:

library(randomForest)
data_set <- cbind(train_features, train_target)
# モデル fitting
rf_fit <- randomForest(target ~ ., data = data_set, ntree=500)
summary(rf_fit)
# 予測
pred_values <- predict(rf_fit, test_features)

10. ブースティング (Boosting)

ブースティングは、複数の弱学習器を直列に結合して強学習器を作成する手法です。前のモデルの誤りを次のモデルが重点的に学習することで、精度を向上させます。

仕組み

  1. 初期状態では、すべての観測値に均等な重みを割り当て。
  2. 誤分類された観測値の重みを増加させ、次のモデルで重点的に学習。
  3. このプロセスを繰り返し、最終的に重み付きの予測結果を統合。

11. GBM と XGBoost の比較

勾配ブースティング (GBM) と XGBoost は共に人気のあるブースティングアルゴリズムですが、XGBoost には以下のような追加の利点があります。

  • 正則化:過学習を防ぐための正則化項が含まれています。
  • 並列処理:特徴量の探索段階で並列計算が可能であり、高速です。
  • 柔軟性:カスタム目的関数や評価指標を定義できます。
  • 欠損値処理:アルゴリズム内部で欠損値の扱いを最適化します。
  • 剪定:負の利得をもたらす分割も一度行い、後から剪定する深さ優先アプローチを採用。
  • クロスバリデーション:学習プロセス内でクロスバリデーションを実行可能。

12. GBM の実装

GBM の主要パラメータには、学習率 (learning_rate)、樹木数 (n_estimators)、サブサンプル率 (subsample) などがあります。

R 実装 (caret パッケージ)

library(caret)
# 制御パラメータ設定
ctrl <- trainControl(method = "cv", number = 10)
# グリッド設定
grid_params <- expand.grid(interaction.depth = 3,
                           n.trees = 300,
                           shrinkage = 0.1,
                           n.minobsinnode = 5)
# モデル学習
gbm_model <- train(target ~ ., data = train_data,
                   method = "gbm",
                   trControl = ctrl,
                   tuneGrid = grid_params)
# 予測
prob_pred <- predict(gbm_model, test_data, type = "prob")

Python 実装

from sklearn.ensemble import GradientBoostingClassifier
# 設定
gbm_clf = GradientBoostingClassifier(n_estimators=200,
                                     learning_rate=0.05,
                                     max_depth=4,
                                     random_state=42)
# 学習
gbm_clf.fit(X_train, y_train)

13. XGBoost の実装

XGBoost は勾配ブースティングの高性能な実装であり、大規模データ処理に適しています。R および Python 双方で専用パッケージが提供されています。

Python では xgboost ライブラリを、R では xgboost パッケージを利用することで、高速な学習と高い予測精度を得ることができます。パラメータチューニングにおいては、正則化項 (lambda, alpha) や木のパラメータ (max_depth, min_child_weight) を調整することが重要です。

タグ: decision-tree random-forest xgboost gradient-boosting Scikit-learn

6月21日 23:13 投稿