フレクトのクラウドblog re:newal

http://blog.flect.co.jp/cloud/からさらに引っ越しています

Einstein Discovery と Einstein Next Best Action を連携する

こんにちは。エンジニアの山下です。

今回は Salesforce の Einstein Discovery と Einstein Next Best Action を連携させ、Lightning Page 上で統計手法ベースのレコメンデーションの出し分けを行う方法について書こうと思います。

Einstein Discovery と Einstein Next Best Action の概要

Einstein Discovery は回帰分析を行うためのモデルをノーコードで構築できるプラットフォームです。モデル構築のための入力データを事前に準備しておく必要はありますが、構築自体は Salesforce 上の簡単な操作のみで実施でき、かつ作成されたモデルの各種メトリクスや推論過程を確認するためのダッシュボード等が完備されています。

画面からの利用方法等の基本的な事柄については以下の Trailhead に十分書かれているため、そちらを参照ください。

trailhead.salesforce.com

もう一方の Einstein Next Best Action ですが、こちらは Flow で定義したロジックに則って Lightning Page 上にレコメンデーションを表示することができるという機能になります。

こちらも基本的な内容は公式ドキュメントの ウォークスルー があれば十分だと思うので、必要であればそちらを参照ください。

統計手法ベースの推論プラットフォームと Flow ベースのレコメンデーション表示機能ということで、この2つのサービスは非常に噛み合いがよいです。これらを組み合わせることで、統計情報を根拠としたレコメンデーション表示機能を実現できるというシナジーを持っています。

連携方法

Einstein Discovery と Einstein Next Best Action の連携方法は2つあり、いずれの方法も Einstein Next Best Action に設定する Flow の Action を利用したものになります。具体的には、

  1. Core Action を利用して連携する
  2. APEX Action を利用して連携する

のいずれかを選択することになります。

2 の方法では APEX コードの管理が必要になるため、特に理由がなければ 1 の方法を採用するのが吉です。1 の方法なら こちら の公式ドキュメントに従って Flow Builder を操作するだけで連携できます。

なのですが、実は筆者が 1 の方法に気づいたのが 2 の方法で実装を終えた後だったという悲しい事情があり、せっかくなので APEX Action を利用した方法も紹介しておきます。

APEX から Einstein Discovery API を利用する

そもそも Einstein Discovery に関連する API 群は Smart Data Discovery というリソースの下で管理されており、APEX でも ConnectApi.SmartDataDiscovery という名前空間にあるクラスを利用することで Einstein Discovery API が利用できるようになっています。このあたりの内容は公式ドキュメントの こちら にサンプルコード付きで書かれています。

今回は推論機能を利用したいので ConnectApi.SmartDataDiscovery.predict() を使います。以下が推論実行のための最小限の APEX コードです。

global class GetPredictionFromEinsteinDiscovery {
  @InvocableMethod
  public static List<Double> get(List<Id> ids) {
    ConnectApi.SmartDataDiscoveryPredictInputRecords predictInput = new ConnectApi.SmartDataDiscoveryPredictInputRecords();
    predictInput.predictionDefinition = '(your-prediction-definition-id)';
    predictInput.records = ids;

    ConnectApi.SmartDataDiscoveryPrediction response = ConnectApi.SmartDataDiscovery.predict(predictInput);
    ConnectApi.SmartDataDiscoveryPredictObject prediction = (ConnectApi.SmartDataDiscoveryPredictObject) response.predictions[0];

    return new List<Double>{
      prediction.prediction.total
    };
  }
}

推論結果は prediction.prediction.total に格納されます。なお、上記のコードでは省略していますが、predictInput.settings に各種設定を施すことができ、推論過程などの情報を追加で得ることができます。

これで推論結果が得られるので、あとは Einstein Next Best Action 側でこの結果を元に条件分岐を行えば OK です。

というわけで、連携できました。簡単でしたね。

そう思っていた時期が私にもありました

そうは問屋が卸しません。難しいのはここからです。

