【決定木】決定木を可視化しつつ、木分割アルゴリズムをまとめた(主にジニ不純度)

　学内での勉強会にて、決定木について発表を行いました。
　内容は「機械学習クックブック」</span>第14章決定木P227~232</span>まででしたが、今回はレシピ14.01の分類問題について、scikit-learnでの実装とアルゴリズム</span>まとめてみたいと思います。(個人ブログ閉鎖に伴う転載)


<h2>scikit-learnでの決定木の実装</h2>


　まず初めに、sklearnでの決定木の実装を見てみましょう。irisのデータセットを使用し、最後に学習過程を出力しています。

<h3>決定木学習用プログラム</h3>

```python
import pydotplus
from sklearn.tree import DecisionTreeClassifier
from sklearn import datasets
from IPython.display import Image
from sklearn import tree

#データをロード
iris = datasets.load_iris()
#説明変数
features = iris.data
#目的変数
target = iris.target

#決定木分類器オブジェクトを作成(デフォルトでジニ不純度を不純度指標としている)
decisiontree = DecisionTreeClassifier(random_state=0)
#decisiontree = DecisionTreeClassifier(criterion="entropy", random_state=0)

#分類器を訓練
model = decisiontree.fit(features, target)

#DOTフォーマットでデータを作成
dot_data = tree.export_graphviz(decisiontree,
                                 out_file=None,
                                 feature_names=iris.feature_names,
                                 class_names=iris.target_names)
#グラフを描画
graph = pydotplus.graph_from_dot_data(dot_data)
#グラフを表示
Image(graph.create_png())
```

<!-- wp:heading {"level":3} -->
<h3>決定木の学習過程可視化</h3>
<!-- /wp:heading -->

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385803/29328ca8-8cb9-815f-3280-bc82bdc51d3b.png)

　さて、以上のような図が表示されました(~~諸事情で若干荒い~~)。まず、この図を解説させて頂くと、この四角で囲まれたもの一つ一つを「**ノード**」と呼びます。一番上のノード**(根ノード**)について、以下の表のようになっており、その下に続くノードも同じものを示しています。

<!-- wp:table -->
<figure class="wp-block-table"><table><thead><tr><th>記述</th><th>記述の説明</th></tr></thead><tbody><tr><td>petal width(cm) &lt;= 0.8</td><td>分岐の条件</td></tr><tr><td>gini = 0.667</td><td>今いるノードのジニ不純度</td></tr><tr><td>samples = 150</td><td>ノード内の全サンプル数</td></tr><tr><td>value = [50, 50, 50]</td><td>ノード内の各クラスのサンプル数<br>(左からsetosa, versicolor, virginica)</td></tr><tr><td>class = setosa</td><td>「petal width(cm) &lt;= 0.8」のときに最も多くなるクラス名</td></tr></tbody></table></figure>
<!-- /wp:table -->

　これ以上分割する必要のない(一番下のノード)を**リーフ**と言いますが、そこでは、gini = 0となっていることが分かります。これはノード内のサンプルにばらつきがなく、完全に分類出来ていることを示しています。ジニ不純度についてアルゴリズムと一緒に見ていきます。

<!-- wp:heading -->
<h2>決定木のCARTアルゴリズム</h2>
<!-- /wp:heading -->

　まず、scikit-learnの決定木に採用されているアルゴリズムであるCARTについて紹介しようと思います。
　**CART**とは**Classification And Regression Tree**の略で、決定木のアルゴリズムの一つです。名前の通り、分類問題と回帰問題の両方を木構造で学習・予測が出来ます。学習の際に、木の分割は2分木で進んでいきます。以下に決定木のアルゴリズムについて簡単にまとめましたものを記載します。

