説明モデルSHAP概説+説明モデルを要因分析に使う時のメモ

Twitter始めました。よかったらフォローしてもらえると嬉しいです!
リンク

また、目下勉強中のため、おかしい/違うと思う/わかりにくい点など些細なことでもフィードバックをいただけるととても嬉しいです。

章立ては以下のようになります。

はじめに

昨年のニュースに、AIの判断について企業に説明責任を求めるというものがありました。是非はさておき、AI・人工知能の説明性というトピックは世間一般でも話題になっているように感じます。少し技術目線に移ると、今現在注目を集めている機械学習のモデル解釈手法の一つにSHAP(Shapley Additive exPlanation)があると思います。 論文は2017年NIPSに採択されていたり、kaggleの予測モデルの説明性を扱うコースにもSHAPが盛り込まれています。 またGoogleのサービスではSHAPの元アイデアとなるShapley値を用いてWebページの評価を行なっているとの記載があります。お墨付きのようで少し心強いですね。笑

このようにSHAPは知名度が高いと感じる一方、日本語の情報が少ないと感じていました。そのため記事を書こうと思ったのですが、こちらのメモを見かけ TreeSHAP論文の素晴らしいメモで怖気付き 論文の話は内容が重複すると思ったので、ここではSHAPの概要と実務で要因分析に用いた際に感じたこと・意識した点についてまとめたいと思います。

以下、SHAPの手法で算出される値のことをSHAP値と表現します。なお、私がSHAPを使った経験はTree系モデルのみのため、解説はTree系のモデルに偏っています。





SHAPとは

  • ゲーム理論のShapley値が起源
  • Shapley値は協力して行うゲームの参加者それぞれに、貢献度を割り振るための手法
  • SHAPはShapley値を機械学習モデルに適用できる形にしたもの
  • 機械学習では、出力結果にそれぞれの変数がどれだけ影響したかを意味する
  • ユースケースは以下の2点
    • 予測モデルの出力結果を説明する
    • 何かの原因となる要因の分析
  • (サンプル数*説明変数の数)の形で出力される

Shapley値とSHAPの関係

シャープレイ値(シャープレイち、英: Shapley value)とは、ゲーム理論において協力によって得られた利得を各プレイヤーへ公正に[1] 分配する方法の一案である。1953年にこの値を導入したロイド・シャープレーを記念して命名された。(Wikipedia引用)

こちらは、SHAPの元アイデアとなるShapley値の説明文です。簡単にいうと複数人で協力して行うゲームのスコアを、それぞれのプレーヤーの貢献度に基づいて割り振る手法です。

SHAPは、このShapley値を機械学習モデルに対して適用できるようにしたものです。論文では、説明モデルに望ましい3つの性質を持つものはただ1つであり、それがShapley値に等しい主張されています。 SHAPにおいては、予測値が複数人で協力して行うゲームのスコアに、説明変数がそれぞれのプレイヤーに、そしてSHAP値がそれぞれのプレーヤーの貢献度に対応します。 つまりSHAP値は、それぞれの説明変数がモデルの予測値にどれだけ影響を与えたかを表します。

ユースケース

kaggleの解釈性についてのコースでは、以下のようなユースケースを挙げています。

  • A model says a bank shouldn't loan someone money, and the bank is legally required to explain the basis for each loan rejection

  • A healthcare provider wants to identify what factors are driving each patient's risk of some disease so they can directly address those risk factors with targeted health interventions

拙訳

  • モデルが融資を行うべきではないと判断した時に、銀行は融資を断った理由を説明する法的義務がある
  • 医療提供者は、ある種の病にかかるリスクを向上させる要因を特定したがる。これにより、彼らはターゲット化した健康的介入をすることで、リスク要因に直接的に対処できるからだ。(すみません、いい訳が思い浮かびませんでした。)

