
シリーズPython⑥ XAI「機械学習を解釈する技術」を最新のライブラリで解釈する
はじめに
機械学習を解釈する技術の紹介
この記事は書籍「機械学習を解釈する技術〜予測力と説明力を両立する実践テクニック」(技術評論社、以下「テキスト」と呼びます)を 最近のPythonで動かすときの留意点を取り扱います。
テキストは、2021年8月に出版された「XAI・説明可能なAI」に関連する書籍です。
4つの基本的な説明指標を非常に丁寧に説明する良書です。
初めて4つの指標を学ぶ方にオススメです!
■ 4つの指標
・PFI : Permutation Feature Importance(特徴量の重要度)
・PD : Partial Dependence(特徴量と予測値の平均的な関係)
・ICE : Individual Conditional Expectation(個別データごとの異質性)
・SHAP : SHapley Additive exPlanations(個別データの特徴量貢献度)
■ テキストの特徴
次の3つの方法を用いて、とにかく、計算ロジックを丁寧に説明しています。
・数式
・簡単なモデルによる計算イメージ図
・コード実装(オリジナルコードと Pythonライブラリ使用コード)
■ 説明に使用する機械学習モデル
・線形重回帰モデル
・Random Forest モデル
■ 利用するプログラム言語
・メインは Python です。
・巻末に R の実装例(tidymodels、DALEX を利用)の掲載があります。

最近の Python 環境で動かすときの留意点と対策
テキストは約2年前に出版されています。
出版後、現在までに Python を取り巻く環境は大きく変化しています。
私もご多分に漏れず変化の波にのまれて、2つの問題に直面しました。
① テキストで利用するデータの取得が困難
② 最近のライブラリでは動かないコードがある
この記事は、私が実施した問題の対策を記載いたします。
テキストを手にした仲間が、ストレスなくコードを動かせたなら、幸いです。

まえがき
この記事は、出典に記載の書籍に掲載された文章及びコードを引用し、適宜、掲載文章とコードを改変して書いています。
コードの書き換えは「見つけることができた範囲内の処理内容」であり、処理の正確性は担保しておりません。
誤りや改善点がありましたら、ぜひ教えてください。
【出典】
「機械学習を解釈する技術〜予測力と説明力を両立する実践テクニック」(初版第4刷、森下光之助 著、技術評論社)
記号について
コードのコメントに★印のついている箇所が変更点です。
それでは「説明可能な対策案」を目指して、記事に進みます!!!

1. 「実データでの分析」で用いるデータセット
【関連する章】
第2章~第6章
テキストは「ボストン住宅価格データセット」を用いて説明指標の分析を行います。
取得方法には scikit-learn の datasets を用いています。
【問題】
scikit-learn のバージョン 1.2 以降、ボストン住宅価格データセットを取得できなくなりました。
従いまして、第2章 2.3.1 「データの読み込み」の「データセットの読み込み」処理でエラーが発生します。
### bostonデータをインポートするコード
from sklearn.datasets import load_boston

【自環境のバージョン】
scikit-learn : 1.3.0
【解決策の一例】
ボストン住宅価格データセットが無いと、テキストの美味しい部分を味わえないので、ぜひとも取得したいです!
ひとまず、ボストン住宅価格データセットを掲載するサイトから入手しましょう。
■ 掲載サイトの例
① rupakc 氏のGitHub(この下線リンクから飛べます)
② kaggle(kaggle ログイン後、下のリンクでデータセットに飛べます)
■ データ取得~読み込みの例
①の rupakc 氏のサイトでデータを取得する場合の手順を例示いたします。
①のサイトを開き、赤枠の下矢印をクリックして、ファイル保存画面を表示します。
ファイル名は表示された「housing.data」のままにして、PythonのNotebookファイルと同じフォルダに保存します。

