English Deutsch
preview
不一致問題(Disagreement Problem):AIにおける複雑性の説明可能性を深く掘り下げる

不一致問題(Disagreement Problem):AIにおける複雑性の説明可能性を深く掘り下げる

MetaTrader 5機械学習 | 22 5月 2024, 10:37
67 0
Gamuchirai Zororo Ndawana
Gamuchirai Zororo Ndawana

不一致問題(Disagreement Problem)

不一致問題は、説明可能なAI(XAI、eXplainable Artificial Intelligence)として知られる学際的な分野での未解決の研究領域です。説明可能なAIは、モデルがどのように判断に至るかを理解する手助けをしようとするものですが、残念ながら言うは易くおこなうは難しです。 

機械学習モデルや利用可能なデータセットが大規模化し、複雑化していることは周知の事実です。実のところ、機械学習アルゴリズムを開発するデータサイエンティストは、ありとあらゆるデータセットにおけるアルゴリズムの挙動を正確に説明することはできません。  説明可能なAI (XAI)は、モデルに対する信頼を築き、その機能を説明し、モデルが本番環境に配備できる状態であることを検証するのに役立ちます。有望に聞こえるかもしれませんが、この記事では、説明可能なAI技術の適用から得られるかもしれない説明を盲目的に信用できない理由を読者に示します。 

目次

  1. はじめに
  2. 説明可能性手法の概要
  3. 大域的な説明と局所的な説明
  4. モデルにとらわれない説明とモデル固有の説明
  5. 不一致問題の定義と問題の要因
  6. ケーススタディ
  7. 結論
  8. 推奨


はじめに

機械学習によって、データの中に存在する関係や相互作用を学習することができますが、モデルの中に存在する関係や相互作用を学習するにはどうすればいいのでしょうか。  その疑問に答える最善の方法は、モデル説明技法を用いることです。この議論では、いくつかの異なる説明技法を検討します。モデル説明技法によって、次のような性質の質問に答えることができます。

  • モデルが最も有益だと判断したのはどの特徴か
  • データセットに1000の特徴があったとして、最も情報量の多い特徴と少ない特徴をどのように分けることができるか
  • ある特徴が変わると、モデルの出力はどう変わるのか
  • さらにエンジニアリングする価値のある特徴は何か

上記の質問に対する答えは重要な価値を持ちますが、私たちの行く手を阻む大きな障壁があります。同じモデルを評価する説明の間で不一致が見られることがあるということです。残念ながら、この記事を書いている時点では、この問題に取り組む方法について世界的に認知された手順はありません。ただし、今日はこの問題を軽減するための独自の枠組みを構築します。

人工知能をより広範なアプリケーションに統合しようとする世界的な潮流があります。しかし、モデルを信頼するという考えを抱く前に、モデル、モデルが学習した関連性、モデルの意思決定のプロセスを徹底的に説明できなければなりません。この望ましい性質は「説明可能性」と呼ばれます。説明可能なAI (XAI)は、与えられたモデルがどのようにしてその予測に到達したかを追跡する大きな可能性を秘めています。説明可能なAIが存在するのは、モデリング技術が高度になるにつれて、それを解釈する能力が徐々に低下していくからです。 

まずはじめに、多くの読者がすでに知っているであろう概念を使用した簡単な例を見てみましょう。最初にもっと単純な問題を一緒に解くことで、さまざまな説明可能性技法に対する直感を素早く養うことができます。この例を完了した後、MetaTrader 5端末から取得した実際の市場データで訓練された機械学習モデルにスキルを適用する準備が整います。

ここで考える例は、スポーツ選手の身体能力から年俸を推定するという単純な問題です。スポーツ選手の身体能力がより際立てばより高い年俸が期待できるのは明らかですが、問題は、どの身体能力が年俸の増加に最も影響するのかということです。

この例題で使用するデータセットは、ビデオゲームの巨人Electronic Artsが、お気に入りのプロアメリカンフットボール選手になりきって試合をシミュレートできるビデオゲーム「マッデンNFL」シリーズの一環として綿密に作成したものです。このデータセットには、アメリカンフットボールのプロ選手に関する詳細な統計が含まれています。この記事では、選手の年齢、スプリントスピード、筋力などの特徴に基づいて、選手の年俸を予測する4つの異なるモデルを訓練します。そこから様々なモデル説明技法を適用し、選手の属性と年俸の関係についてどのような洞察が得られるかを観察します。それぞれの説明技法がどのように解釈されるかを取り上げ、矛盾する説明があるかどうかを観察します。不一致にラベルを付け、何が不一致を生んでいるのかの解読を試み、可能な解決策について話し合います。 


EA「マッデンNFL」ビデオゲームシリーズ

図1:Electronic ArtsのマッデンNFLビデオゲーム


説明可能性手法の概要

大まかに言えば、説明可能性の手法はさまざまな方法で分類できます。最も単純なのは、ホワイトボックス説明手法とブラックボックス説明手法という2つのクラスに分類することです。前回の記事では、グラスボックスモデルとブラックボックスモデルについて説明しました。今日は予測モデルに焦点を当てているわけではないので、ここで言及するブラックボックスは、複雑で解釈の難しい機械学習モデルのことではありません。基礎となるモデルの解釈を助ける説明可能性アルゴリズムのことです。

ブラックボックス説明技法は、どのようなタイプのモデルにも使えるように設計されています。