前者は予測モデルの出力を説明する、SHAP本来の使い方です。こちらは冒頭の説明性のトピックに該当します。後者は何かの原因となる要因の分析です。私は実務で主に後者の用途でSHAPを用いました。

SHAPの特徴

続いて、他の主な変数重要度(Gain,Split,Permutationなど)と比較した実用上のSHAPの特徴を3点説明します。

  • 入力データセットと同じ形でSHAP値が計算される
  • 正負の符号付き
  • 他の説明変数との組み合わせで値が決まる

1点目に、SHAPは入力したデータセットと同じ形の行列で数値が返ってきます。モデル全体に対してそれぞれの説明変数がどれだけ効いたかの粒度で出力されるため、SHAPは細かい粒度で説明変数の影響を見ることができます。なお、SHAP値をサンプルの方向に集計することで、Gainなどのような説明変数の変数重要度を算出することが可能です。
2点目に、SHAP値は正負の符号付きで返ってくるため、その説明変数が予測のどちらの向きに効いたかがわかります。
3点目に、SHAPは他の説明変数との組み合わせで値が決まります。ある説明変数Aの値が同じサンプルがあったとしても、他の説明変数との相互作用によって、説明変数AのSHAP値は変化し得ます。例えば若年層に有効な広告があった場合、その広告を見た/見ていないという説明変数は若年層のサンプルには大きなSHAP値となり、高齢層のサンプルには小さなSHAP値となることが考えられます。

上記の特徴は、モデル全体での各説明変数の寄与ではなく、それぞれのサンプルレベルで各説明変数が出力にどう影響を与えたかを説明している点に起因しています。

Shapley値計算法

ここでは、ゲーム理論におけるShapley値の計算法を説明します。 

余裕があれば(勉強し直して)SHAPの論文の解説を書こうと思いますが、こちらの計算法を知っておけば大きな問題はないと考えています。

Shapley値の計算式

Shapley値の計算式で表現すると、以下のようになります。

\phi_i(v) = \sum_{S \subseteq  N \backslash{i}}\frac{|S|!(n-|S|-1)!}{n!}[v(S\cup{i})-v(S)]

N:プレイヤーの全体集合
S:プレイヤーの部分集合
v(S):部分集合Sのプレイヤーたちが参加した時のスコア
n:プレイヤーの総数

計算方法を簡単にいうと、プレイヤーが新たにゲームに加わった時のスコアの増分(貢献度)を、考えられる全てのパターン(順列)に基づいて計算して平均をとることで計算しています。

以下で例を用いて説明します。なお、こちらの説明はshiibassさんの記事を参考にさせていただきました。

例 プレイヤーA, B, Cが参加するゲームのプレイヤーAのShapley値(貢献度)を算出する。

A, B, Cがそれぞれ参加/非参加だった場合のスコアが以下の通りとします。

S(参加したプレイヤー) = スコア

S(0) = 0
S(A) = 20
S(B) = 20
S(C) = 20
S(A,B) = 60
S(A,C) = 110
S(B,C) = 100
S(A,B,C) = 120

プレイヤーが新たにゲームに加わる時のパターンは順列との類推で網羅でき、ここでは
3! = 6 通りとなります。

続いて、順列B -> A -> C を例とすると A参加前にはプレイヤーはBのみで、A参加後にはプレイヤーはA,Bとなるため、この順列でのAの貢献度は

(A参加後のスコア) - (A参加前のスコア) = S(A,B) - S(B) = 60 - 20 = 40

と計算できます。

この要領で全てのパターンにおけるAの貢献度を計算すると、以下の表のようになります。

プレイヤー順列 A参加前のスコア A参加後のスコア Aの貢献度
A -> B -> C S(0) = 0 S(A) = 20 20 - 0 = 20
A -> C -> B S(0) = 0 S(A) = 20 20 - 0 = 20
B -> A -> C S(B) = 20 S(A,B) = 60 60 - 20 = 40
B -> C -> A S(B, C) = 100 S(A, B, C) = 120 120 - 100 = 20
C -> A -> B S(C) = 20 S(A, C) = 110 110 - 20 = 90
C -> B -> A S(B, C) = 100 S(A, B, C) = 120 120 - 100 = 20

