ランダムフォレストの全決定木を可視化してGIFアニメにしてみた

  • このエントリーをはてなブックマークに追加

機械学習アルゴリズムの1つであるランダムフォレスト分析は多数の決定木を作成して多数決で予測する手法です。決定木が沢山できますが、「どんな木が出来たのかな~」っと何気なく思った人のために、眺めていると無心になれる「全決定木可視化動画」の作り方を紹介します。

こんにちは。wat(@watlablog)です。今回は完全に無益回!ランダムフォレストで作成される全決定木を動画にしてみましたという内容です!

※注意
本記事を読んだからといって、何か特別な知識が付くとか、kaggleで勝てるようになるとかそんなことは全くありません。時間に余裕のある方のみ閲覧するようにして下さい!

ランダムフォレストでは複数の決定木が作成される

決定木とは?

決定木分析とは、機械学習のアルゴリズムの1つで、条件分岐を繰り返して分類や回帰を行う手法のことです。当WATLABブログでは「Python/sklearnで決定木分析!分類木の考え方とコード」という記事で概要を紹介していますので、決定木分析で機械学習をしたことが無い方は是非この記事を読んでみて下さい!

ランダムフォレストとは?

ランダムフォレストとは、決定木とバギングを組み合わせた機械学習法で、簡単に説明すると多数の決定木を作成して多数決で分類結果を決めたり、平均をとって回帰したりする大変民主主義的なアルゴリズムです。

ランダムフォレストについても概要を「Python機械学習!ランダムフォレストの概要とsklearnコード」に記載しましたので、必要であればこちらも読んで頂ければと思います。

決定木は数ある機械学習法の中でも人間が解釈しやすいと言われています。
これは決定木が条件分岐によって構築されるため、図にすることが可能だからです。(ディープニューラルネットワークとかでは中で何が行われているかを確認することは困難と思います)

決定木可視化について

可視化方法の例

図にすることができるのでその方法も多くあり、当WATLABブログでは「Python決定木可視化!Graphvizの導入とdot処理方法」という記事でGraphvizを使った可視化方法を紹介しました。

1つの決定木の可視化であればこの方法で良く、特に問題はありませんが、ランダムフォレストの場合は決定木が沢山あります。

そらもう100本ほど。

ランダムフォレストを可視化する必要性

決定木を可視化するのはハイパーパラメータを調整したり他者に説明するために大変重宝されると思いますが、個人的にはランダムフォレストを全て可視化する意味はあまりないと思います

importanceの分析やノード数depth数ジニ係数といった指標を統計的に見てスコアと対比させる方法が良いと考えられ、人間が直接目で木を1本1本確認していく作業は必要ないのではないかと感じています。

しかし中には全ての決定木を同じように可視化してざっとみたい…という場合もあるかも知れません。

例えばスコアでソートしてナンバリングした決定木を俯瞰してみると、max_depth初期ルートの分岐方法に人間にしか気づけない、何かの特徴を見出せるかも知れません。

他には、可視化した全決定木を画像入力の機械学習に使用する等すれば、より高いスコアが出せるかも知れません。

僕は完全に暇つぶしで可視化しました。

決定木可視化の問題(?)点

得られた画像をさらに使って異なる機械学習を行う…といった場合には画像は正規化(スケーリング)されていなければ使い勝手が悪いです。

これは通常のデータでも同じで、詳しくは「Python/sklearnで学習データの前処理!標準化と正規化」で説明していますので、ご興味のある方は是非読んでみて下さい。

しかし上記で紹介した方法を使って決定木を可視化すると、Graphvizの仕様で画像サイズを最適化してくれていることから、以下の図のようにルートノードが画像に対して必ずしも中心でなかったり画像サイズ(縦と横)が毎回異なるといった特徴があります。

可視化の問題点

この記事の目指す所

今回は各決定木のルートノードの位置を合わせ画像サイズを統一するという所を目指します。

これらのことを実行すれば、以下のようにGIFアニメにでもした時に木自体がどういう形をしているかが一目瞭然になります。