ホワイトボックス説明技法は、特定のタイプの基礎となるモデルの構造を利用して、基礎となるモデルにより忠実な説明をおこなうように設計されています。

予想通り、説明手法は以下のように異なります。

  • 基礎となるデータの形式と構造について異なる仮定を持つ
  • モデルを理解するために異なる指標を定義し、評価する
  • 異なる条件下で失敗する

説明可能性アルゴリズムは、その方法論によっても分類することができます。例えば、各特徴の入力を1つずつ調整し、その後の予測値の変化を観察することで洞察を得る説明技法があります。これらの技法は摂動ベース技法に分類されます。一方、特徴量の変化に対してモデルがどの程度敏感かを理解しようとする説明可能性アルゴリズムもあります。これらの技法は、特徴に対するモデルの出力の微分をとるため、勾配ベース技法に分類されます。

今日は数種類の説明アルゴリズムだけを取り上げます。ここで説明した以外にも多く説明手法が存在するため、このリストは決して網羅的なものではありません。

最後に、期待値を管理することも重要です。50%以上の精度で証券価格を予測できるモデルを構築しても、必ずしも利益を生む取引が保証されるわけではありません。 


大域的な説明と局所的な説明

特徴の重要性やモデルの全体的な挙動についてもっと知りたい場合は、大域的な説明技法を採用する必要があります。逆に、モデルがどのようにして特定の予測にたどり着いたかを詳細に理解したい場合は、局所的な説明が必要になります。 

局所的な説明は、特徴量と目標の関係を細かいレベルで理解し、モデルの予測に対する信頼を築くのに役立ちます。さらに、どの特徴が誤った予測の原因となっているかをよりよく理解し、それらの特徴からより有用な情報を抽出するためのエンジニアリングを検討することもできます。

つまり、この単純な例では、どの特徴がスポーツ選手の年俸を予測するのに重要かを知りたい場合、Permutation Importanceのような大域的な説明技術を適用する必要があります。  さらに、特定のスポーツ選手の予測をより詳細に理解したい場合は、LIMEのような局所的な説明技術が必要になります。 


さっそく、モデルから大域的な説明を理解する例を見てみましょう。

いつものように、必要な依存関係をインストールすることから始めます。

この場合、次をインストールする必要があります。

  • Shap
  • eli5
  • Lime
  • Interpret
  • alibi

pip install alibi shap lime eli5 interpret

次に、いつもの依存関係を読み込みます。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

これで、おもちゃのデータセットを読み込むことができます。

csv = pd.read_csv("/add/your/path/here/to/the/madden/csv")

データセットからいくつかの行と列を見てみましょう。

Maddenデータセット

図2:データセット例 

物事をシンプルにするため、2、3の数値特徴だけを残すことにします。カテゴリ特徴は、エンコーディング技法と今回の議論の範囲にはそぐわない詳細を必要とします。

predictors = ["awareness_rating","throwPower_rating","kickReturn_rating",
              "leadBlock_rating","strength_rating","catchInTraffic_rating",
              "pursuit_rating", "catching_rating","acceleration_rating",
              "height","tackle_rating","yearsPro","throwUnderPressure_rating",
              "throwAccuracyDeep_rating","throwAccuracyShort_rating","speed_rating",
              "jumping_rating","toughness_rating","kickPower_rating",
              "kickAccuracy_rating","agility_rating","passBlock_rating","age"
             ]

csv[predictors].dtypes

awareness_rating            int64

throwPower_rating          int64

kickReturn_rating            int64

では、目標を定めましょう。

target = "totalSalary"

次に、使用するモデルを設定します。

from sklearn.linear_model import LinearRegression
from sklearn.neighbors import KNeighborsRegressor
from sklearn.ensemble import RandomForestRegressor
from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras.callbacks import EarlyStopping

上記の依存関係をインポートした後、機械学習モデルを初期化する前に、データをスケールして標準化し、ルーチンの訓練/テスト分割を実行しました。記事を最初から最後まで読みやすくするために、これらの手順は省略されていることにご注意ください。訓練とテストの分割により、訓練データは変数 x_trainと y_train、検証データはx_validと y_valid、そして最後にテストデータはx_testと y_testに格納されました。

今日扱う各モデルの設定に移ります。

lm = LinearRegression()
rf = RandomForestRegressor()
knn = KNeighborsRegressor(n_neighbors=10)
dnn = keras.Sequential([
    layers.Dense(units=30,activation="relu",input_shape=[scaled_data.shape[1]]),
    layers.Dense(units=20,activation="relu"),
    layers.Dropout(0.3),
    layers.Dense(units=10,activation="relu"),
    layers.Dense(units=1)
])

次に、それぞれのモデルのフィッティングをおこないます。

#Fitting the linear regression
lm.fit(x_train,y_train)

#Fitting the k-nearest neighbor regressor
knn.fit(x_train,y_train)

#Fitting the random forest model
rf.fit(x_train,y_train)

#Fitting the deep neural network
early_stopping = EarlyStopping(
    min_delta=0.001,
    patience=20,
    restore_best_weights=True
)

dnn.compile(optimizer="adam",loss="mae")

dnn.fit(
    x_train,y_train,
    validation_data=(x_validation,y_validation),
    batch_size = 60,
    epochs=100,
    verbose=0,
    callbacks=[early_stopping]
)

大域的な説明

線形回帰モデルに関する大域的な説明から始めましょう。使用する技法は、Permutation Importanceです。これは大域的なブラックボックス説明手法です。

