決定木とは?仕組み・長所短所・Pythonでの実装までわかりやすく解説
こんにちは、あまねです。今日は、機械学習の基本的なアルゴリズムの一つ「決定木(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ページで公開することがあります。