【備忘録】SHAPのexplainerのパラメータによって結果が変わってしまう with chatgpt4o

# SHAPについての簡単な説明
SHAPは学習済み機械学習モデルの解釈を行うための指標のひとつで、協力ゲーム理論のシャープレイ値の考え方を用いて、モデルの予測した値に対して、「特徴量がどのように寄与して算出されたのか」を示す値となっています。
ジニ係数やgain(目的変数の減少)などで求める特徴量重要度はモデル1つに対し1組だけ定まる値となっていますが、SHAPはモデルと1つのデータサンプルについて定まる値であり、ひとつひとつのサンプルについて考察を行うことができる点で便利な方法となっています。
Pythonのライブラリが存在しており、簡単に算出できる値となっています。実装については以下の記事が参考になります。

## 直面した問題
先日、改めてSHAPのドキュメントを見返していたところ自分が使っているTreeExplainerモジュールのパラメータにdataという引数があることに気がつきました。デフォルトの設定では「data = None」となっており、自身のコードでも特に設定はしておらずそのままになっていました。
そこで試しに、dataに訓練データやテストデータを入れてSHAPの算出を行なったところ、変更前とは異なる結果が出力されてしまいました！
QiitaのpythonでSHAPを実装している他の記事のコードを見ると、多くのコードでは「data」が指定されていましたが特にそのパラメータに関する言及はなく、なぜ結果が変わってしまうのかを疑問に感じました。
今回はこの疑問を解消すべく調査を行なった結果を共有できればと思います。

## 行なったこと
以下の2つを行って疑問の解消を図りました。
① 公式ドキュメントの確認
② ChatGPTとの対話
※ 今回の結果には不確実な要素が含まれる可能性がありますのでご了承ください。

### ① 公式ドキュメントの確認
公式ドキュメントのTreeExplainer
https://shap-lrjball.readthedocs.io/en/latest/generated/shap.TreeExplainer.html

「data」パラメータの説明は以下です。

>The background dataset to use for integrating out features. This argument is optional when feature_perturbation=”tree_path_dependent”, since in that case we can use the number of training samples that went down each tree path as our background dataset (this is recorded in the model object).

ここから下の２つのことがわかります。
1. バックグラウンドデータ（data）は特徴量の統合のために使用される
2. 「feature_perturbation」というパラメータが「tree_path_dependance」のとき、このパラメータは省略可能である。その理由は訓練サンプルをバックグラウンドデータと使用できるため

ここで新たなパラメータ「feature_perturbation」が出てきました。このパラメータの説明も見てみます。
>Since SHAP values rely on conditional expectations we need to decide how to handle correlated (or otherwise dependent) input features. The “interventional” approach breaks the dependencies between features according to the rules dictated by casual inference (Janzing et al. 2019). Note that the “interventional” option requires a background dataset and its runtime scales linearly with the size of the background dataset you use. Anywhere from 100 to 1000 random background samples are good sizes to use. The “tree_path_dependent” approach is to just follow the trees and use the number of training examples that went down each leaf to represent the background distribution. This approach does not require a background dataset and so is used by default when no background dataset is provided.

ここから下の２つのことがわかります。
1. 「feature_perturbation」パラメータには「interventional」及び「tree_path_dependance」が存在する
2. バッググラウンドデータが指定されない場合、「tree_path_dependance」が使用される

この「feature_perturbation」パラメータが今回の問題の原因となっているんでしょうか？

### ② ChatGPTに質問してみる
パラメータの説明に記載の論文などを流し見してみても解決の糸口を見つけることができなかったため、最新のGPT-4oの性能検証を兼ねて質問してみることにしました。
プロンプトについては省略し、最終的な出力を示します。
![スクリーンショット 2024-06-09 21.45.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603842/9230b222-3ba9-fc47-2d43-06473d47645b.png)

このようにわかりやすい図を付して、説明してくれます！
ハルシネーションに気をつけなければなりませんが、GPT-3.5しか使ってこなかった身からすると本当に使い勝手がよくなったと感じます。
この図は出力の最初の部分だけで、説明が多少わかりにくい部分もあったため、類似の例を用いて全体の流れを説明します。

