Docker で Jupyter を使用しながら dtreeviz で決定木を綺麗に出力する

## はじめに
この記事は、`Docker` で `Jupyter Lab` を起動し、`dtreeviz` を使用できるようにする内容となっています。
個人的なメモとして残しておきます。

### 必要な環境
- [Docker](https://www.docker.com/products/docker-desktop)（この記事を書いているときは Docker Desktop for mac 3.0.2）

### dtreeviz について
- [https://github.com/parrt/dtreeviz](https://github.com/parrt/dtreeviz)

dtreeviz は、木構造などを可視化するための Python ライブラリです。
グラフ構造を出力するためには graphviz のライブラリの使用が一般的ですが、より綺麗にグラフ構造が出力できるのがこのライブラリとなります。

## 1. Docker でコンテナを立てる
イメージは [jupyter/datascience-notebook](https://hub.docker.com/r/jupyter/datascience-notebook/) を使用します。

今回は

- ホスト OS のポートは 8888 番を使用
- マウントしたいディレクトリが存在し、それにマウントを行う
- メモリは 8GB までに設定
- Jupyter Lab を起動し、トークン無しでアクセスできるように設定

の条件のもとコンテナを立てます。
コマンドは、以下になります。

```bash:Terminal
$ docker run --rm --name {コンテナ名} -d -p 8888:8888 -v {マウントしたいディレクトリ}:/home/jovyan/ -m 8000m jupyter/datascience-notebook jupyter-lab --no-browser --port=8888 --ip=0.0.0.0 --NotebookApp.token=''
```

上のコマンドを毎回入力するのは面倒なので、Makefile を作成してコマンド入力を省略することをおすすめします。

```makefile:Makefile
jupyter:
        docker run --rm --name {コンテナ名} -d -p 8888:8888 \
        -v {マウントしたいディレクトリ}:/home/jovyan/ \
        -m 8000m \
        jupyter/datascience-notebook \
        jupyter-lab --no-browser --port=8888 --ip=0.0.0.0 --NotebookApp.token=''
```

こうすることで `Makefile` が存在しているディレクトリで `make jupyter` と入力することでコンテナを立てることができます。

## 2. コンテナに root ユーザーでログインし、足りない環境をインストールする
以下のコマンドを入力し、root ユーザーとしてログインします。

```bash:Terminal
docker exec -it --user root {コンテナ ID} /bin/bash
```

コンテナ ID は `docker ps` から確認できます。
その後、ログインしたセッションで以下のコマンドを入力します。

```bash:Terminal
$ apt-get dist-upgrade && apt-get update && apt-get install build-essential && apt-get install graphviz -y
$ pip install dtreeviz dtreeviz[boost] dtreeviz[pyspark]
```

1 行目では、graphviz の導入を行っております。
dtreeviz では graphviz が必要となっているため、インストールを行います。
`apt-get install graphviz` だけではうまくインストールを行うことができないため、一度 apt-get の更新などを行ってからインストールを行います。

2行目は、dtreeviz の導入を行っております。
__[scikit-learn](https://scikit-learn.org/stable) のみで使う__ 場合であれば、`pip install dtreeviz` だけインストールでも大丈夫です。
[XGBoost](https://xgboost.readthedocs.io/en/latest) と [Spark MLlib](https://spark.apache.org/mllib/) でも使用したい場合は、`dtreeviz[boost]` と `dtreeviz[pyspark]` もインストールしてください。

インストールが終わったら `exit` でログアウトして大丈夫です。

## 3. 動作確認してみる
Iris データを可視化してみましょう。

[http://localhost:8888/lab](http://localhost:8888/lab) にアクセスし、以下のコードを実行します。

```python
from sklearn.datasets import load_iris
from sklearn import tree
from dtreeviz.trees import dtreeviz

clf = tree.DecisionTreeClassifier(max_depth=2)
iris = load_iris()
clf.fit(iris.data, iris.target)

tree_viz = dtreeviz(
    clf,
    iris.data, 
    iris.target,
    target_name='variety',
    feature_names=iris.feature_names,
    class_names=[str(i) for i in iris.target_names],
)

display(tree_viz)
```

#### 最後の出力構文について
Jupyter Notebook の場合は `tree_viz.view()` でも表示可能です。
__Jupyter Lab や Google Colab を使用している場合__ は、`display(tree_viz)` で可視化を行わないと出力されないので気をつけてください。
また、`tree_viz.save({保存したいファイル名})` で SVG ファイルとして出力結果を保存できます。

結果がこちらです。

|![iris データを dtreeviz で可視化したもの](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276546/8bb09228-a6a2-0758-932d-cf72b8788bbf.png)|
|:-:|

無事、出力できました。

## おわりに
講義で決定木を出力する必要があり、「せっかくなら `graphviz` より `dtreeviz` のほうが綺麗に出力できるよなー」と思って実行してみました。
スライドなどに使う際も見やすいほうがいいと思うので皆さんも使ってみてはいかがでしょうか。