最後に、Aの貢献度の平均値を取ると (20+20+40+20+90+20) / 3! = 35 となります。 同様に計算すると、Bの貢献度は30、Cの貢献度は55となり、足し合わせると35 + 30 + 55 = 120となり、S(A,B,C)に一致します。

なお、ここではプレイヤー(説明変数の数)を3人としましたが、実際の機械学習モデルでは説明変数は数百数千となる場合もざらにあると思います。この時、計算量が階乗のオーダーで増えていくと現実的な計算量で収まらなくなるため、TreeSHAPの論文ではそれを高速化するアルゴリズムを採用しているようです。具体的な計算量は、

O(木の本数*モデル中の木の葉の最大数*木の深さ2)のオーダーです。

補足ですが、SHAPはゲーム理論のShapley値を元に

  • 予測モデルを加法的線形モデルに変換する
  • それぞれの説明変数を考慮する、しないを01のフラグに変換して説明モデルの入力とする
  • 考慮しない変数は学習データの分布でその変数を補完して計算する

の工夫を加えたものと私は理解しています

細かい部分を簡潔に説明するのが私には困難なので、余裕があれば(勉強し直して)解説記事を書こうと思います。

(パッケージでできる)可視化例

一番下の可視化を除いて、bostonという住宅の価格のデータセットに対してSHAPを使った例です。データセットの説明はこちらにあります。

特定のサンプルのSHAP値

f:id:tebasaki3:20190217120914p:plain

あるサンプルのそれぞれの説明変数が予測値をどれだけ変動させたかを可視化した図です。 まず、カラーバーの上の文字の説明から。base valueは全ての変数を考慮していない時の予測値で、学習データの目的変数の平均値となります。そしてmodel outputがそのサンプルの予測値です。 続いてカラーバーの説明です。ピンクが+方向の寄与を、青がー方向の寄与を表しています。例えば、このサンプルではLSTAT(低所得者の割合)の変数を考慮した場合としなかった場合で比較して予測値が4.98変動している(ここでは考慮することで上昇している)と見ます。 そして、base valueと全説明変数のSHAP値を足し合わせるとmodel outputになります。1




全サンプルのSHAP値

f:id:tebasaki3:20190217120947p:plain

一つ目の図は、全サンプルのSHAP値を各説明変数ごとにプロットしたものです。色が説明変数の値の大小を、プロットの位置がSHAP値の大小を表します。例えば、LS TAT(低所得者の割合)が低い変数の方が住宅価格の予測値が高くなる傾向にある事が図から読み取れます。 縦に長く伸びる形でプロットされている部分は、その辺りのSHAP値をとるサンプルが多くあることを意味します。

f:id:tebasaki3:20190217121004p:plain

二つ目の図は、一番上の図を全サンプル分可視化したものです。さらにSHAP値の類似度ごとに並べ替えることが可能で、そのため上の図はいくつかのグループに分けられそうな形状をしています。




それぞれの説明変数の変数重要度

f:id:tebasaki3:20190217121021p:plain

Tree系モデルのデフォルトで出力できる一般的な重要変数と同じ形式です。 SAHP値の絶対値の平均値を大きい順に並べたものです。




2変数とSHAP値の関係

f:id:tebasaki3:20190217121029p:plain

2変数とSHAP値を全サンプル分プロットしたものです。図では、色がRAD、左右がRM、上下がRMのSHAP値を表しています。図を見るとRM=7.3辺りを境にSHAP値が大きく変化しているのがわかります。推測ですが、おそらく予測モデル内で木の分岐がそのRM=7.3辺りで起こり、どちらの分岐に入ったかで予測値が大きく変化していると考えられます。




2つの説明変数の交互作用効果