<!-- wp:group -->
<div class="wp-block-group"><div class="wp-block-group__inner-container"><!-- wp:table -->
<figure class="wp-block-table"><table><thead><tr><th class="has-text-align-center" data-align="center">アルゴリズム</th><th class="has-text-align-center" data-align="center">不純度指標</th><th class="has-text-align-center" data-align="center">備考</th></tr></thead><tbody><tr><td class="has-text-align-center" data-align="center">ID3</td><td class="has-text-align-center" data-align="center">分類：情報エントロピー</td><td class="has-text-align-center" data-align="center">N分木<br>ロス・キンラン開発</td></tr><tr><td class="has-text-align-center" data-align="center">C4.5</td><td class="has-text-align-center" data-align="center">〃</td><td class="has-text-align-center" data-align="center">〃<br>ID3の改良版</td></tr><tr><td class="has-text-align-center" data-align="center">C5.0</td><td class="has-text-align-center" data-align="center">〃</td><td class="has-text-align-center" data-align="center">〃<br>C4.5の改良版</td></tr><tr><td class="has-text-align-center" data-align="center">CART</td><td class="has-text-align-center" data-align="center">回帰：MSE, MAEなど<br>分類：ジニ不純度 or <br>エントロピーなど</td><td class="has-text-align-center" data-align="center">2分木<br>Leo Breimanら開発</td></tr></tbody></table></figure>
<!-- /wp:table --></div></div>
<!-- /wp:group -->

<!-- wp:paragraph -->
<p>　それでは、CARTのアルゴリズムについてみていきましょう。今回使う不純度指数は<span class="keiko_yellow">ジニ不純度</span>です。情報エントロピーなどについてはまた後日まとめようかと思います。さて、学習の手順は以下のようになっています。</p>
<!-- /wp:paragraph -->

<!-- wp:list {"ordered":true,"className":"is-style-sango-list-main-color"} -->
<ol class="is-style-sango-list-main-color"><li>データを分割する条件を決定(ジニ不純度)</li><li>データを分割する</li><li>全てのリーフノードが1クラスになるまで木を分割する</li></ol>
<!-- /wp:list -->


<h3>1. データを分割する基準を決定(ジニ不純度)</h3>


　「1.データを分割する条件を決定」では、「○○が20cm以下」といった**分割条件を決定**します。この分割条件の決定には情報利得を使います。さらにこの情報利得を計算するためにジニ不純度を使います。
　ここで行うことは、以下の2つです。


* ジニ不純度の計算
* 情報利得の計算

<h4>ジニ不純度とは</h4>

　ジニ不純度とは、「**1つのノード内のデータにあるクラスのばらつき**」の指標です。ジニ不純度が大きいほどクラスの分割が出来ておらず、ジニ不純度が小さいほどクラスの分割が出来ているという解釈になります。
　定義式は以下のようになります。


$$I_G(t)=\sum^c_{i=1}p(i|t)(1-p(i|t))=1-\sum^c_{i=1}p(i|t)^2$$

　ここで、$c$はクラス数,$t$は現在のノード, $p(i|t)$はノード$t$においてクラス$i$に属するサンプルの割合となります。
　具体例として、先述したscikit-learnで可視化した決定木の根ノード(一番上のノード)のジニ不純度を実際に計算で求めます。サンプル数は150であり、クラス数は3、各々のクラスには50ずつデータが存在しました。したがって、定義式より、ジニ不純度は

$$I_G(t)=1-(\frac{50}{150})^2-(\frac{50}{150})^2-(\frac{50}{150})^2=1-(\frac{1}{3})^2-(\frac{1}{3})^2-(\frac{1}{3})^2\\<br>=1-\frac{1}{3}=\frac{2}{3}=0.\overline{6}$$

となり、可視化したジニ不純度0.667と一致します。
　次の情報利得はこのジニ不純度を用いて計算を行います。

<!-- wp:heading {"level":4} -->
<h4>情報利得とは</h4>
<!-- /wp:heading -->

情報利得は**分割の良さを示す指標**です。分割前のノードの不純度と分割後の子ノードの不純度の差によって求められます。木の分割が良いほど情報利得は大きくなり、木の分割が悪いほど情報利得は小さくなります。**最終目標は情報利得が最大になる条件で木の分割を行う**ことです。
　情報利得(IG)の定義は以下のようになります。

