第19回「scikit-learnの使い方(5)決定木(Decision Tree)」

こんにちは、小澤です。

前回は、SVM(サポートベクターマシン)を用いた分類について解説しました。今回は、決定木(Decision Tree)を使用して、データを段階的に分割しながら分類を行う方法を説明します。

なお、今回の内容は、教科書『Pythonによる新しいデータ分析の教科書(第2版)』の4.4.2章「分類」の決定木(236〜241ページ)の箇所です。

1. 決定木(Decision Tree)とは?

決定木(Decision Tree)は、データを「はい / いいえ」の質問を繰り返しながら、樹木のような階層構造で分割していくことで、分類や回帰を行う機械学習アルゴリズムです。

2. 決定木のイメージ

決定木は、連続する条件分岐によってデータを分類します。

たとえば、以下のようにデータを分類していきます。

  1. 「花びらの長さは 2.5cm より長いですか?」 → はい / いいえ
  2. 「はい」 の場合 → 次の質問へ
  3. 「いいえ」 の場合 → Iris-setosa と予測
  4. 次の質問:「花びらの幅は 1.5cm より広いですか?」 → はい / いいえ

このように、一連の質問を繰り返して、最終的な分類結果に到達します。これが「決定木」の基本的な考え方です。

3. 決定木の構造

  1. ルートノード (Root Node)
     最初の質問をするノードです。データ全体を対象に、最も情報を分ける特徴量で分割します。

  2. 内部ノード (Internal Node)
     中間の質問ノードです。条件に基づいてデータをさらに分割します。

  3. 葉ノード (Leaf Node)
     最終的な分類結果が表示されるノードです。ここに到達したデータは、特定のクラスラベル(例:Iris-setosa)を持ちます。

4. scikit-learnによる決定木の実装

scikit-learn には、決定木を簡単に使えるクラス DecisionTreeClassifier が用意されています。

以下は、Irisデータセットを使用して、決定木モデルを構築・評価する例です。

4.1 データの準備

Irisデータセットを読み込み、学習データ(80%)とテストデータ(20%)に分割します。

from sklearn import datasets
from sklearn.model_selection import train_test_split

# データセットのロード
iris = datasets.load_iris()
X = iris.data  # 特徴量
y = iris.target  # ラベル

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

コードの説明

  • datasets.load_iris()
     scikit-learn に組み込まれているIrisデータセットをロードしています。
     X には 特徴量(花びらやがく片の長さ・幅)を、y にはラベル(花の種類)を格納します。

  • train_test_split()
     データを学習用(80%)とテスト用(20%)に分けます。
     stratify=y を指定することで、クラスの比率を保ったまま分割しています。
     random_state=42 を設定することで、再現性のある分割が可能になります。

なぜこの設定にするのか?

  • test_size=0.2
     データの20%をテスト用にすることで、モデルの性能を未知のデータで評価できます。テストデータが少なすぎると性能の評価が不安定になり、多すぎると学習に使えるデータが減りモデルの精度が落ちるため、20%前後がバランスの良い値とされています。

  • stratify=y
     クラスの比率を保ったままデータを分割することで、偏りのない評価が可能になります。特に、クラスの割合が均等でない場合に、モデルの性能を正確に評価できます。

  • random_state=42
     データの分割が毎回ランダムに行われると、結果が異なってしまうため、再現性を確保するために設定します。同じ乱数シードを使うことで、常に同じ分割結果を得ることができます。

4.2 決定木モデルの作成と学習

from sklearn.tree import DecisionTreeClassifier

# 決定木モデルの作成
model = DecisionTreeClassifier(criterion=’gini’, max_depth=3, random_state=42)
model.fit(X_train, y_train)

コードの説明

  • DecisionTreeClassifier
     scikit-learn の 決定木モデルを作成するクラスです。
     criterion=’gini’ → ジニ不純度を基準に分割(デフォルト)
     max_depth=3 → 決定木の深さを 3 に制限し、過学習を防止。
     random_state=42 を設定して、分割の再現性を確保。

  • fit()
     学習用データ(X_train と y_train)を使って、決定木モデルの訓練を行います。この段階で、データのパターンを学習し、条件分岐のルールを決定します。

なぜこの設定にするのか?

  • criterion=’gini’
     ジニ不純度を基準にすることで、純度の高いノードを作成できます。
     entropy を与えてエントロピーを基準にすることも可能ですが、計算量が多くなるため、gini の方が高速に動作します。

  • max_depth=3
     決定木が深くなりすぎると過学習のリスクがあるため、適度な深さに制限します。一般的には、3〜5程度がバランスの良い深さとされています。

  • random_state=42
     決定木の分岐はランダム性を含むため、同じモデルを再現するために設定します。こうすると、実験結果の一貫性を保つことができます。

4.3 予測と評価

決定木モデルを作成・学習したら、テストデータを使って予測を行い、その結果を評価します。評価指標には、混同行列(Confusion Matrix)や分類レポート(Classification Report)を用います。

from sklearn.metrics import classification_report, confusion_matrix

# テストデータで予測
y_pred = model.predict(X_test)

