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

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

Einstein Discoveryで「Einsteinのアドバイス」をカスタム項目に実装するには

みなさんこんにちは。技術開発室の佐藤です。

Dreamforce'19のキーノートビデオを見ていると、Einstein関連機能がユーザにアドバイスする場面がしばしば登場します。例えば以下の動画では、Einsteinのおなじみの挿絵と共に、商談の見込み度数とその算定根拠がアドバイスされます。

https://www.youtube.com/watch?v=emxF6yuC9Q8&t=618

これらの機能は、Salesforce標準オブジェクトの結合関係に基づいて作成された機械学習モデルから導き出されたものと考えられます。標準オブジェクトとはつまり取引先(Account)とか商談(Opportunity)のことで、それらの関係は、例えば以下のようになっています。

https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/sforce_api_erd_majors.htm

Sales Cloudやその他の製品ではこれらの機械学習モデルが最初から有効になっており、入力されたデータを観察しているわけです。

一方で、カスタムオブジェクトや、標準オブジェクトに追加されたカスタム項目については、このような機能は実装されていません。しかしEinstein Discoveryを設定することで、開発者が意図した「Einsteinのアドバイス」を表示させることができます。今回はこの手順についてお話しさせていただきたいと思います。

Einstein Discoveryとは

Einstein Discoveryは、Einstein Analyticsの製品機能の一部です。本稿執筆時点では、以下のEinstein Analytics価格表の中の機能リストにEinstein Discoveryの名称があります。

https://www.salesforce.com/editions-pricing/einstein-analytics/

その機能はデータ分析と予測モデルの作成適用に大きく分類できますが、今回のお話では予測モデルの作成適用が主な対象となります。