import eli5
from sklearn.metrics import mean_squared_error
from eli5.sklearn import PermutationImportance
from eli5.permutation_importance import get_score_importances

線形回帰モデルの大域的な説明を得ます。

permutation = PermutationImportance(lm).fit(x_test,y_test)
eli5.show_weights(permutation,feature_names = predictors)

線形回帰モデルの大域的な説明

図3: 線形回帰モデルの大域的な説明

結果を一緒に解釈しましょう。Permutation Importanceは、データ集合の各列の独立性を仮定します。そのため、一度に1列ずつ変更してモデルのエラーメトリクスの変化を観察し、どの特徴が重要かを判断するのに利用できると考えています。もし特徴が重要であれば、その値をシャッフルすることでモデルのエラーメトリクスは増加し、逆に特徴が重要でなければ、その列の値をシャッフルした後にモデルのエラーメトリクスは実際には減少します。独立性の仮定が成り立たない場合は、これらの結果を割引いて解釈しなければなりません。

上の表では、重要な特徴は正の係数を持ち、重要でない特徴は負の係数を持ちます。スポーツ選手の経験年数であるyearsProには負の係数がありますが、私たちは実際にはそれが重要であることを知っています。モデルが私たちが気づいていない現象を発見したのでしょうか。それとも説明手法が私たちに真実の忠実な表現を与えていないのでしょうか。 

Permutation Importanceは、選手の経験を非現実的にシャッフルして、プロのレベルに対して若すぎたり、年齢より経験年数が長かったりする可能性があります。さらに、この手法では、データセットに存在する可能性のある相互作用を無視し、モデルの誤差の変化をすべてその特徴のみに帰属させます。したがって、その結果は非現実的である可能性があり、アルゴリズムを盲目的に適用するのではなく、注意深く理解する必要性を強調するものになっています。
ただし、長期的には、モデルの最も重要な特徴について貴重な洞察を得ることができます。この場合、スポーツ選手の捕球能力と敏捷性は最も重要な特徴の一部です。これは理にかなっています。アメフトでは、たとえ大きなプレッシャーを受けても、チームメイトからのパスをワイドにキャッチすることが求められるからです。さらに、ボールをキャッチした後は、できるだけ多くのライバルを避け、ボールを落とさないようにしなければなりません。したがって、これらの能力が重視されるのは理にかなっています。


局所的な説明

先に述べたように、局所的な説明は、各特徴がモデルがおこなっている個々の予測にどのような影響を与えたかを理解するのに役立ちます。

ディープニューラルネットワークが予想するリチャード・ルクンテの年俸について、局所的な説明を得ます。


リチャード・ルクンテ

図4:リチャード・ルクンテIII

まず、LIMEをインポートします。

LIMEとは、Locally Interpretable Model-Agnostic Explanationsの頭文字をとったものです。どの機能がモデルの出力に貢献しているのか、その貢献が出力を押し上げているのか押し下げているのかを説明します。 

import lime
from lime import lime_tabular
explainer = lime_tabular.LimeTabularExplainer(training_data = np.array(x_train),mode='regression',feature_names=predictors)
exp = explainer.explain_instance(data_row=scaled_data.iloc[test],predict_fn=lm.predict)
exp.show_in_notebook(show_table=True)



DNN LIMEの説明

図5:リチャード・ルクンテの給与に対するディープニューラルネットワークの給与予想のLIMEによる説明


まず、ルクンテの身体能力のどれが期待年俸を増やし、どれが期待年俸を減らしたかを見ることができます。私たちのニューラルネットワークは、ルクンテの靭性評価が彼の期待年俸を下げると予想しました。ルクンテの靭性評価は平均的であるため、これは当然のことです。  さらに、ディープニューラルネットワークはルクンテの強みを正しく認識し、ルカントの強みによって彼の給料が上がると予想しました。これが、私たちが期待するモデルの機能です。局所的な説明は、モデルを盲目的に信頼するのではなく、それを検証するための強力なツールです。


モデルにとらわれない説明とモデル固有の説明

基礎となるモデルの構造を知っている場合には、そのモデルアーキテクチャのために特別に設計された説明技法を使用することができます。これらは一般的にホワイトボックス説明手法と呼ばれています。実際には、ホワイトボックス説明手法は、ブラックボックス説明手法よりも計算効率が高くなります。

ブラックボックス説明手法はモデルにとらわれません。つまり、提示されたどんなモデルでも解釈し説明することができます。先ほど取り上げたLIMEアルゴリズムは、ブラックボックス説明手法の例であり、それはLocally Interpretable Model-Agnostic Explanationsという名前からわかります。 

基礎となるモデルの構造がはっきりしているときにホワイトボックス説明手法を使えば、モデルの振る舞いをより忠実に説明できるようになるかもしれません。一方、ブラックボックス説明手法は、モデルを説明する際に、ある程度の偏りを導入する可能性があります。ブラックボックス説明手法は、扱っているモデルの形式について、いくつかの単純化した仮定を立てます。もしこれらの仮定が破られれば、ブラックボックス説明手法は信頼できなくなります。

経験則として、もしあなたがモデルの基本的な特性を確信しているのであれば、長期的にはホワイトボックス説明手法を使用する方がよいかもしれません。 

SHAPライブラリにはSHAPブラックボックス説明手法の実装があります。以下にその1つを紹介しましょう。 

SHAPをインポートします。

import shap

SHAP値を計算します。

