ななぶろ

-お役立ち情報を気楽に紹介するブログ-

初心者から中級者の機械学習プログラム例:決定木

www.amazon.co.jp

初心者から中級者の機械学習プログラム例:決定木

機械学習は、データからパターンを学習し、予測や意思決定を行うための強力なツールです。その中でも、比較的理解しやすいアルゴリズムの一つが「決定木」です。この記事では、初心者から中級者の方に向けて、決定木の基本的な概念から具体的なPythonコードを用いたプログラム例までを解説します。

1. 決定木とは?

決定木は、人間の意思決定プロセスを模倣した機械学習アルゴリズムです。例えば、「傘を持っていくべきか」という質問に答える際に、以下のような思考過程を経るかもしれません。

  • 空模様を確認する
  • 雨が降っているかどうか判断する
  • 雨が降っていれば傘を持っていく
  • 雨が降っていなければ傘を持っていかない

この思考過程を木構造で表現すると、決定木となります。

決定木の構成要素:

  • ノード (Node): 質問や条件を表します。例えば、「雨が降っているか?」など。
  • 枝 (Branch): ノードの結果(Yes/No, True/Falseなど)に基づいて次のノードへ進む経路を示します。
  • 葉 (Leaf): 最終的な予測結果を表します。例えば、「傘を持っていく」または「傘を持っていかない」。

決定木は、データセット内の特徴量(説明変数)を用いて、データを段階的に分割し、最終的に各葉ノードに分類や回帰の値を割り当てます。

2. 決定木の仕組み:情報エントロピーとジニ不純度

決定木がどのようにデータを分割するかを理解するには、「情報エントロピー」と「ジニ不純度」という概念を知っておく必要があります。これらは、データの不均一性(ランダム性)を表す指標です。

2.1 情報エントロピー (Information Entropy)

情報エントロピーは、データセット内のクラスの分布に基づいて計算されます。エントロピーが高いほど、データセットが不均一で、予測が難しいことを意味します。

情報エントロピーの計算式:

Entropy = - Σ p(i) * log2(p(i))

ここで、p(i)はクラス i のデータの割合です。

例:

あるデータセットに、猫が60%、犬が40%いる場合、エントロピーは以下のようになります。

Entropy = - (0.6 * log2(0.6) + 0.4 * log2(0.4)) ≈ 0.971

一方、猫が90%、犬が10%いる場合、エントロピーは以下のようになります。

Entropy = - (0.9 * log2(0.9) + 0.1 * log2(0.1)) ≈ 0.469

この例からわかるように、クラスの分布が均一になるほど(猫と犬の割合が50%になるほど)、エントロピーは高くなります。

2.2 ジニ不純度 (Gini Impurity)

ジニ不純度は、情報エントロピーと同様に、データセット内のクラスの分布に基づいて計算されます。ただし、ジニ不純度は、情報エントロピーよりも計算が簡単で、より実用的な場面で使用されることが多いです。

ジニ不純度の計算式:

Gini = 1 - Σ p(i)^2

ここで、p(i)はクラス i のデータの割合です。

例:

猫が60%、犬が40%いる場合、ジニ不純度は以下のようになります。

Gini = 1 - (0.6^2 + 0.4^2) = 1 - (0.36 + 0.16) = 0.5

一方、猫が90%、犬が10%いる場合、ジニ不純度は以下のようになります。

Gini = 1 - (0.9^2 + 0.1^2) = 1 - (0.81 + 0.01) = 0.18

この例からわかるように、クラスの分布が均一になるほど(猫と犬の割合が50%になるほど)、ジニ不純度は高くなります。

決定木の構築における情報エントロピーとジニ不純度:

決定木は、これらの指標を用いて、データを最も効果的に分割する特徴量と分割点を決定します。一般的には、あるノードを分割した後の情報エントロピーまたはジニ不純度が最小になるように分割を行います。

3. 決定木のメリット・デメリット

メリット:

  • 解釈性が高い: 決定木の構造は視覚的に理解しやすく、予測の根拠を説明しやすいです。
  • 前処理が不要: 数値データとカテゴリカルデータをそのまま扱えます。
  • 非線形な関係に対応可能: 線形モデルでは表現できない複雑な関係も捉えることができます。
  • 過学習を防ぐための手法が豊富: 剪定(Pruning)やアンサンブル学習(Random Forest, Gradient Boostingなど)を用いることで、過学習を抑制できます。

デメリット:

  • 過学習しやすい: 特に深い決定木は、訓練データに適合しすぎて、未知のデータに対する予測精度が低下する可能性があります。
  • 特徴量の順序に依存する: 特徴量の重要度や分割点の選択が、特徴量の順序によって影響を受けることがあります。
  • 高次元データには不向き: 特徴量が多い場合、決定木は複雑になりすぎて解釈性が失われる可能性があります。

4. Pythonによる決定木のプログラム例

