ツリーの4つの可視化方法

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/986141/1b9c92a6-ece6-fe80-07cd-d6bb307ec056.png)


# ツリー構造の4つの可視化方法
ランダムフォレストやXGBoost、決定木分析をした時にモデルのツリー構造を確認します。決定木の大きさやデータによって描画の仕方に使い分けができるので、それぞれまとめました。

**💡この記事で紹介すること**

:::note info
1. **tree.export_text**でテキスト描画
1. **tree.plot_tree**を使う
1. **graphviz**を使う
1. **dtreeviz**でヒストグラムや円グラフも追加
:::

# ツリーの可視化

Kaggleの**Spaceship Titanic**を題材にします。

https://www.kaggle.com/competitions/spaceship-titanic

このコンペは乗客が異次元に転送されたかどうかを推論する2値分類問題です。
説明変数は13個で、6個がnumerical、7個がcategoricalです。
今回はnumerical変数のみを説明変数として扱います。

<details><summary>前処理はこちら</summary>

```python
[in]
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.tree import DecisionTreeClassifier 
from sklearn.model_selection import train_test_split

df = pd.read_csv('/kaggle/input/spaceship-titanic/train.csv')

target = 'Transported'
X = df.drop([target], axis=1)
X = X[X.loc[:,X.dtypes=='object'].columns]
X = X.fillna(X.mean())
y = df[target].astype(int)

```

</details>

#### 決定木分析でつくったモデルを使います。
```python
[in]
feature_names = list(X.columns)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
clf = DecisionTreeClassifier(max_depth=4,random_state=1234)
model= clf.fit(X_train, y_train)
```


## tree.export_textでテキスト描画
モデルをつくったsklearn.treeには3つの出力方法があります。
ドキュメントは[こちら](https://scikit-learn.org/stable/api/sklearn.tree.html)。

1つ目は、テキストによる描画です。

:::note warn
**こんな時に使う**
さっとツリーを確認したいときやコマンドラインで出力したいときに適しています
:::

```python
[in]
from sklearn import tree
print(tree.export_text(model,feature_names=feature_names))

[out]
|--- RoomService <= 0.50
|   |--- Spa <= 2.50
|   |   |--- VRDeck <= 332.00
|   |   |   |--- Age <= 12.50
|   |   |   |   |--- class: 1
|   |   |   |--- Age >  12.50
|   |   |   |   |--- class: 1
|   |   |--- VRDeck >  332.00
|   |   |   |--- FoodCourt <= 3657.00
|   |   |   |   |--- class: 0
|   |   |   |--- FoodCourt >  3657.00
|   |   |   |   |--- class: 1
|   |--- Spa >  2.50
|   |   |--- FoodCourt <= 2507.50
|   |   |   |--- Spa <= 314.57
|   |   |   |   |--- class: 0
|   |   |   |--- Spa >  314.57
|   |   |   |   |--- class: 0
|   |   |--- FoodCourt >  2507.50
|   |   |   |--- Spa <= 2523.50
|   |   |   |   |--- class: 1
|   |   |   |--- Spa >  2523.50
|   |   |   |   |--- class: 0
|--- RoomService >  0.50
|   |--- RoomService <= 365.50
|   |   |--- Spa <= 422.50
(省略)
```

階層が深いツリーを扱う場合は`max_depth`を設定して大項目だけ見やすくするのも良いです。
```python
tree.export_text(model,feature_names=feature_names, max_depth=3)
```

## tree.plot_treeを使う
plot_treeは、export_text同様sklearn.treeにあります。
こちらは画像としてプロットを生成します。

:::note warn
**こんな時に使う**
ツリーの全体像を図でさっと確認したいときに便利です。ツリーが複雑ではない場合が望ましいです
:::

```python
[in]
fig = plt.figure(figsize=(32,20))
_ = tree.plot_tree(model,feature_names=feature_names, fontsize=10,filled=True)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/986141/2feca98c-14bb-5e0c-b289-5731d8f1c0c5.png)


画面のサイズに収まるように表示するので、サイズ調整が必要になることもがあります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/986141/1ac87aab-a45d-5dfd-96f9-5bcfb27e8937.png)

`figure`のメソッドで画像を保存します。
```python
fig.savefig('tree.png')
```

## graphvizを使う
こちらもsklearn.treeにあります。graphvizはdot言語というグラフ構造を記述する言語によって書かれています。plot_treeとは描画の挙動が異なる点に注意です。

:::note warn
**こんな時に使う**
ツリーが大きいときやパラメーターを細かく見たいときに適しています
:::

```python
[in]
import graphviz
dot_data = tree.export_graphviz(model, out_file=None, 
                                feature_names=feature_names,  
                                class_names=['True','False'],
                                filled=True)
graph = graphviz.Source(dot_data, format="png") 
graph
```
![tree (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/986141/f8dea32b-4bd9-bd27-0a1f-bad276654f7c.png)

plot_treeと異なりオーバーフローが適用されます。大規模なツリーであったり、表示項目が多くても、表示サイズを気にしなくてよいです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/986141/dc77d642-d4be-5688-8bb6-9de0449447a6.png)

保存は`render`を使います。事前にフォーマットとしてpngを指定しているので拡張子の記述は不要です。

```python
graph.render('tree')
```

importが上手くいかない場合は[ドキュメント](https://pypi.org/project/graphviz/)を確認してください。

## dtreevizでヒストグラムや円グラフも追加
最後は[dtreeviz](https://github.com/parrt/dtreeviz)です。dtreevizはツリー構造を説明するためのpythonライブラリで、scikit-learn、XGBoost、Spark MLlib、LightGBM、Tensorflowをサポートしています。

:::note warn
**こんな時に使う**
入力したデータをどのように分岐させたかを確認したいとき
:::

```python
[in]
!pip install dtreeviz
import dtreeviz as dt

viz = dt.model(model,X_train=X_test, y_train=y_test,
                target_name="Transported",
                feature_names=list(feature_names))

viz.view()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/986141/ffecb1c5-f14e-ea5f-524a-0aaa6935e88e.png)

データのヒストグラムに対してどこに分岐の基準点を置いたかをヒストグラムで表し、どの程度の割合でそれぞれのクラスが混ざっているかを円グラフで表しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/986141/1ec8c5b9-776a-1727-21ed-45b1542266d4.png)

また、保存はsvg形式です。
```python
viz.view().save('tree4.svg')
```

# まとめ
dtreevizは性能を確認したり、説明するのにとても便利です。個人的には、実際の解析では方向性が見えるまではさらっとテキストで出力することも多いです。