explainer = shap.Explainer(xgb.predict,scaled_data.loc[test:test_end,predictors])
shap_values = explainer(scaled_data.loc[test:test_end,predictors])

ブラックボックス的説明をプロットします。

shap.plots.beeswarm(shap_values)


SHAPブラックボックス的説明

図6:SHAPブラックボックスによるXGBモデルの説明


各行の幅は外れ値によって決定され、特徴の重要性に関する情報を伝えるものではありません。プロットに沿った各特徴の垂直方向の配置を考慮することで、特徴の重要性を評価します。上位の特徴ほど、SHAPアルゴリズムによって重要視されました。

さらに、ある特徴では青とピンクの点がうまく分離していますが、別の行では青とピンクの点がごちゃごちゃになっていることにご注目ください。点が混在している場合、通常、その特徴と他の特徴または特徴のセットとの間の相互作用効果の兆候です。簡単に言えば、SHAPプロットは、多くの情報を1つのプロットに要約するのに役立ちます。 

各点は各データポイントのシャープレイ値を表します。これにより、個々のデータポイントがモデルの予測にどのような影響を与えたかを、粒度レベルで素早く理解することができます。各点の色は、そのデータポイントがモデルの予測に与えた影響の方向と大きさを表しています。青はモデル出力の減少、ピンクは増加を示します。SHAPアルゴリズムは、特徴が独立していると仮定している、言い換えれば、データセット内の相互作用を無視していることにご注意ください。この仮定に反すると、アルゴリズムが信頼できなくなる可能性があります。 

ここで、XGBモデルのようなツリーベースのモデルのために設計されたホワイトボックス説明手法を考えてみましょう。ツリーベースのモデルを説明するために設計された特別なTreeExplainer()メソッドを使用します。

tree_explainer = shap.TreeExplainer(xgb)
tree_shap_values = explainer(x_test)

そして、ホワイトボックスの説明をプロットすることができます。

shap.plots.beeswarm(tree_shap_values)

SHAPホワイトボックス的説明

図7:XGBモデルのSHAPホワイトボックスによる説明

ブラックボックスSHAPの説明とホワイトボックスSHAPの説明から、最も重要な上位4つの特徴を比較してみてください。 


不一致問題の定義と問題の要因

さて、モデル説明とは何かを理解したところで、今度は不一致の問題に直接焦点を当てることができます。まず、何が不一致なのかを確認することから始めましょう。
特徴の重要性の説明の領域で、何が不一致を構成するのかを解剖してみましょう。
  • 特徴の順列:不一致の最初の形態は、特徴の順列が異なる場合です。もし、ワークフローにおいて、特徴の重要性の順番が重要な意味を持つのであれば、説明によって異なる順列が出現することは、極めて重要な論点となります。この点は、特徴の微妙な配列が分析に重要な意味を持つ場合に特に重要になります。
  • ベストランクの特徴セット:さらに深く掘り下げると、不一致はベストランクの特徴セットにも及んでいます。特徴の重要度の厳密な順列の厳守が緩和されると、注目は上位特徴の集合に移ります。同じモデルについて、異なる説明手法によって特定された上位3つ、5つ、または任意のn個の特徴の不一致は、分析の旅における分岐点の注目すべきポイントになります。
  • 係数符号の変動:多く説明手法の鼓動は、特徴量に割り当てられた係数にあります。これらは、望ましい結果に対する正または負の貢献を示します。同じモデルに対する2つの説明の間で、この係数の符号が変われば、ワークフローにおけるフラグとなります。このような変動は不一致の指標となり、モデルの内部構造をより詳しく調べることを促します。
  • 興味のある特徴間の相対的順序付け:興味のある特定の特徴に焦点を絞ると、不一致はさらに別の次元に進みます。特定の特徴の重要性を別の特徴と比較してベンチマークすることに重点を置いている場合、異なる説明におけるこれら2つの特徴の順序のずれは、ワークフローにおける不一致の戦場となります。

何が不一致ではないのか?

すべての格差が不一致を意味するわけではないことを認識することも、同様に重要です。では、説明が調和を保ちながら共存している例を探ってみましょう。

  • 重要度値の相違:異なる説明手法によって計算された特徴重要度の値が正確に一致しない場合、説明は真の不一致を回避します。重要なのは、多様なアルゴリズムがそれぞれ異なる計算をおこなうため、直接的な比較が難しいという認識です。ここで重視されるのは、重要度の数値的な等しさではなく、異なる説明から得られる一貫した洞察です。
  • 正確な値よりも一貫した洞察:非不一致の本質は、正確な数値の一致を執拗に求めるのではなく、一貫した洞察を追求することに根ざしています。目的は、すべての説明手法に、他の説明手法の重要度を正確に反映させることを要求することではありません。その代わりに、より広範な物語に焦点を移します。つまり、数値的には異なる説明であっても、一貫性があり信頼できるモデルの洞察に導くという点では収束していることを確認するのです。
  • モデルの複雑さと推定の課題:モデルの複雑さのタペストリーが展開するにつれて、基本的な真実が浮かび上がってきます。モデルの内部構造を正確に推定することの難しさは、正比例して増していきます。不一致とは、この本質的な複雑さを認識することです。複雑なモデルを前にすると、説明値の乖離は憂慮すべきことではなく、予想される課題となります。この視点は、透明性の追求が複雑さを増すAIの進化と一致しています。

説明手法間の不一致が生じる理由
説明手法間の不一致が生じる理由はたくさんありますが、いくつかのケースを一緒に考えてみましょう。