$$IG(D_p,f)=I_G(D_p)-\frac{N_{left}}{N_p}I_G(D_left)-\frac{N_{right}}{Np}I_G(D_{right})$$

　ここで、$D_p$は親ノード、$D_{left}$は左子ノード、$D_{right}$は右子ノード、$f$は分割を行う特徴量、$I(D_p)$は親ノード不純度、$N_p$は親ノードのサンプルの数、$N_{left}$は左子ノードのサンプルの個数、$N_{right}$は右子ノードのサンプルの個数となります。

<h3>2.データを分割する</h3>

　「1. データを分割する基準を決定(ジニ不純度)」により、情報利得を最大化するような条件(「○○が20以下」など)が得られたら、その条件でデータを2分木します。

<h3>3.全てのリーフノードが1クラスになるまで木を分割する</h3>

　「1.データを分割する条件を決定」と「2.データを分割する」の処理は、リーフノードが1クラスになる(ジニ不純度が0になる)まで繰り返します。

<h3>木の分割を具体例でみる </h3>

　抽象的な数式だけでは理解が出来ないので、実際に木の分割のための計算をしてみます。今回は以下の例題を考えます。左がパターン1で、右がパターン2です。

![ダウンロード (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385803/d725f864-183f-ba77-93d2-00d574131301.png)

　まず、親ノードの不純度は

$$I_G(D_p)=1-(0.5^2+0.5^2)=0.5$$

となります。

 次に、パターン1での情報利得を考えます。
 パターン1の左子ノードの不純度は

$$I_G(D_{left})=1-((\frac{3}{4})^2+(\frac{1}{4})^2)=\frac{3}{8}=0.375$$

 パターン1の右子ノードの不純度は

$$I_G(D_{right})=1-((\frac{1}{4})^2+(\frac{3}{4})^2)=\frac{3}{8}=0.375$$ 
 パターン1の情報利得は

$$IG(D_p,f1)=0.5-\frac{4}{8}\times0.375-\frac{4}{8}\times0.375=0.125$$
　次に、パターン2での情報利得を考えます。<br>パターン2の左子ノードの不純度は

$$I_G(D_{left})=1-((\frac{2}{6})^2+(\frac{4}{6})^2)=\frac{4}{9}=0.\overline{4}$$

 パターン2の右子ノードの不純度は

$$I_G(D_{right})=1-(1^2+0^2)=0$$
 パターン2の情報利得は

$$IG(D_p,f2)=0.5-\frac{6}{8}\times0.\overline{4}-0=0.\overline{16}$$
　以上の結果からパターン1の時情報利得0.125、パターン2の時情報利得$0.\overline{16}$より情報利得がより大きいパターン2の方が分割の条件として相応しいということになります。

　以上が決定木の分割のアルゴリズムになります。私自身、まだまだ疑問に思うことがあります。機会があればもう少し調査を進めていきたいと思っています。

<h2>参考文献</h2>

・scikit-learn で決定木分析 (CART 法)：<br><a href="https://pythondatascience.plavox.info/scikit-learn/scikit-learnで決定">https://pythondatascience.plavox.info/scikit-learn/scikit-learnで決定</a>木分析<br>・決定木Wiki：<br><a href="https://ja.wikipedia.org/wiki/決定木">https://ja.wikipedia.org/wiki/決定木</a><br>決定木分析についてざっくりまとめ_理論編<br><a href="https://dev.classmethod.jp/articles/2017ad_20171211_dt-2/">https://dev.classmethod.jp/articles/2017ad_20171211_dt-2/</a><br>・「達人データサイエンティストによる理論と実践 Python機械学習プログラミング」<br>・「機械学習クックブック」<br>・「図解即戦力　機械学習&amp;ディープラーニングのしくみと技術がこれ1冊でしっかりわかる教科書」