# 結果の評価
print(“【混同行列】”)
print(confusion_matrix(y_test, y_pred))
print(“\\n【分類レポート】”)
print(classification_report(y_test, y_pred, target_names=iris.target_names))

コードの説明

  • predict()
     テスト用データ(X_test)を使って、学習済みモデルによる分類の予測を行います。予測結果は y_pred に格納されます。y_pred には、各サンプルに対して予測されたクラスラベルが含まれています。
     ここでは、predict(X_test)と、テストデータを使って予測することで、未知のデータに対するモデルの性能を確認できます。学習に使用したデータで評価すると、過学習の影響を受けるため、別のデータ(テストデータ)を用いることで汎化性能を評価します。

  • confusion_matrix()
     実際のラベル(y_test)と予測ラベル(y_pred)を比較し、混同行列を表示します。混同行列には、クラスごとの正解数と誤分類の数が表示されます。
     クラスごとの正解数と誤分類の数を確認することで、どのクラスで誤分類が多いかを分析できます。特に、クラス間で不均衡がある場合に有効です。

  • classification_report()
     精度(Precision)、再現率(Recall)、F1スコアを出力します。target_names を指定して、Irisデータセットの クラス名(Iris-setosa, Iris-versicolor, Iris-virginica)を表示しています。
     精度(Precision)、再現率(Recall)、F1スコアを確認することで、分類モデルの性能を総合的に評価できます。F1スコアは、精度と再現率のバランスを表すため、不均衡データの評価に適しています。

4.4 決定木の可視化

決定木は、樹木のような階層構造を持っているため、可視化することで条件分岐のルールが直感的に理解できます。ここでは、scikit-learn の plot_tree()を使用して、決定木をグラフとして表示します。

from sklearn import tree
import matplotlib.pyplot as plt

# 決定木の可視化
plt.figure(figsize=(15, 10))
tree.plot_tree(model, feature_names=iris.feature_names, class_names=iris.target_names, filled=True)
plt.title(“Decision Tree for Iris Classification”)
plt.show()

コードの説明

  • plt.figure(figsize=(15, 10))
     グラフのサイズを設定します。
     figsize=(15, 10) で、横15インチ、縦10インチのサイズに設定しています。

  • plot_tree()
     決定木の構造を可視化します。
     feature_names には特徴量の名前を、class_names にはクラスラベルを表示しています。filled=True にすることで、クラスごとにノードに色がつき、どのクラスに分類されたかが視覚的にわかりやすくなります。

  • plt.title()
     グラフのタイトルを設定します。今回は “Decision Tree for Iris Classification” としています。

  • plt.show()
     グラフを表示します。

4.5 実行結果の解説

混同行列の出力

  • Iris-setosa はすべて正しく分類されています。
  • Iris-versicolor は 1 件、Iris-virginica に誤分類されています。
  • Iris-virginica はすべて正しく分類されています。

分類レポートの出力

  • Iris-setosa
     Precision(精度) = 1.00:予測がすべて正解
     Recall(再現率) = 1.00:実際の Iris-setosa をすべて正しく予測
     F1-score = 1.00:完璧なバランス

  • Iris-versicolor
     Precision(精度) = 1.00:Iris-versicolor と予測したものはすべて正解
     Recall(再現率) = 0.90:実際の Iris-versicolor の 10 件中 9 件を正しく予測
     F1-score = 0.95:高いバランスを維持

  • Iris-virginica
     Precision(精度) = 0.91:予測した Iris-virginica のうち、91% が正解
     Recall(再現率) = 1.00:実際の Iris-virginica をすべて正しく予測
     F1-score = 0.95:バランス良好

決定木の可視化

全体の評価

  • Accuracy(正答率) = 0.97 (97%)
     全体の予測のうち、97% が正解 しており、非常に高い精度を持つモデルです。
  • Macro avg と Weighted avg がともに 0.97
     クラス間のバランスが良いことを示しています。特定のクラスに偏った予測がない、偏りのないモデルです。

5. まとめ

決定木は、直感的で解釈がしやすく、可視化が容易なモデルです。scikit-learn の DecisionTreeClassifier を使用することで、シンプルなコードで実装できるという利点があります。しかし、過学習しやすいというリスクもあります。

過学習を防ぐためには、いくつかの工夫が必要です。まず、木の深さを制限する(max_depth)ことで、モデルが複雑になりすぎるのを防ぎます。さらに、ノードの最小サンプル数を設定する(min_samples_split, min_samples_leaf)ことで、過剰に細かい分割を抑えることができます。これにより、ノイズに過剰に適応することを防ぎ、モデルの汎化性能を向上させることが可能です。

また、特徴量の選択を工夫することも有効です。不要な特徴量やノイズを含むデータを取り除くことで、モデルの精度を保ちつつ、過学習のリスクを軽減できます。過学習のリスクを認識し、これらの工夫をすることで、決定木の性能を最大限に引き出せるでしょう。

次回は、回帰モデルと次元削減、特に「主成分分析(PCA)」について解説します。これらの手法では、データのパターンをより深く理解し、効果的に情報を圧縮することが可能になります。回帰モデルを用いた予測や次元削減を通じたデータの可視化など、応用範囲が広がります。次回もお楽しみに。

PAGE TOP