大域的な説明手法と局所的な説明手法の比較

不一致が見られる理由の1つは、大域的な説明と局所的な説明を比較している可能性があるからです。これは非常に単純なミスではありますが、この記事を読んだ読者の誰一人として、このようなミスを犯してはならないと信じたいです。大域的な説明と局所的な説明は、簡単に直接比較することはできません。アルゴリズムが中でどのように実装されているかを詳細に理解していない限り、大域的な説明と局所的な説明を比較することは得策ではないし、そうすることでおそらく異なる説明が得られるでしょう。

ブラックボックスとホワイトボックスの比較

さらに、ブラックボックス説明手法とホワイトボックス説明手法で比較することも、不一致の原因となりえます。ブラックボックス説明手法は、どのようなアルゴリズムでも説明できるという有用性を示そうとしていることを忘れてはなりません。それゆえ、モデルやモデルの振る舞いについて、ある単純化した仮定を立てます。このような仮定があるからこそ、ブラックボックス説明手法は堅牢で、さまざまな状況下でうまく機能するのですが、仮定が正しくない場合、説明手法に偏りが生じます。この偏りが、ブラックボックス的説明とホワイトボックス的説明を食い違わせるのかもしれません。 

特徴の順序を変更する

私たちの悩みはここで終わりではありません。不一致を生む狡猾な原因は、特徴の提示順の変更かもしれません。モデル入力の順序に敏感な説明技法もあれば、そうでないものもあります。例えば、相互情報量は入力の順番に敏感ではありませんが、SHAPは敏感です。したがって、SHAP説明手法は、同一のモデルを観察しても、自分自身と一致しない可能性があります。  

例えば以下は、2つの同じXGBRegressorから得られた2つのSHAP説明を出力しています。2つのモデルの違いは、同じデータセットから学習し、同じ目標を持つという点を除けば、入力として受け取る特徴の順番だけです。 


SHAP初期値

図8:SHAPの初期値


SHAPシャッフル

図9:特徴順位変更後のSHAP値

特徴量をモデルに見せる順番を入れ替えたところ、お互いの説明が食い違っていることがわかります。新しい情報が提示されたわけでもないのに、身長特集の重要性が急に高まりました。トップ3は変わりませんでしたが、ほとんどの特徴が上下し、順位が入れ替わりました。ブートストラップ技術やその他の再サンプリングやサブセット選択を使用するつもりなら、少なくともこの現象が普通であり、予想されることであることを認識しておくべきです。 


さらに、同じ説明技法の異なる実装は、その計算にわずかな違いがあるため、互いに一致しないことがあります。例えば、eli5のPermutation Importanceの実装は入力の順番に敏感ですが、sklearnの同じ説明手法の実装はそうではありません。これが可能なのは、同じ説明技法をさまざまな方法で実装できるからです。 

eli5のPermutation Importanceの実装が入力の順序に敏感であることを示すために、以下にeli5の順列重要度の実装を使用して得られた2つの説明を出力します。2つの同じXGBRegressorから結果を得ました。2つのモデルの違いは、同じデータセットから学習し、同じ目標を持つという点を除けば、入力として受け取る特徴の順番だけです。 


初期Permutation Importance

図10: 初期Permutation Importance


シャッフルされたPermutation Importance

図11: シャッフルされたPermutation Importance


kickPower_ratingは、当初は正の係数を持っていましたが、特徴量の順序を変更した結果、負の係数になりました。このような不安定な変動は、強い不一致とみなされます。最も重要な特徴が変わり、特徴間の相対的な順序も変わりました。

最後に、部屋の中の象の1頭は方法論の相違である可能性があります。これは、説明手法同士が同じモデルを説明しているにもかかわらず、不一致が生じるという興味深い現象を引き起こす極めて重要な要因です。各説明手法はモデルについて異なる測定基準を計算するため、それぞれ異なる観点からモデルを解釈する可能性があります。

幸いなことに、XGBには特徴の重要性を評価できる関数が実装されています。この関数を利用して、どの説明技法が真実を忠実に表現しているかを観察してみましょう。読者の便宜を図るため、上下にスクロールし続けなくてもいいように、これまでの説明結果をここに掲載しました。


XGBの基本真実

図12:XGB特徴の重要性

XGB Permutation Importance

図13:XGB Permutation Importance


SHAPホワイトボックス的説明

図14:SHAPホワイトボックス的説明


SHAPブラックボックス的説明

図15:SHAPブラックボックス的説明


説明可能なブースティングマシン

図16:グラスボックスツリーに基づくモデル特徴の重要性

認知度評価は、私たちのモデルにとって最も重要な特徴でしましたが、私たちのブラックボックス説明技術の小さなセットは、上位3つの特徴を完全に見逃し、それを説明することができませんでした。これは、説明は特徴の重要性の推定に過ぎず、絶対的な真実ではないことを痛感させます。さらに、yearsProは繰り返し上位にランクされているが、実際にはそれほど重要ではないことにご注目ください。これは、さまざまなテストで繰り返し上位にランクされる特徴が本質的に重要であるという単純な仮定に対して警告するものです。 

XGBモデルに適用したブラックボックス的説明は、適用したホワイトボックスの説明と矛盾しますが、最終的にはどちらの説明も間違っていました。つまり、このような状況で、どちらの説明手法がより忠実であるかを見極めることは、時間を完全に無駄にしたことになります。

