「決定木」は、おそらく世界で最も利用されている機械学習アルゴリズムです。教師ありの学習データから、階層的に条件分岐のツリーを作り、判別モデルを作ることができます。

今回は決定木の活用例として、きのこ派とたけのこ派を予測する人工知能を作りました。プログラム言語は、Pythonとscikit-learnです。

過去記事:AIエンジニアが教えるゼロから機械学習の勉強法

決定木を利用するメリット

①作ったモデルを可視化できるため、人間が理解できる。
②データの標準化やダミー変数の作成が不要。
③カテゴリデータと数値データの両方を特徴量として設定することが可能。

つまり、データ加工が良く分からない初心者でも、分かりやすいモデルを作ってくれるということです。素晴らしいですね。さすが世界一位です。

決定木はエントロピーで分類モデルを作る

機械学習の目的は、分類能力の高いモデルを作ることです。決定木は、エントロピーという情報理論を用いて、データから分類モデルを作ります。

エントロピーという言葉は、聞いたことがあるかもしれません。乱雑さや不規則性の程度を表す指標です。イメージ的には、散らかっている部屋の中はエントロピーが高く、整頓された部屋はエントロピーが低いです。

ここで日本の代表的なチョコレートである、たけのこ派ときのこ派を分類するモデルを考えます。10人に聞いてみたところ、たけのこ派が6名、きのこ派が4名いました。

分類モデルのゴールは、たけのこ派ときのこ派を綺麗に分類するルールを見つけることです。

Aルール:たけのこ派6名グループ v.s きのこ派4名グループ →エントロピー0(最小)
Bルール:たけのこ派3名きのこ派2名グループ v.s たけのこ派3名きのこ派2名のグループ →エントロピー1(最大)


Aルールの方がきれいに分けられてますね。決定木は、エントロピーを最小化するルールをデータから自分で発見する学習モデルです。

枝刈りと過学習:モデルはシンプルの方が美しい

複雑なモデルは、過学習を起こしやすいです。過学習とは、モデルが学習データに過剰適合していることです。過剰適合の何が悪いかというと、ノイズデータも学習してしまうからです。ノイズまで学習すると、未知のデータを分類する能力(汎化能力と言います)が落ちてしまします。

物理学の世界では、シンプルな方程式が美しいと言われています。アインシュタインの相対性理論の方程式(E=mc^2)もシンプルです。同じく機械学習もシンプルな方程式(モデル)を作ることで、結果的に汎化能力が高いモデルを作ることが出来ます。

では、決定木ではどうやってモデルをシンプルにするか。それは枝刈りです。枝刈りとは、決定木の深さに制約を与えることです。この制約を与えないと、決定木はいくらでも深く枝を作ってしまい複雑になってしまいます。よって過学習のリスクが極めて高くなります。そのため、人間がパラメータとして設定し、深さに制約を与えることが大事です。

Pythonで決定木の学習と実装

今回の分析例では、身長と体重のデータを元にその人がたけのこ派かどうかを予測するモデルを作成します。身長と体重を説明変数に、たけのこ派の有無を目的変数として扱い、分類する決定木を作成します。

※青色の文字がPythonのコードです

①ライブラリ群のインポート

まずはNumPy、Pandas、scikit-learnのライブラリをインポートします。

import numpy as np
import pandas as pd
from sklearn import tree
from sklearn.metrics import accuracy_score
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
from sklearn.tree import export_graphviz

②身長、体重、たけのこ派の有無のデータを定義

身長、体重、たけのこ派の有無のデータを用意します(疑似データです)。takenoko列の0がきのこ派、1がたけのこ派です。

#データフレームの作成
df = pd.DataFrame({'height': [170, 181, 173, 159, 176, 185, 145,154, 156,170],
                   'weight': [60, 59, 61, 51, 62, 70, 50,56,60,50],
                   'takenoko': [1, 0, 0, 1, 0, 0, 1, 1, 0,1]})

#データを説明変数と目的変数に分割して格納
x = df.ix[:, ['height','weight']].values
y= df.ix[:, 'takenoko'].values

③scikit-learnのDecisionTreeClassifier(決定木)で学習

最大の深さを4とする決定木を定義して、fit関数で学習を行います。

#決定木の作成
clf = tree.DecisionTreeClassifier(max_depth=4)
clf = clf.fit(x, y)

④正解率でモデルの評価

決定木が予測したデータと実際のデータを比較して、正解率を測定します。

#予測データ作成
y_pre = clf.predict(x)

#正解率
print accuracy_score(y, y_pre) 

精度100%のモデルが出来ました。

⑤決定木の予測結果

NumPyのmeshgrid関数を活用してメッシュ状の座標を作成し、全てのメッシュに予測結果をプロットします。

# 教師データの取りうる範囲 +-1 を計算する
train_x_min = x[:, 0].min() - 1
train_y_min = x[:, 1].min() - 1
train_x_max = x[:, 0].max() + 1
train_y_max = x[:, 1].max() + 1

# 教師データの取りうる範囲でメッシュ状の座標を作る
xx, yy = np.meshgrid(
    np.arange(train_x_min, train_x_max, 0.5),
    np.arange(train_y_min, train_y_max, 0.5),
)

# メッシュの座標を学習したモデルで判定させる
Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
# 各点の判定結果をグラフに描画する
plt.pcolormesh(xx, yy, Z.reshape(xx.shape), cmap=ListedColormap(['#FFAAAA', '#AAAAFF']))
plt.show()
77
横軸が身長で、縦軸が体重です。青色がたけのこ派で赤色がきのこ派と予測された領域です。上のグラフから、たけのこ派がやせていて、きのこ派が太っていること、また身長が高すぎたり低すぎる人は、きのこ派になっていることが分かります。

参考記事:これだけは知っておけ!PythonでAI開発の基礎まとめ

⑥決定木の可視化

export_graphviz関数で、決定木のdotファイル(決定木の分岐ロジックが書いてある)を作成できます。作成したファイルをwindows用のGveditツールで開くと、以下のような決定木を可視化するグラフが作成できます。

#決定木ツリーの可視化
export_graphviz(clf, out_file="tree1.dot", filled=True,rounded=True)
9999

先ほど決定木は、エントロピーを少なくするようなルールで分岐を作るとお話ししました。では、上記の決定木で最もエントロピーを最小化しているルールはどれでしょうか。それは、一番上の「体重が57.5kg以下ならきのこ派」というルールです。決定木は、上から順に重要なルールであると言えます。だから枝刈りして深さを減らしても割と大丈夫なんですね。

いずれにせよ、ルールを可視化できるところが決定木の素晴らしいところです。ディープラーニングでは、こうはいきません。機械学習エンジニアだろうがデータサイエンティストだろうがまず最初に試すべきアルゴリズムと言えます。

決定木の問題点は過学習しやすいこと

決定木は素晴らしいアルゴリズムなのですが、データに過剰適合しやすいという問題点があります。いわゆる過学習です。ノイズデータにも学習するので、未知のデータを予測をする汎化性能が低くなる傾向があります。

ならば、決定木をたくさん作ってその結果を平均化すればいいのではと頭の良い方が気付きました。これがランダムフォレストです。機械学習を実務で利用されるならば、ぜひとも身に付けたいアルゴリズムの一つです。

参考記事:ランダムフォレストで特徴量の重要度を評価する

本日のまとめ

決定木は将棋でいうと棒銀みたいなものです。簡単で強力なモデル作成が可能です。決定木分析を数式までしっかり学びたい方は、下記の本がおすすめです。

参考書籍



参考記事:Pythonでロジスティック回帰分析して確率予測する