XGBoost と RandomForest で中国語を可視化する

特徴量名やクラスラベルに中国語の文字が含まれていると、XGBoost、scikit-learn、Graphviz が生成する木の可視化で、それらが四角い箱や欠落したグリフとして表示されることがあります。一般的な対処法は、Graphviz が画像をレンダリングする前に、中国語をサポートするフォントを設定することです。

以下の例では FangSong を使用します。これは、使用しているシステムにインストールされている中国語対応フォントであれば、SimHeiMicrosoft YaHeiNoto Sans CJK SCSource Han Sans SC など、任意のものに置き換えられます。

Table of Contents

XGBoost

xgb.to_graphviz() は Graphviz オブジェクトを返します。レンダリングする前に Graphviz のソースを変更し、ノードのフォント定義を追加します。

import re
import xgboost as xgb


def set_graph_font(graph, font_name="FangSong"):
    graph.source = re.sub(
        r"graph [ rankdir=TB ]nn    0 ",
        f'graph [ rankdir=TB ]nn node [fontname="{font_name}" shape=plaintext]nn    0 ',
        graph.source,
    )
    return graph.source


diagraph = xgb.to_graphviz(model, num_trees=9)
diagraph.format = "png"
set_graph_font(diagraph)
diagraph

それでもフォントがレンダリングされない場合は、ローカルマシン上で Graphviz から利用できるフォントを確認してください。Linux では、フォントがインストールされているかを確認する最短の方法として fc-list がよく使われます。

fc-list | grep -i "fang|noto|source han"

RandomForest

scikit-learn の RandomForestClassifier または RandomForestRegressor では、各木を DOT ファイルにエクスポートし、デフォルトフォントを中国語対応フォントに置き換えてから、Graphviz で DOT ファイルをレンダリングします。

import re
from pathlib import Path
from subprocess import call

from sklearn.tree import export_graphviz


def plot_forest(model, column_names, output_dir="forest", font_name="FangSong"):
    output_path = Path(output_dir)
    output_path.mkdir(parents=True, exist_ok=True)

    for i, estimator in enumerate(model.estimators_[:10]):
        dot_path = output_path / f"tree-{i}.dot"
        cn_dot_path = output_path / f"tree-cn-{i}.dot"
        png_path = output_path / f"tree-cn-{i}.png"

        export_graphviz(
            estimator,
            out_file=str(dot_path),
            feature_names=column_names,
            class_names=["Class Name 1", "Class Name 2"],
            rounded=True,
            proportion=False,
            precision=2,
            filled=True,
        )

        source = dot_path.read_text(encoding="utf-8")
        source = re.sub(r"helvetica", font_name, source, flags=re.IGNORECASE)
        cn_dot_path.write_text(source, encoding="utf-8")

        # Convert to PNG using Graphviz.
        call(["dot", "-Tpng", str(cn_dot_path), "-o", str(png_path), "-Gdpi=600"])

Jupyter Notebook では、レンダリング済みの木を次のように 1 つ表示できます。

from IPython.display import Image

Image(filename="forest/tree-cn-0.png")

変換ステップを実行する前に、Graphviz がインストールされ、コマンドラインから利用できることを確認してください。

dot -V

dot が見つからない場合は、使用しているオペレーティングシステムのパッケージマネージャーで Graphviz をインストールし、その後 Notebook またはスクリプトを再実行してください。

Leave a Reply