また、説明可能なブースティングマシンをデータに適用して、グラスボックスモデルが特徴の重要性を評価するための代理として使用できるかどうかを調べました。データセットから最も重要な特徴を正しく特定することができましたが、特に説明しようとしているモデルがツリーベースのモデルでない場合は、常に実行可能なオプションとは限りません。しかし、残念なことに、グラスボックスモデルもyearsPro特徴を、そうでないにもかかわらず、有益であると判断しました。これは、説明手法が誤った情報に同意する可能性があることにも注意する必要があることを意味します。


ケーススタディ

MetaTrader 5端末からデータを抽出することから始めます。戦略では、効率的なデータ抽出と変換のために調整されたMetaQuotes Language 5 (MQL5)スクリプトを開発します。まずグローバル変数を宣言します。
//---Our handlers for our indicators
int ma_handle;
int rsi_handle;
int cci_handle;
int ao_handle;
int bbands_handle;
int atr_handle;

続いて、テクニカル指標の値を格納するための配列を作成します。これらのデータ構造体は、スクリプトの実行全体を通じて、指標の出力を系統的に捕捉、管理、活用する上で極めて重要な役割を担います。 

//---Data structures to store the readings from our indicators
double ma_reading[];
double rsi_reading[];
double cci_reading[];
double ao_reading[];
double bb_high_reading[];
double bb_low_reading[];
double bb_mid_reading[];
double atr_reading[];

続いて、CSVファイルの名前を作成します。 

//---File name
string file_name = "The Dissagrement Problem Data.csv";

そこから、要求したいバーの数を格納する変数を作成します。

//---Amount of data requested
int size = 10000;
int size_fetch = size + 50;

テクニカル指標ハンドラの設定に移ります。テクニカル指標を設定するたびに、使用する銘柄と時間枠を指定する必要があります。指標によっては、指標の期間、シフトパラメータ、平滑化法、指標を適用する価格を指定する必要があります。 

void OnStart()
  {
      //---Setup our technical indicators
      ma_handle = iMA(_Symbol,PERIOD_CURRENT,20,0,MODE_EMA,PRICE_CLOSE);
      rsi_handle = iRSI(_Symbol,PERIOD_CURRENT,60,PRICE_CLOSE);
      cci_handle = iCCI(_Symbol,PERIOD_CURRENT,10,PRICE_CLOSE);
      ao_handle = iAO(_Symbol,PERIOD_CURRENT);
      bbands_handle = iBands(_Symbol,PERIOD_CURRENT,120,0,0.2,PRICE_CLOSE);
      atr_handle = iATR(_Symbol,PERIOD_CURRENT,14);

スクリプトの実行を継続すると、その後の責任として、指標ハンドルから指定されたデータ構造体への値の転送がおこなわれます。

 //---Set the values as series
      CopyBuffer(ma_handle,0,0,size_fetch,ma_reading);
      ArraySetAsSeries(ma_reading,true);
      CopyBuffer(rsi_handle,0,0,size_fetch,rsi_reading);
      ArraySetAsSeries(rsi_reading,true);
      CopyBuffer(cci_handle,0,0,size_fetch,cci_reading);
      ArraySetAsSeries(cci_reading,true);
      CopyBuffer(ao_handle,0,0,size_fetch,ao_reading);
      ArraySetAsSeries(ao_reading,true);
      CopyBuffer(bbands_handle,0,0,size_fetch,bb_mid_reading);
      ArraySetAsSeries(bb_mid_reading,true);
      CopyBuffer(bbands_handle,1,0,size_fetch,bb_high_reading);
      ArraySetAsSeries(bb_high_reading,true);
      CopyBuffer(bbands_handle,2,0,size_fetch,bb_low_reading);
      ArraySetAsSeries(bb_low_reading,true);
      CopyBuffer(atr_handle,0,0,size_fetch,atr_reading);
      ArraySetAsSeries(atr_reading,true);

ファイルを書き始める前に、スクリプトにファイルハンドラを組み込むことが重要な準備作業となります。この基本的な手順は、出力ファイルのスムーズな作成と操作を可能にするために、必要なパラメータとメカニズムを設定することです。

      //---Write to file
       int file_handle=FileOpen(file_name,FILE_WRITE|FILE_ANSI|FILE_CSV,",");

この後、スクリプトの重要な段階は、過去の価格と指標値の配列を体系的にナビゲートし、指定したCSVファイルにデータをエンコードできるようにすることです。

for(int i=-1;i<=size;i++){
      if(i == -1){
            FileWrite(file_handle,"Time","Open","High","Low","Close","MA 20","RSI 60","CCI 10","AO","BBANDS 120 MID","BBANDS 120 HIGH","BBANDS 120 LOW","ATR 14");
      }
      
      else{
            FileWrite(file_handle,iTime(_Symbol,PERIOD_CURRENT,i),
                                 iOpen(_Symbol,PERIOD_CURRENT,i),
                                 iHigh(_Symbol,PERIOD_CURRENT,i),
                                 iLow(_Symbol,PERIOD_CURRENT,i),
                                 iClose(_Symbol,PERIOD_CURRENT,i),
                                 ma_reading[i],
                                 rsi_reading[i],
                                 cci_reading[i],
                                 ao_reading[i],
                                 bb_mid_reading[i],
                                 bb_high_reading[i],
                                 bb_low_reading[i],
                                 atr_reading[i]);
      }
    }
    FileClose(file_handle);
  }


市場データ

図17:MetaTrader 5端末からの市場データ