何が難しいかというと、Einstein Discovery API のレスポンスパラメータの意味と仕様を理解するのが難しいのです。これは Core Action でも APEX Action でも同じです。そんなバカなと思うかもしれませんが、実際筆者が最も苦労したポイントがこれでした。

なぜ理解するのが難しいのかというと、ひとえに公式ドキュメントの説明が不十分なためです。レスポンスパラメータの簡単な説明は こちら に一通り書いてあるのですが、あまりにも簡単に書かれており、実際使ってみると戸惑うことが多いです。

どれくらい戸惑うかというと、先ほど示したサンプルコードで推論結果として得ていた total ですが、公式ドキュメントの説明は以下のようになっています。

Final prediction value.

筆者は Einstein Discover で二値分類モデルを作成したのですが、モデル作成時点で画面には以下のような表示があり、二値化の閾値が 0.495 であることがわかります。

そして実際に返ってきた total の値が以下です。

18.518670863527415

二値分類モデルなのに 0 or 1 でないどころか 0-1 の範囲ですらない値が返ってきています。なんですと ... 。

何か見落としがあるのかと思い、公式ドキュメントを見直してみましたが、残念ながら上記以外で total について説明している文言は見当たりませんでした。

Einstein Discovery と Einsten Next Best Action を連携させるためには、この値をベースとした条件分岐のロジックを Flow に実装しなければならないため、この謎を何とか解明しなければなりません。

その他、レスポンスに以下のような変数が存在することもわかりましたが、こちらも公式ドキュメントの説明から内容を理解することはできませんでした。

パラメータ 公式ドキュメントの説明
baseLine double Baseline from where the prediction started. Basically the average if there were no model.
other double Unexplainable portion of the final prediction value.

というわけで、変数名と公式ドキュメントの雰囲気だけの説明を元にレスポンスパラメータを解析する必要性が生じました。つらい。

試行錯誤の結果、幸いにも謎は概ね解けたので、第2第3の被害者がでないことを祈って、その解析結果を以下に書いておきます。

prediction.prediction.total

結論から述べると、total の値は百分率で表現された値でした。つまり total が 18.51 であれば、実際の推論値は 0.1851 という具合です。

どうやってこの結論に辿り着いたかというと、Einstein Discovery には作成したモデルを画面上でお試し実行できる機能があり、こちらを利用している際にわかりました。該当画面のキャプチャ画像が以下です。

画面右に入力パラメータを設定するペインがあり、その入力を与えた場合に出力がどうなるかを中央ペインにあるダッシュボードで確認できるという構成になっています。上記画像の場合、中央ペインの Model Overview に表示されている 0.602 という値が推論結果になります。

この画面を使えば入力と出力の関係が確認できるのですが、この画面で与えた入力と同じ値を API で入力した場合どうなるのかを確認したところ、

60.20929180562907

という total の値が得られたため、この仮説に辿り着きました。その後、入力内容を変えて何度か検証を繰り返し、正しいという確信に至ったという形です。後述する otherbaseLine といったパラメータも同様に全て百分率で表現されているのでご注意ください。何故そんな紛らわしいことを ... 。

ちなみに二値分類モデルの場合でもレスポンスは 0-1 の範囲の推論結果(確率)のみで、二値化の処理は APEX ないし Flow 側に自前で実装する必要があります。ダッシュボード上に表示されている二値化の閾値は、Lightning コンポーネントなどでモデルを利用した場合に適用されるもので、API 経由で推論を利用した場合には適用されないようです。

Einstein Discovery のアルゴリズム(線形回帰モデル)

total の謎は解けました。実のところ、API の利用に必要な知識は total だけで十分で、その他のパラメータは全て解析用のものになります。従って、実益のみが必要な方は以降は読み飛ばしてしまっても問題ありません。

以降で説明する total 以外のパラメータは解析用のため、その意味を理解するには Einstein Discovery で使用されるアルゴリズムについての知識が必要です。なので、まずは Einstein Discovery で使用されているアルゴリズムについて簡単に説明します。