2.3.1「データの読み込み」の2つ目のコードを次の内容に差し替えます。
### データセットの読み込み
# 特徴量名の設定
feature_names = ['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS',
'RAD', 'TAX', 'PTRATIO', 'B', 'LSTAT', 'MEDV']
# ファイルの読み込み
X = pd.read_csv('housing.data', names=feature_names, sep='\s+',
encoding='utf_8_sig')
# データの整形
y = X['MEDV'].values
X = X.drop('MEDV', axis=1)
【改善後】
特徴量 X と目的変数 y の形状、および、特徴量の先頭5行を表示します。
# 特徴量と目的変数の形状の表示
print('X.shape:', X.shape)
print('y.shape:', y.shape)
# 特徴量の表示
display(X.head())
2.3.2「データの前処理」の「特徴量の出力」の結果と同じになりました。


2. seabornのplot引数
【関連する章】
第2章~第5章、付録Bの「plot_scatter(s)関数」など
テキストでは、グラフ描画ライブラリ「seaborn」を多用して、ビジュアルにデータの特徴や説明指標を説明しています。
【問題】
最近の seaborn では、引数の順番が変更された模様です。
data、x、y ・・・ のように、x 引数、y 引数の前に data 引数が割り込んだため、テキストの順番 x、y ではエラーが発生して、グラフを描画できません。
※おそらく seaborn のバージョン 0.12.0 以降だと思われます。
【自環境のバージョン】
seaborn : 0.12.2
【解決策の一例】
第2章の plot_scatters 関数の定義を例にして、コード変更案を説明します。
### 散布図描画関数の定義
def plot_scatters(x, y, title=None):
'''目的変数と特徴量の散布図を作成'''
cols = x.columns
fig, ax = plt.subplots(2, 2)
for ax, c in zip(ax.ravel(), cols):
# sns.scatterplot(x[c], y, ci=None, ax=ax) # ★変更
sns.scatterplot(x=x[c], y=y, ax=ax) # ★変更
ax.set_ylabel('MEDV')
fig.suptitle(title)
plt.show()
「sns.scatterplot(x=x[c], y=y, ax=ax)」のように、x 軸のデータには x= を、y 軸のデータには y= を付けます。
なお併せて、引数 ci を削除しました。
【改善後】
無事に散布図を描画できました!

【影響する他のコード】
第3章・第4章・第5章・付録Bの「plot_scatter 関数」に含まれる sns.scatterplot
第5章の「IndividualConditionalExpectationクラス」に含まれる sns.lineplot と sns.scatterplot
Pythonスクリプトファイル「interpret.py」に含まれる sns.lineplot と sns.scatterplot

3. PD・ICEの可視化 by scikit-learn
【関連する章】
第4章・第5章の「plot_partial_dependence」を用いるコード
第4章・第5章の「実データでの分析」の項では、PD、ICEのグラフ可視化に scilit-learn の 「plot_partial_dependence」関数を用いています。
【問題】
最近の scilit-learn では「plot_partial_dependence」関数が削除されました。
※おそらく scikit-learn のバージョン 1.2.0 以降だと思われます。
テキストのコードをそのまま実行すると、エラーになり、PDやICEのプロットができません。
【自環境のバージョン】
scikit-learn : 1.3.0
【解決策の一例】
第4章の 4.5.1 「PDによる可視化」の「plot_boston_pd 関数」を例にして、コード変更案を説明します。
### PDの可視化 by scikit-learn
# from sklearn.inspection import plot_partial_dependence # ★変更
from sklearn.inspection import PartialDependenceDisplay # ★変更
# 何度か使うのでPartialDependenceDisplayを利用した関数を作成する
def plot_boston_pd(var_name, var_name_jp):
'''PDを可視化する関数'''
fig, ax = plt.subplots()
# plot_partial_dependence( # ★変更
PartialDependenceDisplay.from_estimator( # ★変更
estimator=rf, # 学習済みモデル
X=X_test, # PDを計算したいデータ
features=[var_name], # PDを計算したい特徴量
kind='average', # PDは'average', ICEは'individual', 両方は'both'
ax=ax,
)
fig.suptitle(f'{var_name_jp}({var_name})のPartial Dependence Plot')
plt.show()
「plot_partial_dependence」関数の代替機能は「PartialDependenceDisplay.from_estimator」です。
次の2点を変更します。
インポート
PartialDependenceDisplay をインポートします。
関数の実行
PartialDependenceDisplay.from_estimator に差し替えます。
なお、引数は、以前の「plot_partial_dependence」関数と同じで動きます。
【改善後】
無事に特徴量「RM」の PD を描画できました!