これでデータを扱い、例のデータセットから学んだ新しいスキルを適用する準備ができました。 

次に依存関係をインポートします。

#Import Dependencies
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import shap
import lime
from lime import lime_tabular
import eli5
from eli5.sklearn import PermutationImportance
from sklearn.feature_selection import mutual_info_regression

IntepretMLの依存関係を読み込みます。

from interpret import set_visualize_provider
from interpret.provider import InlineProvider
set_visualize_provider(InlineProvider())
from interpret import show
from interpret.blackbox import MorrisSensitivity

csvを読み込みます。

csv = pd.read_csv("/enter/your/path/here")

目標を設定します。

csv["Target"] = csv["Close"].shift(-30)

欠損値のある行を削除します。

csv.dropna(axis=0,inplace=True)

予測変数のリストを作成します。

drop = ["Time","Target"]
predictors = csv.columns.tolist()
predictors = [col for col in predictors if col not in drop]
predictors

データをスケーリングしてみます。

from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
print(scaler.fit(csv.loc[:,predictors]))
scaled_data =  pd.DataFrame(scaler.transform(csv.loc[:,predictors]), index = csv.index, columns = predictors)
scaled_data


スケール済み市場データ

図18:  スケール済み市場データ

ブラックボックスアルゴリズムの設定

#Black box models
from xgboost import XGBRegressor
from sklearn.linear_model import LinearRegression
from xgboost import plot_importance
from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras.callbacks import EarlyStopping

訓練とテストを分割します。

train = 0
train_end = 5000
test = train_end + 40

線形モデルを設定します。

lm = LinearRegression()
lm.fit(scaled_data.loc[train:train_end,predictors],csv.loc[train:train_end,"Target"])

XGBモデルを設定します。

#XGBModel
xgb = XGBRegressor()
xgb.fit(scaled_data.loc[train:train_end,predictors],csv.loc[train:train_end,"Target"])

ディープニューラルネットワークモデルを設定します。

dnn = keras.Sequential([
    layers.Dense(units=30,activation="relu",input_shape=[scaled_data.shape[1]]),
    layers.Dense(units=20,activation="relu"),
    layers.Dropout(0.3),
    layers.Dense(units=10,activation="relu"),
    layers.Dense(units=1)
])
early_stopping = EarlyStopping(
    min_delta=0.001,
    patience=20,
    restore_best_weights=True
)
dnn.compile(optimizer="adam",loss="mae")
dnn.fit(
    scaled_data.loc[train:train_end,predictors],csv.loc[train:train_end,"Target"],
    validation_data=(csv.loc[validation:validation_end,predictors],csv.loc[validation:validation_end,"Target"]),
    batch_size = 60,
    epochs=100,
    verbose=0,
    callbacks=[early_stopping]
)


ディープニューラルネットワークの大域的な説明を得る

ディープニューラルネットワークの説明を得るために、alibiパッケージを使用します。alibiパッケージには、累積局所効果(Accumulated Local Effects、ALE)として知られる説明技法の便利な実装があります。ALEは、これまでに検討したすべての説明技法を拡張します。堅牢で相関の強い特徴を扱えること、特徴の独立性の仮定が緩和されること、視覚的に解釈できること、計算効率が高いこと、そして他の説明手法とは異なり、線形性の仮定に依存していないことが理由です。ALEはデータ内の複雑な関係を捉えるのに適しています。   

まず、ALE値を計算します。

dnn_ale = ALE(dnn.predict, feature_names  = predictors,target_names=["Close 30 Steps"])

次に、ALEプロットを得る前に、入力データをNumPy形式に変換します。

X = scaled_data.loc[train:train_end,predictors].to_numpy()
dnn_alibi =dnn_ale.explain(X)
plot_ale(dnn_alibi,n_cols=4, fig_kw={'figwidth': 20, 'figheight': 10}, sharey=None)

ALEプロットは、各特徴の変化がモデルの出力にどのような影響を与えるかを解釈するのに役立ちます。例えば、以下にAwesome OscillatorのALEプロットを示します。このように、Awesome Oscillatorはディープニューラルネットワークが価格が下落するタイミングを予測するのに役立ちます。

ALE AO

図19:Awesome OscillatorのALEプロット


さらに、情報量の少ない特徴では、ALEプロットが水平線のようになり、その特徴の変化が目標にほとんど影響を与えないことを意味します。私たちのケースでは、相対力指数は参考になりませんでした。 

ALE RSI

図20:ALE RSI

モデルにとらわれないSHAP Explainerから大域的な説明を得る

explainer = shap.Explainer(xgb.predict,scaled_data.loc[test:,predictors])
shap_values = explainer(scaled_data.loc[test:,predictors])
shap.plots.beeswarm(shap_values)


XGBモデルのSHAPブラックボックスビーズウォームプロット

図21:  XGBモデルのSHAPブラックボックスビーズウォームプロット

ビーズウォームプロットは、オーサムオシレーターがこのデータセットで最も重要な特徴であることを教えてくれます。プロットの各行の幅は、単に外れ値で判断できるので、何の情報も伝えないことを覚えておいてほしい。さらに、青とピンクの点がごちゃごちゃになっていないことから、このデータセットには強い相互作用項が含まれていない可能性があることがわかります。

相互情報量による特徴の重要性

mi_scores = mutual_info_regression(scaled_data.loc[test:,predictors], csv.loc[test:,"Target"])
mi_scores = pd.Series(mi_scores, name="MI Scores", index=scaled_data.columns)
mi_scores = mi_scores.sort_values(ascending=False)
mi_scores

