Python3でscikit-learnの決定木を日本語フォントで画像出力するためのメモ

タイトルの通り、Python3でscikit-learnの決定木を日本語フォントで画像出力するためのメモ。

結論からいうと以下のようにすればよい。

  • tree.export_graphviz()でdot文字列に出力
  • dot文字列をpydotplus.graphviz.Dotクラスに変換
  • pydotplusを利用してすべてのNodeやEdgeにfontnameを指定

前提

  • Windows 10, Anaconda 4.6.2, Python 3.7
  • 環境周りの準備は完了済み*1

irisを使って適当に決定木を作り表示する例。

from sklearn.datasets import load_iris
from sklearn import tree
import pydotplus
from IPython.display import Image
from graphviz import Digraph

clf = tree.DecisionTreeClassifier(max_depth=2)  # limit depth of tree
iris = load_iris()
clf.fit(iris.data, iris.target)

dot_data = tree.export_graphviz(
    clf,
    out_file=None,
    feature_names=['がく片の長さ','がく片の幅','花弁の長さ','花弁の幅'],
    class_names=iris.target_names,
    filled=True,
    proportion=True)
graph = pydotplus.graph_from_dot_data(dot_data)

#Setting font for Node 
graph.set_fontname('MS UI Gothic')

#Setting font for Node 
for node in graph.get_nodes():
    node.set_fontname('MS UI Gothic')

#Setting font for Edges 
for e in graph.get_edges():
    e.set_fontname('MS UI Gothic')

Image(graph.create_png())

# to save file
# graph.write_png('./test.png')

調べた過程

python graphviz 日本語化 決定木”あたりでとりあえず検索してみると。以下の記事が出てくるが... ライブラリを手動で書き換えており、いくらなんでもそれは面倒かなと思いもう少し調べてみることに*2

Python3でscikit-learnの決定木を日本語フォントで画像出力する方法のまとめ | 自調自考の旅

そもそもGraphvizだけでも同じ事象が起こるのでは?、と思い”Graphviz 日本語化”あたりで調べると、日本語フォントを明示的にDOT言語の中に指定しないと文字化けするとのこと*3

サンプルコードのgraphをgraph.to_string()で文字列として出力してみると、font名の指定がないので、それさえ指定してやれば日本語化できそうな当たりがつく。

あとは、pydotplusのリファレンスを読み解きながら、Graph, Node, Edgeの各オブジェクトに対してfontnameを指定してやることで解決した。

※最初は、graph.set_node_defaults(fontname="MS UI Gothic")のようにデフォルト値を設定できそうなメソッドで設定したが、文字化けは解消せず。結局、各オブジェクトを取得したうえで、font設定を追加する方法をとった。

なお、Subgraphがあるような場合は、get_subgraph()で取得した後に、Subgraph自身と配下のNodeとEdgeに同じ操作をすればよいはず。

参考資料

DOT言語

Graphviz (ソフトの方)

graphviz (ライブラリの方)

pydotplus

決定木

*1:scikit-learnのUser's Guideの例のような英語での決定木は出力できている

*2:ライブラリを更新したときや、別の環境で作業するときに困ると思う...

*3:Graphvizで日本語を使う (Graphviz version 2.26.3) - とあるソフトウェア開発者のブログ