【影響する他のコード】
第5章 5.6「実データでの分析」の「plot_ice 関数」

4. shap のインストール
【関連する章】
第6章の 6.6.1「shap パッケージの導入」
第6章の「実データでの分析」の項では、SHAP 値の算出やさまざまなグラフ描画にパッケージ「shap」を利用します。
次のリンクは shap のサイトです。
【問題】
Anaconda 環境に conda コマンドで shap をインストールして、テキストの「SHAP 値を計算するための explainer を作成」コードを実行したところ、エラーになりました。
conda install -c conda-forge shap
■ エラーメッセージ
AttributeError: module 'numpy' has no attribute 'bool'.
実行コードに numpy は含まれていないので、このエラーは謎だらけでした・・・
【エラーの原因】
anacondaで管理可能な shap と numpy のバージョンの関係に問題がありました。
・shap は内部処理で numpy を利用。
・numpy が 1.24.0 にバージョンアップした際に bool に関する処理を削除。
しかし、shapでは削除した処理を利用していた。
・shap が 0.42.0 にバージョンアップした時に、numpy 利用処理を変更。
・conda コマンドでインストールする shap のバージョンは 0.41.0 。
まとめます。
shap が 0.42.0 より古い場合、numpy は 1.24.0 より古いバージョンが必要
shap が 0.42.0 以降の場合、numpy は 1.24.0 以降のバージョンでOK
【自環境のバージョン】
numpy : 1.24.3

【解決策の一例】
主に次の3つの方法でインストール/バージョン変更を行って、 shap と numpy のバージョンの整合性をとります。
■ anaconda で実施できる策
① shap と numpyのバージョン整合性を維持できる仮想環境を作る
② numpy を 1.24.0 よりも前のバージョンにする
■ anaconda で実施できない策
③ pip でバージョン 0.42.0 以上の shap をインストールする
私は、③の pip で バージョン 0.42.1 の shap をインストールしました。
最も簡単に実施できる点を優先しました。
なお、pip でインストールする前に、shap のアンインストールが必要です。
# conda環境のshapをアンインストール
conda uninstall shap
# pipでshapをインストール
pip install shap
【改善後】
無事にインスタンス0の SHAP 滝グラフを描画できました!

【影響する他のコード】
第6章 6.6「実データでの分析」の shap を利用するコード全般
付録B B.5.2「シミュレーションによる比較」の shap を利用するコード全般

結び
shap ライブラリは、shap 値を利用した特徴量重要度を可視化できるなど、活用の場が広いと思います。
データ分析のモデルを評価したり、関係者にモデルを伝えるときに、今回学んだ4つの指標を活用したいです。
おわり
ブログの紹介
noteで3つのシリーズ記事を書いています。
ぜひ覗いていってくださいね!
1.のんびり統計
統計検定2級の問題集を手がかりにして、確率・統計をざっくり掘り下げるブログです。
雑談感覚で大丈夫です。ぜひ覗いていってくださいね。
統計検定2級公式問題集CBT対応版に対応しています。
2.Python機械学習プログラミング実践記
書籍「Python機械学習プログラミング PyTorch & scikit-learn編」を学んだときのさまざまな思いを記事にしました。
この書籍は、scikit-learnとPyTorchの教科書です。
よかったらぜひ、お試しくださいませ。
3.データサイエンスっぽいことを綴る
統計、データ分析、AI、機械学習、Pythonのコラムを不定期に綴っています。
「統計」「Python」「数学とPython」「R」のシリーズが生まれています。
最後までお読みいただきまして、ありがとうございました。