f:id:tebasaki3:20190217121101p:plain こちらは、2つの説明変数の交互作用効果をプロットしたものです。図を行列と見た時、対角線上のプロット群はその変数の主効果を、対角線以外のプロットは交互作用効果を表現しているようです。色は行方向の変数の値の大小を、左右が交互作用効果を表現しています。

説明モデルで要因分析する際に気づいた/意識した点

この章は特に、思うところがあればフィードバックをいただけると嬉しいです。
そして、SHAPに特化した話より説明モデルの一般的な内容が多いことに気づいたので、タイトルを変えました。以下ではSHAP値で説明していますが、ご承知おきください。

  • 予測モデルの精度が高いことが望ましい
  • SHAP値がばらつくことがあるので、バリアンスを小さくする工夫を行ったほうがいい
  • 予測モデルの出力を説明する手法なので、因果関係を考慮しているわけではない

予測モデルの精度が高いことが望ましい

SHAP値はあくまでも予測モデルの出力結果に対して変数がどの程度効いたかを算出する手法です。なので、予測モデルの精度が低い場合、その説明モデルの出力であるSHAP値自体の真のモデルに対する信頼性も低いと考えられます。そのため、構築した予測モデルがある程度の精度を持つことが望ましいです。

SHAP値がばらつくことがあるので、バリアンスを小さくする工夫を行ったほうがいい

信頼性の観点から、なるべく出力値のバリアンスを下げる工夫を行った方がよいと思います。特にTree系モデルの問題なのですが、入力するデータセットの違いによってモデルの構造が大きく変化します。シードを変えて複数回CV(cross validation)してSHAP値を計算する実験を行ってみると、同じサンプルでもSHAP値が割とバラついたりします。そのため、シードを変えて複数回CVを行なって結果を平均するなどバリアンスを小さくする処理を行った方が良いと思います。

予測モデルの出力を説明する手法なので、因果関係を考慮しているわけではない

繰り返しですが、SHAP値はあくまで予測モデルの出力結果を解釈する手法です。そのため、説明変数と予測値になんらかの傾向が見えたとしても、それがイコール要因を表す訳ではありません。 以下、引用です。

サンゴとその捕食者の例を採り上げてみます(この話はこのtogetterの内容を基にしていますが、本記事ではあくまでも説明のための仮想例としてディテールは無視して取り扱います)。

サンゴの保全のための調査から、サンゴの生存率とサンゴの捕食者Oの個体数に以下の相関関係が示されているとしましょう。また、捕食者Oは実際にサンゴを捕食していることがフィールドでの観察から分かっているとします。

>

このとき、「捕食者Oの増加→サンゴの生存率の減少」という因果関係を想起するのは自然なことかもしれません。

もしこのような因果関係が存在するならば、「捕食者O」を減少させることにより「サンゴの生存率」を増加させることができそうです。

はてさてしかしながら:

より詳細な調査から、「捕食者Oは死にかけのサンゴしか食べない」ことが分かってきたとします。このとき、捕食者Oは実は生態系の中でスカベンジャー的役割を果たしていたということになります。

こうなると、「サンゴの生存率が低下→スカベンジャーである捕食者Oが増加」という逆の因果が真である可能性も出てきます。もしこの形の因果が真ならば、「捕食者Oを減少させることによりサンゴの生存率を増加させる」という保全施策は全く効果を及ぼさないことになります。(むしろ、スカベンジャーを排除することによりサンゴの健全な新陳代謝が妨げられる可能性さえあるかもしれません)

そして、このどちらの「因果の向き」がより真に近いのかは、基本的には現場での観察 and/or 介入によってしか明らかにすることはできません*7。