ところでその「予測モデル」ですが、Einstein Discoveryでサポートしている予測モデルの種類は、現在時点では以下の2つです。(https://help.salesforce.com/articleView?id=bi_edd_model_about.htm)

  • Classification Use Case: logistic regression
  • Numeric Use Case: linear regression

え?たった2つ?と思われたかもしれません。この道の有名ライブラリScikit-learnのlinear_modelモジュールなどと比較すると少ないように思いますが、Einstein Discoveryは、最も基本的なミニマム構成を、ユーザにわかりやすく機能実装しているということなのでしょう。

シナリオを決める

ところで、そもそもカスタムオブジェクトのアドバイスって、何でしょうか?
いえいえ、予め決まっている話は何もありません。まずはこのシナリオから考えなければなりません。

動作検証ということで、以下のような、これ以上ない簡単なシナリオを考えてみます。

  • 入力値は Category ただひとつで、データ型は文字列で、値は A または B のみ。
  • 出力値はこれまたただひとつ SpeculatedValue で、データ型は数値。
  • 「Categoryが A だったら、SpeculatedValue は 4.0 付近に分布し、Categoryが B だったら、SpeculatedValue は 1.0 付近に分布する」という真理を仮に設定する。
  • Category が入力されたときに、その入力値が A だったら約 4.0 を、入力値が B だったら約 1.0 を予測値としてEinsteinにアドバイスしてもらう。

本来であれば、この「真理」は誰にもわからない秘密の法則で、多数のデータを用いて発見していくものですが、ここでははじめに設定します。なんとも回りくどい話で、かつミニマムですので全く味気がありません。しかしここまで自明なシナリオなら、意図したアドバイス(=予測結果)になっているかどうか簡単に確かめられるでしょう。ちょうどテストコードを書いて本来の機能コードの機能を確認していくような作業でしょうか。

レーニングデータを作る

次に、仮設の真理に基づくデータを作成します。

Einstein Discoveryでは最低400件のデータを必要とします。(https://help.salesforce.com/articleView?id=bi_edd_limits.htm)

今回は以下のようなデータを作成してみました。

date        category  value
2018-01-01  A         3.5435852645574193
2018-01-02  B         1.275152805839512
2018-01-03  A         5.40014361858529
2018-01-04  B         0.6804527791760495
2018-01-05  A         3.212071974642821
2018-01-06  B         0.02215664060029765
2018-01-07  A         2.6168577420923445
2018-01-08  B         1.5697355255078034
2018-01-09  A         3.738544793192011
(以下同様に、2年分、730件)

要するに category が A だったら value が 4.0 を中心に、B だったら 1.0 を中心に分布しているだけです。プロットすると以下のようになりました。まさに仮設した真理から作り出されたデータです。Einstein Discoveryの予測モデル作成機能はきっと容易にこの真理を見つけ出してくれるはずです。

f:id:masashi-sato-flect:20200109162618p:plain

Einstein Analyticsデータセットを作成

次にEinstein Analyticsにこのデータをインポートします。

Einstein Analyticsには無償の開発者エディションがありますので、今回はこれを利用しました。

https://developer.salesforce.com/promotions/orgs/analytics-de

ログイン後、以下のTrailheadの手順にならって作成したCSVをインポートします。

予測モデルの作成

ここからインポートしたデータをもとに予測モデルを作っていくわけですが、はじめにインポートしたデータセットの「Create Story」を選択します。

f:id:masashi-sato-flect:20200109162709p:plain

すると設定項目をいろいろ問い合わせる一連のダイアログが表示されます。

最初は Start an Einstein Discovery Story ですが、ここは以下のように設定します。

f:id:masashi-sato-flect:20200109162729p:plain

Story Goalと言われても困ってしまいますね。これはEinstein Discovery固有の概念と考えたほうが良いと思います。予測モデルの期待動作は言わずとしれた予測で、これ自体の評価は「正確かどうか」に尽きるでしょう。しかしここで言うStory Goalは、予測対象の数値を「どうしたいのか」という、予測モデル作成の背景に関する質問なのです。売上や利益なら「最大化したい」とか、故障率や返品率なら「最小化したい」という意図があると思いますが、その意図を入力します。

なぜこういう設定が必要なのでしょうか?それはEinstein Discoveryが「現状成果の構成要因は何か?もっと良くするにはどうすればよいのか?」を探るためのツールとして設計されており、予測モデルは「こうすればいいよ」というアドバイスを出力するために使われることになっているからです。

ここでは「Valueを最大化する」という目標を設定します。その他に、この予測モデルの名称と、Einstein Analytics上での保存先を設定します。

次は What type of story are you interested in? ですが、今回のゴールは予測値をアドバイスしてもらうことですので、 Insights & Predictions を選択します。

f:id:masashi-sato-flect:20200109162749p:plain

次は How would you like to select the fields for your story? ですが、ここでは Automated を選択します。

f:id:masashi-sato-flect:20200109162858p:plain

以上を入力すると「Story」が出来上がります。Einstein Discoveryでは、これがすなわち、予測モデルです。

f:id:masashi-sato-flect:20200109162920p:plain

どんな予測モデルを作ったの?

出来上がった予測モデルを観察してみましょう。クリックすると、以下のような画面になります。

f:id:masashi-sato-flect:20200109162940p:plain

機械学習に多少の覚えのある筆者でしたが、この画面を読み解くには、Einstein Discoveryの設計背景を少々洞察する必要がありました。この図はつまり、category の選択が、 value 最大化という目的に「大きく影響している」と言っているのです。もちろんそうなるようにデータを作ったのだから当然ですが、この「Story(=予測モデル)」、何を根拠に数値を出しているのでしょうか?

そのタネ明かしは、「R Code」の中にありました。

f:id:masashi-sato-flect:20200109163019p:plain

ポイントは以下の部分です。

converters <- list(
    `date` = converter.date(c("2018/01" 中略),
    `category` = converter.text(c("B", "A"), 中略)
)

predict <- function(data) {

    predictions <- (
        2.3825128790222143 +
        (data[[1]] == 0 & data[[2]] == 0) * 0.11883377753580698 +
        (data[[1]] == 0 & data[[2]] == 1) * 0.11883377753580698 +
        中略
        (data[[2]] == 0) * -1.4558662462697816 +
        (data[[2]] == 1) * 1.4458832575039133
    )

筆者はR言語には詳しくありませんが、上記のコードが以下のような処理を実行していることは容易に読み取れます。

  • 平均 2.3825128790222143
  • category が B なら、 -1.4558662462697816 (=~ 0.92)
  • category が A なら、 1.4458832575039133 (=~ 3.83)
  • あとは category と date によって、細かい値調整

まさに最初に仮設した真理をだいたい反映する内容になっていると言えます。 これこそが予測モデルの正体のようです。 Einstein Discoveryがやっていたことは、モデル作成という名の、係数調整だったのです。(言われてみれば、Linear Regressionのトレーニングとは、そういう作業にほかなりませんね。。。)

予測モデルをデプロイする

予測モデルはできました。次はデプロイ作業です。デプロイとはつまり、Salesforceのカスタムオブジェクトにこの予測モデルを仕掛け、どこかの項目に「A」や「B」と入力されたら、予測値を別の項目に設定するように仕掛ける作業ということになります。このためには、カスタムオブジェクトを定義する必要があります。

まず以下のような項目を持つカスタムオブジェクト Csv01__c を定義します。例によって確実な動作確認のための味気ない最低限の内容です。

Nane           Auto Number
Category__c    Text(16)
FinalValue__c  Number(9,9)

FinalValue__cという項目ですが、これはEinstein Discoveryに予測に対する実測値を伝えるための項目です。これについては後述します。

カスタムオブジェクトを定義したら、以下の「Deploy Model」をクリックして作業を開始します。

f:id:masashi-sato-flect:20200109163210p:plain

新規デプロイを選択し、適当な名前をつけます。

f:id:masashi-sato-flect:20200109163227p:plain

次に、予測モデルを適用するカスタムオブジェクトとして「Csv01__c」を指定します。

f:id:masashi-sato-flect:20200109163249p:plain

次に、予測モデル作成で使用したデータの項目と、カスタムオブジェクトの項目の対応関係を設定します。

(なお、ここで「date - Create Date」の対応関係が設定されているのはなぜかと思われたかもしれませんが、これは「最低2項目の対応関係が必要」というEinstein Discoveryの制約をかわすための措置ですので、ここでは気にしないでください。)

f:id:masashi-sato-flect:20200109163303p:plain

次は予測モデルの予測結果を設定する項目の指定です。Einstein DiscoveryではaiPredictionFieldと呼ばれる特別なメタデータ属性を設定した読み取り専用項目に予測結果を設定します。既存項目を指定することもできるようですが、ここでは項目名を入力してEinstein Discoveryに適当な新規項目を追加してもらうことにしましょう。

f:id:masashi-sato-flect:20200109163320p:plain

次は予測モデルを適用するレコード条件の設定ですが、ここでは「全レコードにひとつの予測モデルを適用」を指定します。

f:id:masashi-sato-flect:20200109163336p:plain

次に「ユーザが入力する、予測モデルの入力情報となる項目はどれか」を指定します。今回の場合は category の1項目だけです。

f:id:masashi-sato-flect:20200109163609p:plain

次に指定するのは、「実測値」です。ここでは、カスタムオブジェクト作成時に設定した項目 FinalValue__c を指定します。また、 0 を超える実測値が入力された場合に、実績値の入力が完了したと認識するように設定します。実測値を指定することにより、予実比較のレポートを作成することができます。これについては後述します。

f:id:masashi-sato-flect:20200109163628p:plain

ようやくすべての設定が完了しました。しばらく待つと、デプロイ完了のメッセージが表示されます。

f:id:masashi-sato-flect:20200109163654p:plain

Salesforce Platform側の準備

以上でEinstein Discovery側の準備は完了しましたので、次はSalesforce Platform側の作業です。

まずはじめに、Einstein Discoveryと、カスタムオブジェクトを操作するユーザが必要な項目にアクセスできるように項目レベルセキュリティを設定します。ここで注意ですが、Einstein Discoveryは「Analytics Cloud Integration User」というプロファイルですので、これに対しても項目レベルセキュリティを設定する必要があります。ここでは以下のように設定しました。

Field               System Administrator  Analytics Cloud Integration User
---------------------------------------------------------------------------
SpeculatedValue__c  read only             read only
FinalValue__c       read write            read only

ページレイアウトにも項目を追加しておきます。

「Einsteinのアドバイス」のUIを追加する

次は冒頭にご紹介したような「Einstienのアドバイス」を表示する画面上の導線設定です。これはカスタムオブジェクトのLightning Record Pagesを設定することによって行います。

Lightning Componentsから「Einstein Predictions」をドラッグしてオブジェクト詳細の右側にドロップし、このコンポーネントの設定「Prediction」に、作成した予測モデルの名称 csv01 SpeculatedValue を設定します。

f:id:masashi-sato-flect:20200109163719p:plain

実験してみる

以上で長い準備作業が完了しました。早速テストしてみましょう。カスタムオブジェクトを新規作成し、Categoryに「A」と入力して保存します。

f:id:masashi-sato-flect:20200109163737p:plain

するとEinsteinのアドバイスが表示されました。「予測値は3.95で、そのうちCategoryがAであることによる要因が1.45」と、前述のR言語のコードに書かれた係数値の通りの内容です。

f:id:masashi-sato-flect:20200109163752p:plain

なお、この段階でSpeculatedValueの表示更新が滞る現象が何度か観察されましたが、原因についてはわかりませんでした。APIでクエリしてみると、以下のように正しい値が取得できました。

f:id:masashi-sato-flect:20200109163811p:plain

次にCategoryをBに変更してみましょう。こうすると「予測値は1.01で、CategoryがBであることが要因であり、改善のためにはCategoryをAにすることが考えられる」という内容のアドバイスになりました。

f:id:masashi-sato-flect:20200109163825p:plain

実に長い道のりでしたが、ようやく当初の目標通りEinsteinのアドバイス機能をカスタム実装することができました。

実測値との比較

詳細は割愛しますが、カスタムオブジェクトのFinalValueを設定することで、実測値との比較も可能です。以下のようなダッシュボードを作成してくれます。

f:id:masashi-sato-flect:20200109163922p:plain

ここでは予測モデルが適用された2つのレコードについて、 SpeculatedValue に設定された Predicted Value と FinalValue に設定された Actual Value がプロットされ、予測が概ね正確に行われていることが観察できます。また一定期間運用すれば、 Accuracy Trend で予測精度の時系列変化を観察することもできるでしょう。

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