決定木とは?仕組み・長所短所・Pythonでの実装までわかりやすく解説

決定木とは?仕組み・長所短所・Pythonでの実装までわかりやすく解説

6分で読める テック
最終更新:

こんにちは、あまねです。今日は、機械学習の基本的なアルゴリズムの一つ「決定木(Decision Tree)」について勉強したことをまとめてみました。

決定木は機械学習の中でも直感的に理解しやすいアルゴリズムで、「なぜその判断になったのか」が見えるのが大きな特徴です。ブラックボックスになりがちな機械学習の中で、これは嬉しいポイントですよね。

決定木とは

決定木とは、木構造を用いてデータの分類や回帰を行うアルゴリズムです。

ざっくり言うと、「Yes/Noの質問を繰り返して、答えにたどり着く」仕組みです。20の質問ゲーム(「それは動物ですか?」「食べられますか?」と質問していって答えを当てるやつ)をイメージすると、まさにそれが決定木です。

用語を整理しておくと:

  • 木構造:根(ルート)から葉(リーフ)に向かって枝分かれしていくデータ構造
  • 分類:入力データがどのカテゴリに属するかを判定すること(例:この花はどの品種?)
  • 回帰:入力データから数値を予測すること(例:この家の価格は?)

決定木の仕組み:どうやって分けるの?

具体的な例で考えてみましょう。「今日の昼ごはんに何を食べるか」を決定木で表すとこんな感じです:

[お腹はすごく空いている?]
    ├── Yes → [暑い?]
    │           ├── Yes → 冷やし中華
    │           └── No  → ラーメン
    └── No  → [時間に余裕がある?]
                ├── Yes → カフェでランチ
                └── No  → コンビニおにぎり

このように、各ノード(分岐点)で条件を評価して、データを振り分けていきます。最終的にたどり着いた葉(リーフ)が予測結果になります。

では、機械学習としての決定木はどうやって「どの条件で分けるか」を決めるのでしょうか?

分割の基準:不純度を減らす

決定木が学習するときの方針は、「分割後のノードの不純度をできるだけ小さくする」 ことです。

「不純度」というのは、ノードの中にどれだけ異なるクラスのデータが混ざっているかを表す指標です。例えば、あるノードの中身が「猫10匹」だけなら不純度は0(完全に純粋)。「猫5匹、犬5匹」なら不純度は最大。なるべく同じクラスのデータが集まるように分割するのが、良い分割というわけです。

不純度の計算方法には主に2つあります:

ジニ不純度(Gini Impurity)

ランダムに選んだデータを、そのノードのクラス分布に従ってランダムに分類したとき、間違える確率。scikit-learnのデフォルトはこれです。CARTアルゴリズムで使われます。

エントロピー(Entropy)

情報理論に基づく指標。ノード内のクラス分布の「乱雑さ」を測ります。C4.5やID3アルゴリズムで使われます。

どちらを使っても結果に大きな差が出ることは少ないですが、ジニ不純度のほうが計算が軽いので、こだわりがなければジニ不純度で良いと思います。

決定木の長所

  • 可読性が高い:なぜその判断になったか、木をたどれば理解できる。これは他のアルゴリズム(ニューラルネットワークなど)にはない大きな強み
  • 前処理が少なくて済む:特徴量のスケーリング(標準化・正規化)が不要
  • 外れ値に比較的強い:極端な値があっても、分割条件には大きく影響しにくい
  • 数値データもカテゴリデータも扱える
  • 非線形な関係も捉えられる

決定木の短所

  • 過学習しやすい:制限をかけないと、訓練データに完全にフィットしてしまい、汎化性能が下がる
  • 単体での精度は高くない:他のアルゴリズムと比べると、分類・回帰の精度は劣ることが多い
  • データの小さな変化に敏感:訓練データが少し変わるだけで、木の構造が大きく変わることがある
  • クラスの偏りに弱い:データの偏りがあると、多数派のクラスに引っ張られやすい

過学習への対策としては、木の深さを制限したり(max_depth)、葉のサンプル数の最小値を設定したり(min_samples_leaf)、枝刈り(pruning)を行ったりします。

Pythonでやってみる(scikit-learn)

実際にscikit-learnで決定木を使ってみましょう。有名なIrisデータセット(アヤメの品種分類)を使います。

from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

iris = load_iris()
X_train, X_test, y_train, y_test = train_test_split(
    iris.data, iris.target, test_size=0.3, random_state=42
)

clf = DecisionTreeClassifier(max_depth=3, random_state=42)
clf.fit(X_train, y_train)

y_pred = clf.predict(X_test)
print(f"正解率: {accuracy_score(y_test, y_pred):.2f}")

max_depth=3 で木の深さを制限しているのがポイント。これがないと過学習しやすくなります。

また、scikit-learnには木を可視化する機能もあります:

from sklearn.tree import export_text

print(export_text(clf, feature_names=iris.feature_names))

これを実行すると、「花びらの長さが2.45cm以下なら → setosa」のような分岐ルールがテキストで表示されます。どういうロジックで分類しているかが一目瞭然で、これが決定木の大きな魅力です。

決定木を使うべき場面・使わないべき場面

向いている場面

  • 判断の理由を説明する必要があるとき(医療診断、融資審査など)
  • データの探索・分析のファーストステップとして
  • 特徴量の重要度を把握したいとき

向いていない場面

  • 高い精度が必要なとき → ランダムフォレストやXGBoostなどのアンサンブル手法を検討
  • 大量の特徴量があるとき → 次元削減を先に行うか、他のアルゴリズムを使う
  • データ量が非常に少ないとき → 木の構造が不安定になりがち

ちなみに、決定木の弱点を補うために、決定木を大量に組み合わせたのが ランダムフォレスト勾配ブースティング(XGBoost, LightGBMなど) です。実務ではこれらのアンサンブル手法のほうがよく使われますが、その基盤にあるのは決定木なので、決定木の仕組みを理解しておくことは大事です。

まとめ

決定木は「判断の過程が見える」機械学習アルゴリズム。単体での精度は控えめですが、わかりやすさと解釈性は抜群です。機械学習を学ぶ最初のステップとしても、実務で「なぜこの判断になったのか」を説明する必要がある場面でも、頼りになるアルゴリズムだと思います。

質問・リクエストを送る

記事についての質問や、取り上げてほしいテーマがあればお気軽にどうぞ。いただいた質問はブログ記事として回答し、Q&Aページで公開することがあります。