**1 . 以下の様なバックグラウンドデータセット、学習済みの決定木モデル、SHAPを算出するデータサンプルを考えます**
<table>
  <caption>バックグラウンドデータセット</caption>
  <thead>
    <tr>
      <th>ID</th> <th>X1</th> <th>X2</th>　<th>X3</th>
    </tr>
  </thead>
  <tr>
    <td> 1 </td> <td>1</td> <td>3</td>　<td>2</td>
  </tr>
  <tr>
    <td> 2 </td> <td>2</td> <td>2</td>　<td>3</td>
  </tr>
    <td> 3 </td> <td>3</td> <td>1</td>　<td>4</td>
  <tr>
    <td> 4 </td> <td>4</td> <td>0</td>　<td>1</td>
  </tr>
</table>

学習済み決定木モデル
```
     (root)
     X1 <= 2
True  /     \False 
   (A)      (B)
 X2 <= 2   X3 <= 2
 /T  \F    /T \F
10   25  35   45
```
サンプルデータ
<table>
  <caption>サンプルデータ</caption>
  <thead>
    <tr>
      <th>ID</th> <th>X1</th> <th>X2</th>　<th>X3</th>
    </tr>
  </thead>
  <tr>
    <td> 1 </td> <td>3</td> <td>2</td>　<td>1</td>
  </tr>
<table>

**2 . 「feature_pertribution = "tree_path_dependence"」の場合、期待値の計算は以下の様になります。特徴量が与えられないか、ひとつのみ与えられる場合の計算例を示します。**
(i) 特徴量がない場合の期待値
```math
E(f(x)|x = \phi) = \frac{10 + 25 + 35 + 45}{4}  = 28.75
```
(ii) X1のみ与えられた時の期待値

X1  = 3なので、出力は35か45のいずれかとなります。これより期待値は
 ```math
 E(f(x)|x = [X1]) = \frac{35 + 45}{2}  = 40
```
(iii) X2のみ与えられた時の期待値

X2  = 2なので、出力は10か35、45のいずれかとなります。これより期待値は
 ```math
 E(f(x)|x = [X2]) = \frac{10 + 35 + 45}{3}  = 30
```

(iV) X3のみ与えられた時の期待値

X3  = 1なので、出力は10か25、35のいずれかとなります。これより期待値は
 ```math
 E(f(x)|x = [X3]) = \frac{10 + 25 + 45}{3}  =  26.66..
```

**3 . 「feature_pertribution = "intervation"」かつdataがバックグラウンドデータの場合、期待値の計算は以下の様になります。**

(i) 特徴量がない場合の期待値

「feature_pertribution = "tree_path_dependence"」の場合と同様に計算されます
```math
E(f(x)|x = \phi) = \frac{10 + 25 + 35 + 45}{4}  = 28.75
```
(ii) X1のみ与えられた時の期待値

X1  = 3で、他の特徴量はバックグラウンドデータで補完したデータ、(X1,X2,X3)=(3,3,2),(3,2,3),(3,1,4),(3,0,1)の出力の平均が期待値となります
 ```math
 E(f(x)|x = [X1]) = \frac{45 + 45 + 45 + 35}{4}  = 42.5
```
(iii) X2のみ与えられた時の期待値

(ii)と同様に考えると、(X1,X2,X3)=(1,2,2),(2,2,3),(3,2,4),(4,2,1)に対する出力を用いて以下のように求めることができます。
 ```math
 E(f(x)|x = [X2]) = \frac{10 + 10 + 45 + 35}{4}  = 25
```

(iV) X3のみ与えられた時の期待値

(ii)、(iii)と同様に(X1,X2,X3)=(1,3,1),(2,2,1),(3,1,1),(4,0,1)を考え
 ```math
 E(f(x)|x = [X3]) = \frac{25 + 10 + 35 + 35}{4}  =  21.25
```

以上のような計算によって「feature_pertribution」パラメータの違いがSHAPの計算結果を変わってしまうようです。
厳密に正しいかはわかりませんが、個人的には正しそうだと感じます。

# まとめ
今回はSHAPのTreeExplainerを用いる「data」パラメータに関する問題について、ドキュメントの確認とChatGPTを用いて調査を行いました。

結果として、『なぜ計算結果が変化するのか？』という疑問に対して納得感のある説明を得ることができました。

冒頭にも述べた通り、今回の説明は誤りを含む可能性があります。何か疑問点・修正点を見つけていただけましたら、加筆・修正していきたいと思いますのでコメントいただけるとありがたいです。

ここまでお付き合いありがとうございました。