決定木可視化画像のスケーリングと位置調整の手順

ランダムフォレストから全決定木の.dotファイルを作成するPythonコード

以下のコードは「Python機械学習!ランダムフォレストの概要とsklearnコード」で紹介した全コードに「tree.export_graphviz」で.dotファイルを作成する部分を追加しただけです。

このコードを実行する.pyファイルがあるフォルダ内に「dir」フォルダを作っておくと、そのフォルダの中にランダムフォレストで構築された全決定木の.dotファイルが自動ナンバリングされて作成されます。

全決定木の.dotファイルを画像にするバッチファイル

次に、「Python決定木可視化!Graphvizの導入とdot処理方法」で可視化した時の「dot -Tpng 入力ファイル(.dot) -o 出力ファイル(.png)」コマンドをWindowsバッチファイルのforループを使って自動で.png画像に変換します。

このバッチファイルは.pyファイルと同じ位置に置いて実行します。事前にGraphvizは先ほどの記事に従ってインストールしてあります。

echo offにしなかったり、ループの最後にechoを書いているのは、実行されていることがわかるようにという意味がありますが、無くても構いません。

このファイルを実行するとdirフォルダの中に自動ナンバリングされた.png画像が作成されます。

決定木のルートノードの位置と画像サイズをそろえるPython画像処理コード

全コード

最後に、最終目的である「全決定木のルートノードと画像サイズをそろえるPythonコード」を紹介します。

この.pyファイルもその他.pyファイルやバッチファイルと同じ場所に入れて実行します。

実行すると、全ての決定木画像の画像サイズが同じになり、ルートノードが中央揃えになります

以下より概要を説明します。

画像を2値化してルートノードの両端エッジ座標を取得する

ルートノードは横方向の位置を合わせます。

それぞれの画像ルートノードの横方向の位置を取得するために、今回は下の図のように画像を横方向にスライスして四角形の両端エッジを検出しました。

グレースケール画像のライン

但し、画像を読み込んだだけでは画像の輝度値が安定していないので、以下の画像のように二値化してからスライスし、「index = np.where(line == 0)」と0位置を検索、配列1D化後に始めと最後の要素を取得すれば画像内でルートノードの中心位置が計算可能です。

二値化画像のライン

画像の二値化は「Python/OpenCVで画像の二値化をする方法」に詳細を書きましたので、是非参考にして下さい。

背景画像を作成する

画像サイズのスケーリングは各画像をリサイズ等で変えるのではなく(それだと決定木ノードの大きさがまちまちになるため)、背景画像を作成して各決定木画像を貼り付けるということを行っています。

背景画像は全画像の中で最も大きくする必要がありますが、縦サイズは全決定木画像の最大縦サイズ、幅サイズは全決定木画像の中で最大のルートノード中心位置(np.max(root_c_list))の2倍としました。

こうすることで全決定木の中で最もルートノードが右に来る画像のルートノード中心(つまり最大画像幅の半分)に全画像のルートノード中心を合わせれば幅方向位置合わせが完了します。

画像を貼り付ける

画像の貼り付けは「Python/OpenCVのROI抽出!領域の切り出しとコピー」で習得したROI抽出の方法をそのまま使っています。ROIは元の決定木画像そのもので、貼り付け先に背景画像、貼り付け位置に補正計算座標値を設定しています。

これらのコードを実行すると、以下のように複数決定木の画像が出来上がります。お好みの方法でGIFにしたり、その他機械学習に利用したりして活用(?)可能と思います。

まとめ

今回の記事は本当に思い付きの内容であまりに無益で申し訳ございませんが、機械学習と画像処理は意外と密接な関係があるのではと思い、これまで習得したコードを組み合わせてみました。

まだ本手法を使った画期的なソリューション等は思いつきませんが、本内容は暇つぶしにでもしていただければと思います。。

今回は正月休みぼけでちょっと「何の役に立つんだ!」感が強い記事でした!
Twitterでも関連情報をつぶやいているので、wat(@watlablog)のフォローお待ちしています!

SNSでもご購読できます。

コメントを残す

*