BBANDS 120 MID     1.739039

BBANDS 120 HIGH    1.731220

BBANDS 120 LOW     1.716019

MA 20                      1.525800

High                        1.172096

Open                       1.155583

Close                       1.143642

Low                         1.140613

ATR 14                     0.421772

AO                           0.232608

RSI 60                      0.181932

CCI 10                     0.016491

相互情報量は、上位4つの特徴に関する限り、私たちのSHAP説明手法と完全に食い違っています。これは、すでに混乱していた私たちの旅にさらに疑問を投げかけるだけです。さらに悪いことに、この場合、オーサムオシレーターが最も重要な特徴であるというSHAP説明手法は実際には正しかったのです。したがって、複数説明手法に頼ることは、実は諸刃の剣なのです。一方では、使用される説明から受け継がれる偏りから身を守ることになりますが、他方では、不一致が生じる確率的な空間をより大きくしてしまうことになります。  特定のデータセット、特定のモデル、その他多くの変数に依存するため、どちらのケースが経験的に優れているかを言うのは難しいです。

最後に、最後の大域的ブラックボックス説明手法として、モリス法則(Morris Sensitivity Analysis)について考えてみましょう。

msa = MorrisSensitivity(xgb, scaled_data.loc[train:train_end,predictors])
show(msa.explain_global())


モリス法則

図22:モリス法則

以下は、XGBモデルによる実際の重要度指標です。

XGB基本真実市場データ

図23:XGB市場データの重要性

移動平均はデータセットで最も重要な特徴であり、次いではオーサムオシレーターでした。つまり、この特定のケースでは、モリス法が相対的に言って最良の説明を与えてくれました。しかし、ほとんどの場合、グラウンドトゥルースにアクセスできない可能性があるため、より重視する説明をどのように選択するでしょうか。自分の決断にどれほどの自信があったでしょうか。もし本当の重要度表にアクセスできなかったら、どうやって重要度に関する決定を検証することができるでしょうか。 


結論

見てわかるように、ここには単純な答えはありません。データセットの形式と構造を考慮し、基礎となるモデルも考慮し、データ中の相互作用項の存在を説明し、そして何よりも、それぞれの説明の内部構造を機械学習実践者の指先で理解できるようにしなければなりません。さらに、制御された例では、すべての説明手法が間違っている可能性があることが観察されました。したがって、そのような状況では、不一致を解決しようとすることは無駄な時間の無駄になるでしょう。したがって、説明技法から得られる利益は、それがもたらす複雑さを必ずしも正当化するものではありません。しかし、時代が進むにつれて、より優れた説明技術が実現し、より優れたアルゴリズムが観察されるようになるかもしれません。


推薦

したがって、これらすべてを考慮した結果、不一致問題に対する最善の解決策は、一般化加法モデル(Generalised Additive Model、GAM)や説明可能なブーストマシン(Explainable Boosting Machine、EBM)のような解釈可能な機械学習モデルにもっと依存することかもしれないと私は確信しています。現在のところ、不一致問題のあらゆるケースに対する世界的に認知された解決策は存在しませんが、この問題に対する認識が高まるにつれて、私たちが構築した機械学習モデルを自信を持って説明できる日が来るかもしれません。 

MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/13729

MQL5を使ったシンプルな多通貨エキスパートアドバイザーの作り方(第7回):オーサムオシレーターシグナルを持つジグザグ MQL5を使ったシンプルな多通貨エキスパートアドバイザーの作り方(第7回):オーサムオシレーターシグナルを持つジグザグ
この記事の多通貨エキスパートアドバイザー(EA)は、オーサムオシレーター(AO、Awesome Oscillator)でフィルタされたジグザグ(ZigZag)指標を使用するまたは互いのシグナルをフィルタするEA(自動売買)です。
MQL5の高度な変数とデータ型 MQL5の高度な変数とデータ型
変数とデータ型は、MQL5プログラミングだけでなく、どのプログラミング言語でも非常に重要なトピックです。MQL5の変数とデータ型は、単純なものと高度なものに分類できます。単純なものについては前回の記事ですでに述べたので、今回は高度なものを特定し、それについて学ぶことにします。
知っておくべきMQL5ウィザードのテクニック(第13回):ExpertSignalクラスのためのDBSCAN 知っておくべきMQL5ウィザードのテクニック(第13回):ExpertSignalクラスのためのDBSCAN
DBSCAN (Density-Based Spatial Clustering of Applications with Noise)は、データをグループ化する教師なし形式であり、入力パラメータをほとんど必要としません。入力パラメータは2つだけであり、K平均法などの他のアプローチと比較すると利点が得られます。ウィザードで組み立てたEAを使用してテストし、最終的に取引するために、これがどのように建設的であり得るかを掘り下げます。
MetaTrader 5用のMQTTクライアントの開発:TDDアプローチ(第6回) MetaTrader 5用のMQTTクライアントの開発:TDDアプローチ(第6回)
この記事は、MQTT 5.0プロトコル用のネイティブMQL5クライアントの開発ステップを説明する連載の第6部です。今回は、私たちの最初のリファクタリングにおける主な変更点、私たちがどのようにしてパケット構築クラスのための実行可能な設計図にたどり着いたか、どのようにPUBLISHとPUBACKパケットを構築しているか、そしてPUBACK Reason Codeの背後にあるセマンティクスについてコメントします。