このように、因果関係があると思っていると実は因果が逆かもしれないという例は、ビジネスの現場でもあります。他にも、ある変数と目的変数に共通の要因となる交絡因子が絡んでくるなど、因果関係と混同するような変数間の関係性は色々あります。そのため、結果を鵜呑みにせず、データの生成過程を推測し変数同士の背後にある関係性を整理することで、今見ているものが何かを人が判断する必要があります。2因果関係にまつわる変数間の関係性については、詳しくは引用元のページで説明なされています。

余談ですが、複雑な因果関係を整理するフレームワークとして上司の方からシステムシンキングの本を紹介されました。3私は現状あまり使えていないのですが、とてもわかりやすくおすすめです。

おまけ 説明モデルを要因分析に使う際の考察

以下、簡単のため学習データの評価指標値をTS(Train Score)、検証データの評価指標値をVS(Validation Score)と表現します。

これは私の中の仮説なのですが、説明モデルで説明変数が目的変数に与える要因分析を行う場合、予測モデルは必ずしもVSが最大になる(early stopping)まで学習させない方が良いのではないかと考えています。一般にVSが最大になるまでモデルを学習させた場合、TSとVSは乖離するため、モデルがそれなりにノイズを拾っていると考えられるからです。

f:id:tebasaki3:20190219203626p:plain
学習曲線のイメージ図(引用)

学習途中で定期的に評価指標をプロットしてみると、最初の方はTSとVSが同じ形で伸びていきますが、徐々にTSの方がよくなり、最終的にTSが改善し続ける一方VSの方は指標が悪化し始めます。 この過程は、自分の頭の中では下のようにイメージしています。  

学習過程は真のモデルに近づく学習(LearnSignal)と学習データのノイズ(LearnNoise)を拾ってしまう学習が混ざったものであり、その比率LearnSignal/LearnNoiseは学習が進むにつれて小さくなっていく。そして、その比率が1より小さくなったタイミングで、early stoppingがかかり学習が止まる。

 

懸念として持っているのは、VSが最大になるまで学習を進めると学習データのノイズも相応に含んだモデルとなってしまうのではないかという点です。 そのため、要因を分析する目的で説明モデルを用いる場合は、必ずしもVSを最大にするような学習で構築したモデルが適切ではないのではないか、と考えています。

上記の説明は、VSが上がりきるまで学習させたモデルと、TSとVSの乖離が少ない学習途中のモデルのどちらが真のモデルに近いか、という話に帰着すると思います。

こちらについては、そのうち検証したいと考えています。しかし、どうすれば検証したことになるか難しい。。そもそもデータやモデル依存な部分もありますし。。学習の初期・中盤・終盤で、モデルで分岐に使用される変数やSHAP値がどう変化するかを調べたり、いい感じのシミュレーションデータがあれば、そのSHAP値と実際の目的変数に与えている貢献度を比較できる、などでしょうか。 良い方法があったり、もしくは近そうな論文などご存知の方がいらっしゃったら教えていただければ幸いです...!

ただ、DART(勾配ブースティングのモードの1つ)の論文では学習終盤に構築した木は学習序盤の木と比べてモデル全体に与える影響が小さいことが問題点として指摘されています。そのため、学習終盤の木がSHAP値に与える影響も大きくはないのかもしれませんが。

ここまで書いて今回は力尽きたので、SHAPを実際に動かす内容は次回以降に持ち越します。



文献リスト

SHAPに関する主な論文リストとパッケージは以下の通りです。私はSHAP総論とTreeSHAPしか読めていません。


  1. 分類モデルの場合、各説明変数のSHAP値の総和は確率値での出力では一致せず、木の葉の値(lightgbmならシグモイド変換をする前のraw value)に対して一致するようです。shap.readthedocs.io

  2. 余談ですが、因果関係を考えるのは非常に難しいです。以前少しだけ因果推論を扱ったのですが、自身の理論的な知識/ドメイン知識の不足を痛感させられました。

  3. 本ブログは副業が目的ではないので、リンクを踏んでも私の元にお金は入りません。よかったと思う本は積極的に紹介していく予定なので、興味があれば是非読んでいただければと思います。