はじめに
今回は、機械学習の基礎でありながら、そのシンプルさと解釈のしやすさから現場でも広く活用されている決定木について、その基本的な概要をまとめていこうと思います。
決定木とは
決定木は、データを木構造で表現し、一連のルールに基づいて予測や分類を行うアルゴリズムです。まるでフローチャートのように、データの特徴量(特徴となる変数)に基づいてYes/Noで分岐を繰り返し、最終的に予測結果や分類結果にたどり着きます。
例えば、ある顧客が製品を購入するかどうかを予測する場合、決定木は以下のような分岐を辿るかもしれません。
年齢は30歳以上ですか?
├── はい
│ └── 過去に購入履歴がありますか?
│ ├── はい -> 購入する可能性が高い
│ └── いいえ -> 他のキャンペーンを検討
└── いいえ
└── 学生ですか?
├── はい -> 学生向けプランを提案
└── いいえ -> 通常プランを提案
このように、決定木は直感的で理解しやすいルールを自動的に生成してくれるのが大きな特徴です。
決定木の仕組み
決定木の学習プロセスは、与えられたデータセットを、ある評価指標に基づいて最も良く分割できる特徴量と閾値を見つけ、再帰的に分割していくことで構築されます。
・ノード(Node): 木構造における各分岐点や終端点を指します。
・根ノード(Root Node): 最初の分割を行うノードです。
・内部ノード(Internal Node): 分割を行うノードです。
・葉ノード(Leaf Node): 最終的な予測結果や分類結果を表すノードです。これ以上分割されません。
・枝(Branch): ノード間の繋がりを表し、特徴量の値に応じた分岐を表します。
分割の際に用いられる評価指標は、タスクの種類によって異なります。
分類タスク
ジニ不純度 (Gini Impurity) や エントロピー (Entropy)、情報利得 (Information Gain) などが用いられます。これらの指標は、分割後のノードにおけるクラスの偏りを測り、より均一なクラスに分割されるように特徴量と閾値を選択します。
回帰タスク
平均二乗誤差 (Mean Squared Error) や 平均絶対誤差 (Mean Absolute Error) などが用いられます。分割後のノードにおける予測値のばらつきを小さくするように分割を行います。
決定木のメリット
・解釈性の高さ: 生成された木構造とルールが非常に分かりやすく、なぜその予測や分類結果が得られたのかを容易に理解できます。
・前処理の容易さ: 数値データだけでなく、カテゴリカルデータもそのまま扱うことができます。また、特徴量のスケーリングなどの前処理の影響を受けにくいという利点もあります。
・非線形な関係性の学習: 線形モデルでは捉えにくい、複雑な非線形な関係性を学習することができます。
・特徴量の重要度の評価: どの特徴量が予測や分類に大きく影響しているかを評価することができます。
決定木のデメリット
・過学習 (Overfitting): 木が深くなりすぎると、訓練データに対して過剰に適合してしまい、未知のデータに対する汎化性能が低下する可能性があります。
・データのわずかな変化に弱い: 訓練データのわずかな変化によって、生成される木の構造が大きく変わってしまうことがあります。
・最適な木の構造を見つけるのが難しい: 全ての可能な木の構造を探索することは計算コストが高いため、貪欲法的に最適な構造を探索しますが、必ずしも全体最適解が得られるとは限りません。
決定木の課題と対策
上記のような課題に対して、以下のような対策が取られます。
・剪定 (Pruning): 木の深さや葉ノードのサンプル数などに制約を設け、過学習を防ぎます。
・事前剪定 (Pre-pruning): 木の成長を途中で停止させる方法です。
・事後剪定 (Post-pruning): 完全に成長させた木を、汎化性能が向上するように枝刈りする方法です。
・アンサンブル学習: 複数の決定木を組み合わせて、より強力な予測モデルを構築します。代表的な手法として、ランダムフォレスト (Random Forest) や 勾配ブースティング決定木 (Gradient Boosting Decision Tree) などがあります。
プログラム例
実際にscikit-learnのサンプルデータを使って、決定木でアヤメデータの分類を行ってみます。
グラフの表示にはpydotplus、graghvizを使用しています。
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from pydotplus import graph_from_dot_data
from sklearn.tree import export_graphviz
# サンプルデータをロード
sample = load_iris()
x,y = sample.data, sample.target
# データ分割
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=1)
# 学習
tree = DecisionTreeClassifier(max_depth = 3, random_state=1)
tree.fit(x_train, y_train)
# 予測
predict = tree.predict(x_test)
print(predict)
# テストスコア表示
y_test_score = tree.score(x_test,y_test)
print("Score: ", y_test_score)
#pydotplus・graghvizで可視化
dot_data = export_graphviz(tree, filled=True, rounded = False, class_names=sample.target_names, feature_names=sample.feature_names, out_file=None)
graph = graph_from_dot_data(dot_data)
graph.progs = {'dot': u"C:\\Program Files\\Graphviz\\bin\\dot.exe"}
graph.write_png("Iris_tree.png")
結果
pridict: [0 1 1 0 2 1 2 0 0 2 1 0 2 1 1 0 1 1 0 0 1 1 2 0 2 1 0 0 1 2 1 2 1 2 2 0 1
0 1 2 2 0 1 2 1]
Score: 0.9555555555555556
classがアヤメの種類、その分類の条件が各ノードの1行目に記載されています。
giniはジニ不純度を表しています。
まとめ
今回は、決定木アルゴリズムの基本的な仕組みやメリット・デメリットについてまとめました。決定木は、そのシンプルさと解釈性の高さから、機械学習の入門としてだけでなく、様々な場面で実用的に使用されています。一方で、過学習などの課題も存在するため、適切なパラメータ調整やアンサンブル学習との組み合わせが重要になります。最後までお読みいただきありがとうございました。