tkherox blog

データサイエンスおよびソフトウェア開発、たまに育児についての話を書いています

SHAPの各種可視化プロットを日本語化する

今回の記事は備忘録も兼ねて軽めの内容を記載していきます.

はじめに

機械学習のモデル解釈で頻繁に用いられるのがSHAPです.
実際のデータ分析の現場で頻繁に用いられるライブラリとしては shap があります.

github.com

個別のサンプルにおけるSHAP Valueの傾向を確認する force_plot や大局的なSHAP Valueを確認する summary_plot 、変数とSHAP Valueの関係を確認する dependence_plot など,モデル傾向を確認するための便利な可視化メソッドが用意されておりこれらを適切に用いることで可視化をモデル の解釈を行うことができます.

今回のテーマではライブラリの基本的な操作方法については言及しないので,基本的な操作方法について把握したいという方は以下のサイトなどを参照してみてください.

engineering.mercari.com

www.medi-08-data-06.work

実行環境

今回の実行環境は以下となります.

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.14.6
BuildVersion:   18G6042

$ python -V
Python 3.9.1

問題

さて,通常アナリストが分析を実施してモデルを解釈する際には特段気にする必要はないのですが、機械学習のモデル解釈性をアナリスト以外の人にレポーティングする際には注意する必要があります.
それは shap ライブラリを用いた可視化を行った際に特徴量として利用したカラム名の英字表記になります.何が問題なのかをもう少し言及すると、アナリストは実際にデータを扱っているため英字のカラム名が何を意味するデータ項目なのかを把握していますが、初見で見た人はそのデータ項目が何を指しているのかを理解することは容易ではありません.つまり、報告される側に立って可視化するためにカラム名をマルチバイト文字(日本語)に変更する修正をする対応が必要になってきます.

そこで,直面する問題がマルチバイト文字の文字化けです.
実際の例を見てみましょう.
データはUCIの公開データセットである Adult Data Set を利用します.

archive.ics.uci.edu

当該データセットではデフォルトでは英字になっていますが、今回はこれらのカラムを日本語に変更して扱います. カラムのそれぞれにおける英字と日本語の対応は以下の通りです.

|カラム| 日本語 | |:---:|:---:| | Age | 年齢 | | Workclass | 労働階級 | | Education-Num | 教育年数 | | Marital Status | 婚姻状態 | | Occupation | 職業 | | Relationship | 続柄 | | Race | 人種 | | Sex | 性別 | | Capital Gain | 資産売却益 | | Capital Loss | 資産売却損 | | Hours per week | 労働時間 | | Country | 出身国 |

では、早速実際のSHAPを出力するコードと出力結果を見ていきましょう.

import os
import sys
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import lightgbm as lgb
import xgboost as xgb
import shap
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, auc, roc_curve
shap.initjs()

seed = 42

# データ読み込み
X,y = shap.datasets.adult()
X_display,y_display = shap.datasets.adult(display=True)

# カラム名変更
X.columns = [
    "年齢", "労働階級", "教育年数", "婚姻状態", "職業", "続柄",
    "人種", "性別", "資産売却益", "資産売却損", "労働時間", "出身国",
]

# 学習データセット作成
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=seed)
lgb_train = lgb.Dataset(X_train, label=y_train)
lgb_test = lgb.Dataset(X_test, label=y_test)

# パラメータ
params = {
    "objective": "binary",
    "metric": "acu",
}

# モデルの学習
lgb_m = lgb.train(
    params,
    lgb_train,
    10000,
    valid_sets=lgb_test,
    early_stopping_rounds=50,
    verbose_eval=1000,
)

# shap可視化
explainer = shap.TreeExplainer(model=lgb_model)
shap_values = explainer.shap_values(X=X_test)
shap.summary_plot(shap_values[1],X_test)

モデルはLightGBMを用いて作成したその後に各特徴量のShap値をViolinPlotで出力しています. 結果は以下のようなグラフになりました.ご覧の通り文字化けしていて、どの特徴量がモデルの予測結果に寄与しているのかが分かりません. つまり、このようにshapを用いて日本語の可視化を行った場合は結果が読み取れないグラフが出来上がったしまいます.

対策

前章で記載した問題についての対策を述べていきます. この文字化けが発生する原因はmaplotlibで日本語フォントが扱えないことが要因になります. そのため、matplotlibで日本語フォントが扱えるように対応するだけで解決できます.そこで、japanize-matplotlibをインストールして利用します.

$ pip install japanize-matplotlib

さて、実装方法ですが非常にシンプルで import japanize_matplotlib をimportするだけです.

import os
import sys
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import japanize_matplotlib # ここを追加するだけ
import lightgbm as lgb
import xgboost as xgb
import shap
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, auc, roc_curve
shap.initjs()

seed = 42

# データ読み込み
X,y = shap.datasets.adult()
X_display,y_display = shap.datasets.adult(display=True)

# カラム名変更
X.columns = [
    "年齢", "労働階級", "教育年数", "婚姻状態", "職業", "続柄",
    "人種", "性別", "資産売却益", "資産売却損", "労働時間", "出身国",
]

# 学習データセット作成
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=seed)
lgb_train = lgb.Dataset(X_train, label=y_train)
lgb_test = lgb.Dataset(X_test, label=y_test)

# パラメータ
params = {
    "objective": "binary",
    "metric": "auc",
}

# モデルの学習
lgb_m = lgb.train(
    params,
    lgb_train,
    10000,
    valid_sets=lgb_test,
    early_stopping_rounds=50,
    verbose_eval=1000,
)

# shap可視化
explainer = shap.TreeExplainer(model=lgb_model)
shap_values = explainer.shap_values(X=X_test)
shap.summary_plot(shap_values[1],X_test)

出力結果ですが、先程のソースコードを改修することなく文字化けが解消されました. 可視化周りは意外とこういった細かい部分で詰まることが多いのですが、いったん解決策を知ると案外大したことない問題だったといったことが多い気がします.とは言え、知らないと多くの時間を浪費してしまうこともあるので些細なTipsを把握しておくのも大事ですよね.

まとめ

最近忙しくて更新が滞っていたのですが、また意識して更新するようにしていきたいと思います. 内容についてもあまり世間一般的に記事がまとめられていない内容について積極的に記載していきたいと思います.