ここでは、Pythonのscikit-learnライブラリを用いて、決定木のプログラム例を紹介します。

from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import pandas as pd

# 1. データセットの準備 (Irisデータセットを使用)
iris = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning/data/iris/iris.data', header=None, names=['sepal length', 'sepal width', 'petal length', 'petal width', 'species'])

# 2. データセットを訓練データとテストデータに分割
X = iris[['sepal length', 'sepal width', 'petal length', 'petal width']]  # 特徴量
y = iris['species']  # 目的変数
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# 3. 決定木モデルの作成と学習
model = DecisionTreeClassifier()  # 決定木モデルのインスタンス化
model.fit(X_train, y_train)  # モデルの学習

# 4. テストデータに対する予測
y_pred = model.predict(X_test)  # テストデータに対する予測

# 5. モデルの評価
accuracy = accuracy_score(y_test, y_pred)  # 正確度の計算
print("Accuracy:", accuracy)

# 6. 決定木の可視化 (オプション)
from sklearn.tree import export_graphviz
import graphviz

dot_data = export_graphviz(model, out_file='iris_decision_tree.dot', feature_names=['sepal length', 'sepal width', 'petal length', 'petal width'], class_names=['setosa', 'versicolor', 'virginica'], filled=True, rounded=True)
graph = graphviz.Source(dot_data)
graph.render("iris_decision_tree") # iris_decision_tree.pdf が生成される

# 7. 特定のデータに対する予測 (オプション)
new_data = pd.DataFrame([[5.1, 3.5, 1.4, 0.2]])  # 新しいデータの例
prediction = model.predict(new_data)[0]
print("Prediction for new data:", prediction)

コードの説明:

  1. データセットの準備: Irisデータセットをpandas DataFrameとして読み込みます。Irisデータセットは、アヤメの花の種類(setosa, versicolor, virginica)を、萼片の長さ、幅、花弁の長さ、幅という特徴量から予測する問題です。
  2. データセットの分割: 訓練データとテストデータに分割します。一般的に、データセット全体の70%~80%を訓練データとして使用し、残りをテストデータとして使用します。train_test_split関数は、データをランダムに分割してくれます。
  3. 決定木モデルの作成と学習: DecisionTreeClassifier()で決定木モデルを作成し、fit()メソッドを用いて訓練データから学習させます。
  4. テストデータに対する予測: 学習済みのモデルを用いて、テストデータに対する予測を行います。predict()メソッドは、各データのクラスを予測します。
  5. モデルの評価: accuracy_score()関数を用いて、予測精度を計算します。
  6. 決定木の可視化 (オプション): export_graphviz()関数とgraphvizライブラリを用いて、決定木をグラフとして可視化します。これにより、決定木の構造や各ノードの条件を視覚的に確認できます。
  7. 特定のデータに対する予測 (オプション): 新しいデータに対して、モデルがどのような予測を行うかを試すことができます。

5. 決定木の改良:剪定とアンサンブル学習

決定木は過学習しやすいという欠点があります。これを改善するために、以下の手法を用いることがあります。

5.1 剪定 (Pruning)

剪定とは、決定木を簡素化する処理です。具体的には、葉ノードの深さを制限したり、ある程度の不純度以上のノードを削除したりします。剪定を行うことで、訓練データに対する適合度は低下しますが、未知のデータに対する予測精度は向上する可能性があります。

scikit-learnでは、DecisionTreeClassifierクラスのmax_depthパラメータを用いて、決定木の深さを制限することができます。また、min_samples_leafパラメータを用いて、葉ノードに含まれる最小サンプル数を指定することもできます。

5.2 アンサンブル学習 (Ensemble Learning)

アンサンブル学習とは、複数のモデルを組み合わせて、より高性能なモデルを作成する手法です。決定木を用いたアンサンブル学習として、Random ForestやGradient Boostingなどがあります。

  • Random Forest: 多数の決定木をランダムに生成し、それぞれの予測結果を平均化することで、最終的な予測を行います。
  • Gradient Boosting: 弱学習器(浅い決定木)を順番に学習させ、前の学習器の誤りを修正するように次の学習器を学習させることで、より高性能なモデルを作成します。

これらの手法は、単一の決定木よりも過学習しにくく、高い予測精度を実現することができます。

まとめ

この記事では、初心者から中級者の方に向けて、決定木の基本的な概念から具体的なPythonコードを用いたプログラム例までを解説しました。決定木は、解釈性が高く、前処理が不要というメリットがありますが、過学習しやすいという欠点もあります。剪定やアンサンブル学習などの手法を用いることで、この欠点を克服し、より高性能なモデルを作成することができます。

機械学習の学習を進める上で、決定木は理解しておくべき重要なアルゴリズムの一つです。この記事で紹介した内容を参考に、ぜひ実際にコードを書いて、決定木の仕組みを体験してみてください。