Einstein Discovery では推論に使用するアルゴリズムを選択できるのですが、これらのアルゴリズムは線形回帰モデルをベースとしています。線形回帰モデルでは推論対象が y = ax + b のような式(をもう少し複雑にした式)に従うと仮定して処理を行います。実際には以下のような形の式を仮定しています:

 \displaystyle y = a_0 x_0 + a_1 x_1 + ... + a_n x_n + b

我々が求めたいのは  y の値で、変数  x_n に入力値を当てはめて  y の値を得るのが最終的なゴールになります。この最終的に得たい値  y を目的変数といい、そのために入力する値  x_n を説明変数といいます。 a_n b は事前に収集しておいたデータから導き出した定数で、ひとまとめに回帰係数と呼ばれます。

Einstein Discovery ではこの線形回帰モデルをうまく活かして各説明変数に対応する事象がどのくらい影響力を持つかをダッシュボード上で確認できるようにしています。画面キャプチャを以下に示します。

上の画像の下部に書かれている各事象が説明変数に該当するイメージとなります。

prediction.prediction.baseLine

線形回帰モデルが前提とする式の  b にあたる値が baseLine です。言い換えると式の切片にあたる値です。

baseLine は推論結果に対して無条件に足される値のため、公式ドキュメントの以下の説明に符合しています。

Baseline from where the prediction started. Basically the average if there were no model.

線形回帰モデルと Einstein Discovery のモデルお試し実行画面に表示される以下の Waterfall チャートを合わせて考えると、まず間違いないと思います。チャートからは baseLine に説明変数分の数値(緑のブロック)が加算された結果が最終推論結果になっていることがわかります。

ちなみに baseLine および other の値は APEX で predictInput.settings を設定した場合のみレスポンスに含まれます。デフォルトの設定では null になるので、自身で追試したいという方はご注意ください。

prediction.prediction.other

other の話をするには middleValues の話をしなければなりません。

middleValues は Einstein Discovery API のレスポンスに含まれる比較的理解が容易なパラメータです。公式ドキュメントの説明は以下のようになっています。

List of top predictors that contribute to the prediction.

要するに説明変数の中で最も推論結果への貢献度が高いものを上から順に集めたものです。middleValues の各項には最終推論結果に加算された対象の説明変数の値(先の Waterfall チャートの緑ブロックに該当する値)などが格納されています。なお、middleValues に格納される説明変数の数は predictInput.settings にて指定可能です。

other はこの middleValues に含まれていない説明変数の値の合計値です。つまり貢献度の高い説明変数は詳細に、それ以外はサマリとして別々に取得できるような設計になっているというわけです。

実際に筆者が API で取得した結果を例として挙げると、

// 説明上不要な情報は除いています
middleValues=(
  ConnectApi.SmartDataDiscoveryPredictCondition[
    value=11.385852361102891
  ],
  ConnectApi.SmartDataDiscoveryPredictCondition[
    value=-7.323287318983713
  ],
  ConnectApi.SmartDataDiscoveryPredictCondition[
    value=3.005398168300985
  ]
),
other=0.4877605766188733,
baseLine=10.962947076488378,
total=18.518670863527415

のようになっており、middleValuesotherbaseLine を足し合わせて検証したところ、ちゃんと total に一致するようになっていました。

まとめ

今回の話をまとめると、

  • Einstein Discovery と Einstein Next Best Action は Flow Action で連携できる
  • Einstein Discovery API の推論結果は百分率で返されるので注意する

というところかなと思います。

Einstein Discovery は Salesforce の中では比較的渋いサービスのため、インターネット上にあまり詳細な情報がないという点が今回のネックでした。少なくとも公式ドキュメントにはちゃんとした情報が載っていてほしいという気持ちはあります。

回帰分析自体はそれなりに使いどころがある気がするので、今後、細かい使い勝手が改善することを期待したいですね。第2第3の被害者を出してはいけない。

以上です。最後までお読みいただき、ありがとうございました。

2024/05/16 11:20 頃に記事の内容を一部更新しました。