目次
1. はじめに
こんにちは!ご覧いただきありがとうございます。
新卒1年目の吉田です。
データサイエンスに対する興味から、機械学習の基本的なアルゴリズムの一つ「決定木(Decision Tree)」について学び始めました。その直感的な理解と基本的な実装方法を共有することで、同じく学習を進める皆さんの助けになればと思います。
決定木は、その名の通り、木のような構造を持つアルゴリズムで、データの分類や回帰に広く使用されています。本記事では、決定木の基本概念を直感的に理解しやすいよう説明し、その後、Pythonを使った簡単な実装方法を紹介します。
2. 決定木とは
決定木の基本概念
決定木は、データを一連の質問(または条件)を通じて分類するアルゴリズムです。木の各ノードは質問を表し、枝は質問に対する答え(はい/いいえ)を表します。葉(リーフ)ノードは最終的なクラスラベルや予測値を表します。
例:フルーツの分類
フルーツを分類するための決定木の例を考えてみましょう。
質問1: フルーツの色は赤ですか?
- 「はい」の場合、次の質問へ進みます
- 「いいえ」の場合、そのフルーツは「バナナ」と判断されます
質問2: フルーツのサイズは小さいですか?
- 「はい」の場合、そのフルーツは「チェリー」と判断されます
- 「いいえ」の場合、そのフルーツは「リンゴ」と判断されます
このように、決定木は一連の質問を通じてデータを分類します。
決定木の構造
決定木の構造は以下の通りです:
- ルートノード: データセット全体を最初に受け取る最上位のノード
- 内部ノード: 分岐を表すノード。各ノードは属性(特徴量)に基づいて質問を持ちます
- 葉ノード: 最終的な決定または予測を表すノード
3. 決定木の構築方法
決定木を構築するためには、どの特徴量を基にデータを分割するかを決定する必要があります。ここでは、データの純度を高めるための分割方法を直感的に説明します。
データの純度と分割基準
決定木を構築する主な目標は、データセットを可能な限り「純粋な」サブセットに分割することです。純粋なサブセットとは、同じクラスラベルを持つデータが多く含まれているグループのことです。これを実現するために、エントロピーなどの分割基準を使用します。
エントロピーとは
エントロピーは、データの不純度を測る指標の一つです。エントロピーが低いほど、そのノード内のデータは純粋です。エントロピーを使って分割基準を決めることで、データセットをより純粋なサブセットに分割することができます。
分割の例
例えば、次のようなデータセットがあるとします。
色 | サイズ | フルーツ |
---|---|---|
赤 | 大 | リンゴ |
赤 | 小 | チェリー |
黄 | 大 | バナナ |
黄 | 小 | チェリー |
このデータセットを「色」と「サイズ」に基づいて分割する際に、どの特徴量を最初に使うかを決めるために、各特徴量の分割によるエントロピーの変化を計算します。直感的には、データを分割することで、同じフルーツが多く含まれるようにするのが目標です。
決定木の構築アルゴリズム
決定木の構築には、以下の手順を用います。
- 全データセットから開始: ルートノードを作成します
- 最良の分割を見つける: エントロピーなどの基準に基づいて、データを最も純粋なサブセットに分割する特徴量を選びます
- データを分割する: 選ばれた特徴量に基づいてデータを二分します
- 再帰的に繰り返す: 各サブセットで再び最良の分割を見つけ、分割を続けます。これを葉ノードに到達するまで繰り返します
このプロセスを通じて、決定木はデータを分類するためのルールを学習します。
4. Pythonでの決定木の実装
必要なライブラリのインストール
まずは、Pythonのライブラリをインストールします。
pip install scikit-learn pandas graphviz
サンプルデータの準備と決定木の構築
サンプルデータを用意し、決定木を構築します。以下のコードは、前処理、モデルのトレーニング、テストデータでの評価を行います。
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import confusion_matrix, accuracy_score
from sklearn.tree import export_graphviz
import graphviz
# サンプルデータ
data = {
'色': ['赤', '赤', '赤', '黄', '黄', '黄', '赤', '赤', '黄', '黄', '赤', '黄', '黄', '赤', '赤', '黄', '黄', '赤', '黄', '赤', '黄', '赤', '黄', '赤', '黄', '赤', '黄', '赤', '黄'],
'サイズ': ['大', '大', '小', '大', '小', '小', '小', '大', '小', '大', '大', '大', '小', '小', '大', '小', '大', '小', '大', '大', '小', '小', '大', '大', '小', '大', '大', '小', '大'],
'フルーツ': ['リンゴ', 'リンゴ', 'チェリー', 'バナナ', 'チェリー', 'バナナ', 'チェリー', 'リンゴ', 'バナナ', 'リンゴ', 'チェリー', 'バナナ', 'リンゴ', 'チェリー', 'バナナ', 'リンゴ', 'チェリー', 'リンゴ', 'バナナ', 'リンゴ', 'チェリー', 'バナナ', 'リンゴ', 'チェリー', 'バナナ', 'リンゴ', 'バナナ', 'チェリー', 'リンゴ']
}
dataset = pd.DataFrame(data)
print(dataset)
# 特徴量とラベルに分割
X = pd.get_dummies(dataset.iloc[:, :-1])
y = dataset.iloc[:, -1].values
# トレーニングデータとテストデータに分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
# 決定木モデルのトレーニング
classifier = DecisionTreeClassifier(criterion='entropy', random_state=0)
classifier.fit(X_train, y_train)
# テストデータで予測
y_pred = classifier.predict(X_test)
# 混同行列の作成
cm = confusion_matrix(y_test, y_pred)
print(cm)
# 精度の計算
accuracy = accuracy_score(y_test, y_pred)
print(f'Accuracy: {accuracy: .2f}')
モデルの可視化
決定木の構造を可視化することで、直感的に理解しやすくなります。
# 決定木の可視化
dot_data = export_graphviz(classifier, out_file=None, feature_names=X.columns, class_names=classifier.classes_, filled=True, rounded=True, special_characters=True)
graph = graphviz.Source(dot_data)
graph.render("decision_tree")
# グラフを表示
graph
以下のような決定木の図が生成されます。
5. 決定木の利点と欠点
利点
- 直感的で分かりやすい: 視覚的に理解しやすく、その構造からデータの分岐と決定プロセスが明確になります
- データの前処理が少ない: カテゴリーデータと数量データの両方に対応可能で、データの前処理が比較的少なくて済みます
- 高速な予測: モデルがシンプルなため、予測が高速です
欠点
- 過学習しやすい: データに過剰に適合してしまい、新しいデータに対する汎化性能が低下することがあります
- 小さなデータセットでは不安定: データのバリエーションが少ない場合、モデルが不安定になることがあります
- 計算量が多い: 特に大規模なデータセットでは、計算量が増加する可能性があります
6. まとめ
この記事では、決定木の基本的な概念とその直感的な理解方法、Pythonを用いた簡単な実装方法を解説しました。読者の皆さんからの貴重なフィードバックやご指摘をいただけると、非常に助かります!
最後までご覧いただき、ありがとうございました!