前の章では、コール・センター・エージェントが顧客にオファーを提示できるように、オファーをCRMアプリケーションに返すアドバイザを追加しました。顧客にオファーが提示された後は、顧客がそのオファーを受け入れたかどうかを追跡してから、オファーの提示と受入れのプロセスに関するループをクローズする必要があります。フィードバックのループは、様々な方法によって様々なタイミングでクローズされる場合があります。デシジョンやオファーが実行されてから数日から数週間後に結果が判明することもあります。それだけの時間が経過した後でも、肯定的な結果のみが判明し、否定的な結果は不明な場合が多くあります。フィードバックの直接的な取得元は顧客だけでなく、通話を処理するエージェントに加えて、サービス、契約および請求を処理する業務システムやバッチ・プロセスに及ぶ場合があります。
インライン・サービスに対するフィードバック・ループは、インフォーマントの使用を介してReal-Time Decision Serverに通知することでクローズされます。
この章の内容は次のとおりです。
一般的にオファーの存続期間において、成功を追跡する観点から見て有意義なイベントが複数あります。たとえば、Credit Cardオファーの存続期間では、次のようなイベントが存在する場合があります。
オファーの提示
顧客による興味関心
カード発行の申込み
カードの受領
カードの使用
これらのイベントは、顧客がクレジット・カードを使用したときが本当の成功とみなす考えに基づいています。最終的な目標は、顧客による興味関心、カード発行の申込みおよびカードの受領だけではなく、多くの顧客がカードを使用することにあります。カードが使用されることで企業に売上がもたらされるからです。
一般的に、オファーの提示直後のイベントは追跡が容易です。たとえば、コール・センターにおいてエージェントがオファーを提示した時点で、顧客が示す興味関心の程度を測定できます。オファーがWebサイトに提示されている場合は、クリック・イベントが興味関心のインジケータになります。
オファーの存続期間の後半にあるイベントほど、オファーを追跡して妥当性を評価することが難しくなる場合があります。そのため、プロジェクトを開始して即座に結果の出るフィードバック・ループのみをクローズし、システムが熟成するにつれて下流のイベントを追加するのが一般的です。Oracle RTDでは、開始直後のフィードバックのみでも、マーケティングの意思決定に大きく貢献できます。
この項の内容は次のとおりです。
イベントは、選択肢グループのレベルで定義します。イベントはグループ階層の任意のレベルで定義できますが、ルートに近い最上位レベルで定義するのが一般的です。
ここではイベントを2つ作成します。1つはオファーが顧客に提示された事実を示すイベントで、もう1つはオファーが受け入れられた事実を示すイベントです。このチュートリアルでは、アドバイザの結果として選択されたすべてのオファーが提示され、オファーの受入れがただちに判明することを前提にしています。
選択肢グループにイベントを定義する手順は、次のとおりです。
「Inline Service Explorer」の「Choices」で、「Cross Selling Offer」選択肢グループをダブルクリックします。
「Choice Events」タブを選択します。「Add」をクリックして、イベントを2つ追加します。最初のイベント名はpresented
、2番目のイベント名はaccepted
にします。これらのイベント名は単なるラベルで、オファーの内部状態には対応しないことに注意してください。これらのイベントは選択肢イベント・モデル(次の項で説明)で使用され、これらのイベント名はそこで意味を持ちます。
イベントごとに、ドロップダウン・リストを使用して、「Statistic Collector」を「Choice Event Statistic Collector」に設定します。これはデフォルトの統計コレクタです。このコレクタによって、各イベントに関する統計が収集されます。
「Event History (days)」が「Session Duration」に設定されていることを確認します。
「Value Attribute」は空欄のままにします。
これは、イベントの自動処理に使用されます。このチュートリアルでは、フィードバック・インフォーマントのロジックによりイベントを記録します。
「File」→「Save All」を選択します。
ここまでで、イベントの定義が完了し、統計を追跡する準備が整いました。イベントでは、統計の追跡に加えて、様々な要因(顧客の特性、通話とエージェント、およびオファーの成功や失敗)間における相関関係に関する学習が自己学習モデルにおいて行われます。この知識は次の2つの目的で役立ちます。
マーケティング担当者や営業担当者の洞察力と把握力の向上
様々な状況で最適なオファーを提示する自動予測
このチュートリアルでは、これらの両方に対する使用方法について説明します。
選択肢イベント・モデルを定義する手順は、次のとおりです。
「Inline Service Explorer」で、「Models」を右クリックしてから、「New Choice Event Model」を選択します。新しいモデルの名前をOffer Acceptance Predictor
に設定し、「OK」をクリックします。
モデルのエディタで、「Default time window」の選択を解除し、「Time Window」を1週間に設定します。
「Choice Group」で「Cross Selling Offer」を選択します。
このグループは選択肢階層の最上位グループで、このモデルを使用してオファーの受入れを追跡します。
「Base Event」で「presented」を選択します。前項で、選択肢グループのこれらのイベント名を定義したことを思い出してください。
このイベントが、成功を測定する対象イベントになります。オファーが受け入れられたかどうかは、オファーの提示後に追跡します。
「Positive Outcome Events」で、「Select」をクリックして「accepted」を選択し、「OK」をクリックします。このチュートリアルでは、これが唯一の肯定的な結果です。複数のイベントを追跡する場合は、ここで追加します。
必要に応じて、イベントのラベルをオファー指向の名前に変更できます。
選択肢イベント・モデルには、他にも役に立つ設定があります。「Attributes」タブには重要な設定が2つあります。1つはパーティション化属性でもう1つは除外属性です。次の各項では、それらを含めて各種設定について説明します。
この項の内容は次のとおりです。
パーティション化属性は、大きく異なる結果をもたらす区分に従ってモデルを分割する目的で使用されます。たとえば、同じオファーでも、Web提示とコール・センター提示では、その受入れ特性が大きく異なる場合があります。その場合は、提示チャネルをパーティション化属性として設定できます。
パーティション化属性は複数設定できますが、メモリー使用量に影響する場合があることに注意してください。各パーティション化属性では、属性値の数だけモデル数が倍増します。たとえば、モデルに3つの値を持つパーティション化属性と4つの値を持つパーティション化属性がある場合、メモリーの使用量はパーティション化でないモデルの12倍になります。それでもパーティション化が重要な場合は、それによってモデルの予測性能と説明性能が大きく向上するため、必ずパーティション化属性を使用してください。
モデルへの入力として意味がない属性があります。たとえば、Reason Analysisモデル(第3.1.2項「Decision Centerにおける分析結果の表示」を参照)では、入力として理由コードを持つことで、理由コードと通話理由の選択肢との間に相関関係が検出されました。この関係全体は、第2.9.4項「選択肢の選択のためのロジックの追加」で作成したロジックの当然の結果です。この相関関係は人為的であり有意義な洞察でないため、理由コードをモデルから除外しました。
他のモデルでは理由コードが重要な要素となる場合があるため、除外が適切でない場合があることに注意してください。たとえば、Offer Acceptance Predictorモデルでは、オファーの受入れと理由コードとの間における相関関係に注目する必然性があります。
「Learn Location」タブで、モデルの学習をプロセス内のどのタイミングで実行するかを設定します。ほとんどの場合は、デフォルトの「On session close」が適しています。セッションにおいて複数の状態から学習を行う必要があるときは、特定の統合点において学習を設定すると有効な場合があります。
選択肢イベント・モデルの定義が完了し、使用する準備が整いました。モデルに適切な情報を入力するには、ループをクローズするロジックを完成する必要があります。
提案されたオファーをモデルで使用可能にするには、オファーIDをセッションで記憶する必要があります。オファーIDはフロントエンド・クライアント側で記憶される場合もあるため、この手順は必須ではありませんが、ここではフロントエンドの機能を前提にしません。オファーの記憶には単純な文字列属性を使用するだけですが、複雑な場合は配列を使用して複数の選択肢を記憶します。
提案されたオファーを記憶する手順は、次のとおりです。
「Inline Service Explorer」で、「Entities」の下の「Session」をダブルクリックします。
「Add Attribute」をクリックして属性を追加し、Offer Extended
と命名します。
属性の説明を入力します。「Show in Decision Center」および「Use for Analysis」の選択を解除します。「OK」をクリックします。
この操作を行う理由は、現時点でこの属性を内部変数として扱い、ビジネス・ユーザーには表示しないためです。
「Inline Service Explorer」で、「Integration Points」→「Advisors」にある「Get Cross Sell Offer」をダブルクリックします。
「Asynchronous Logic」タブで、既存コードを更新します。提示されたイベントを記録してOfferExtendedセッション属性に選択肢IDの値を設定する行を既存コードに追加します。更新後のコードは次のようになります。
logInfo("Integration Point - Get Cross Sell Offer"); logInfo(" Customer age = " + session().getCustomer().getAge() ); // 'choices' is array returned by the 'Select Offer' decision if (choices.size() > 0) { //Get the first offer from array Choice offer = choices.get(0); //For the selected offer, record that it has been 'presented' offer.recordEvent("presented"); //Set the session attribute 'OfferExtended' with the offer's ID. session().setOfferExtended(offer.getSDOId()); logInfo(" Offer presented: '" + offer.getSDOLabel() + "'"); }
これによって、選択された選択肢のSDOIdがセッション・エンティティのOfferExtended属性に割り当てられます。SDOIdは一意の識別子です。Oracle RTD構成のすべてのオブジェクトは一意なSDOIdがあります。オファー・オブジェクトには、選択されたオファーのPresentedイベントも記録されます。イベント名は小文字表記で、Presentedの選択肢イベントIDに対応することに注意してください。このIDを表示するには、「Inline Service Explorer」で、「Choices」を開いてから「Cross Selling Offer」をダブルクリックし、「Choice Events」タブ→ラベル/ID切替アイコンをクリックします。
デシジョンの時点で、どのオファーが選択されコール・センター・エージェントによって(Get Cross Sell Offerアドバイザを介して)顧客に提示されたかがセッションにおいて記憶されます。顧客からのレスポンスは判明していません。レスポンスは、次の項で説明するフィードバック・インフォーマントを介して送信されます。
このインフォーマントによりOracle RTDに対して、オファー選択デシジョンの結果評価に必要な情報が提供されます。
フィードバック・インフォーマントを作成する手順は、次のとおりです。
「Inline Service Explorer」で、「Integration Points」を開いて「Informants」フォルダを右クリックし、「New Informant」を選択します。インフォーマント名をOffer Feedback
にします。
エディタで、インフォーマントの説明を入力します。「External System」で「CRM」を選択します。「Order」に「4
」を入力します。
セッション・キーをOffer Feedbackインフォーマントに追加するには、「Session Keys」の横にある「Select」をクリックします。「customerId」を選択し、「OK」をクリックします。
「Add」をクリックして入力パラメータを追加します。パラメータ名をPositive
にします。
データ型が「String」でない場合は選択し、「OK」をクリックします。
パラメータはマップされないままにします。このパラメータにセッション属性へのマッピングが不要なのは、この引数がオファーの受入れの成否を即時に判定する目的で使用されるためです。オファーの受入れは、yes値によって示されます。
「Logic」タブの「Logic」に次のコードを入力し、受入れイベントの発生時に記録されるようにします。
logInfo("Integration Point - Offer Feedback"); //"yes" or "no" to accept offer. String positive = request.getPositive(); positive = positive.toLowerCase(); //Get the offer id from session attribute 'OfferExtended' String extendedOfferID = session().getOfferExtended(); if (extendedOfferID != null) { //Get the offer from choice group 'Cross Selling Offer' Choice offer = CrossSellingOffer.getChoice(extendedOfferID); if (offer != null){ String offerId = offer.getSDOId(); //If response is "yes", then record the offer as accepted. if (positive.equals("yes")) { offer.recordEvent ("accepted"); logInfo(" Offer '" + offer.getSDOLabel() + "' accepted"); } } }
すべてを保存し、インライン・サービスを再デプロイします。「Deploy」ダイアログで、「Terminate Active Sessions (used for testing)」を選択します。
次の図に、Get Cross Sell Offerアドバイザがオファーを取得および提示してから、Offer Feedbackインフォーマントがオファーを受け入れるか拒否するまでのフローを示します。Call Endインフォーマントによってセッションがクローズされると、Offer Acceptance PredictorモデルがオファーのPresentedイベントまたはAcceptedイベントによって更新されます。
図5-1 Tutorialインライン・サービスのオブジェクト: アドバイザおよびインフォーマントのフロー
Offer Feedbackインフォーマントをテストするには、最初にGet Cross Sell Offerをコールしてオファーを取得して提示する必要があります。
フィードバック・インフォーマントをテストする手順は、次のとおりです。
「Test」ビューで、Get Cross Sell Offer統合点を選択します。「customerId」に10
などの値を入力します。
「Send」アイコンをクリックします。
「Response」サブタブでオファーが取得されたことを確認します。「Log」サブタブには、次のような結果が表示されます。
00:45:28,466 Integration Point - Get Cross Sell Offer 00:45:28,466 Customer age = 38 00:45:28,466 Offer presented: 'Credit Card'
他の値を「customerId」に入力しても、提示されるオファーは必ずSavings AccountかCredit Cardのどちらかになります。これは、この段階ではパフォーマンス目標をコストの最小化に対してのみ構成しており、顧客の年齢に応じてSavings AccountまたはCredit Cardが最小コストとなるためです。
「Integration Point」ドロップダウン・リストから、Offer Feedbackインフォーマントを選択します。同一セッションで手順を続行するため、「customerId」の値はそのままにします。入力の「Positive」に、yes
などの値を入力します。
「Send」をクリックし、Get Cross Sell Offerアドバイザによって取得されたオファーが受け入れられたことを「Log」サブタブで確認します。次のようなマップが表示されます。
00:46:01,418 Integration Point - Offer Feedback 00:46:01,418 Offer 'Credit Card' accepted
入力の「Positive」値をno
に変更し、Offer Feedbackインフォーマントを再送信します。「Log」サブタブの内容は次のようになります。
00:47:31,494 Integration Point - Offer Feedback
Get Cross Sell OfferアドバイザおよびOffer Feedbackインフォーマントに対するコールが含まれるように、Load Generatorスクリプトを更新します。これらの統合点コールは、ServiceCompleteインフォーマントの後でしかもCallEndインフォーマント(セッションをクローズするインフォーマント)の前に実行される必要があることに注意してください。ロジックは次のようになります。最初にコールを開始します。次に、標準サービス(通話理由の記録と分析をReason Analysisモデルを使用して行う)を実行します。その後で、コスト最小化目標に基づいてエージェントが抱合せ販売オファーを顧客に提示します。オファー提示後、顧客のオファー受入れ可否を記録します。最後にコールまたはセッションの終了処理(オファーの提示や受入れに関する学習をOffer Acceptance Predictorモデルにより行う)を行います。
Get Cross Sell OfferアドバイザをLoad Generatorスクリプトに追加する手順は、次のとおりです。
RTD_HOME
\scripts\loadgen.cmd
を実行することで、Load Generatorを開きます。そして、以前のスクリプトを開きます。
「Edit Script」タブを選択し、左側のツリー・ビューを右クリックして「Add Action」を選択します。アクションのタイプを「Message」に、統合点の名前をGetCrossSellOfferにそれぞれ設定します。
「Input Fields」で右クリックして「Add item」を選択し、入力フィールドを追加します。「Name」の下のスペースをクリックしてcustomerIdを入力してから、[Enter]を押します。
入力フィールドの「Variable」をクリックし、ドロップダウン・リストを使用して、対応する変数のvar_customerId(詳細は第3.1.1項「Load Generatorスクリプトの作成」を参照)を選択します。「Session Key」を選択して、customerIdをセッション・キーとしてマークします。
このアクションをスクリプトに追加すると、アクション・リストの下部に追加されます。GetCrossSellOfferがServiceCompleteの後にコールされるように、順序を調整する必要があります。「Edit Script」タブの左側で「GetCrossSellOffer」を右クリックしてから、「Move Up」または「Move Down」を使用して、順序がCallBegin、ServiceComplete、GetCrossSellOffer、CallEndになるようにします。
Load Generatorスクリプトを保存します。
Offer FeedbackインフォーマントをLoad Generatorスクリプトに追加する手順は、次のとおりです。
Offer Feedbackへのコールを「Edit Script」タブで追加する前に、新しい変数を「Variable」タブで作成する必要があります。Offer Feedbackインフォーマントの定義を思い出してください。positiveパラメータを使用してオファーの受入れを示します。Load Generatorでは、このパラメータ値はランダムに、yesが30%、noが70%になるように設定します。この設定は、重み付けされた文字列配列を使用して行います。
「Variables」タブの左側で、「Script」フォルダを右クリックし、「Add Variable」を選択します。「Variable name」にvar_positive
と入力し、「Contents」タイプを「Weighted String Array」に設定します。2つのアイテムを配列に追加します(コンテンツ・タイプの下のスペースを右クリックし、「Add Item」を選択)。最初のアイテムでは、「Weight」セルをダブルクリックして編集可能にして値として30
を入力し、対応する「String」セルに値としてyes
を入力します。2番目のアイテムでは、重み付け値を70
にし、文字列値をno
にします。重み付け値は合計を100にする必要はありません。自動的に正規化されるためです。この場合は、重み付け値を6と14にしても、同じ結果となります。
「Edit Script」タブを選択し、左側のツリー・ビューを右クリックして「Add Action」を選択します。アクションのタイプを「Message」に、統合点の名前をOfferFeedback
にします。
「Input Fields」で右クリックして「Add item」を選択し、入力フィールドを追加します。「Name」の下のスペースをクリックし、customerIdを追加します。「Variable」列で、対応する変数のvar_customerId(詳細は第3.1.1項「Load Generatorスクリプトの作成」を参照)を選択します。「Session Key」を選択して、customerIdをセッション・キーとしてマークします。
再び「Input Fields」で右クリックして「Add item」を選択し、入力フィールドを追加します。「Name」の下のスペースをクリックし、positive
を追加します。「Variable」列で、対応する変数のvar_positiveを選択します。
このアクションをスクリプトに追加すると、アクション・リストの下部に追加されます。OfferFeedbackがGetCrossSellOfferの後にコールされるように、順序を調整する必要があります。「Edit Script」タブの左側で「OfferFeedback」を右クリックし、「Move Up」または「Move Down」を選択して、順序がCallBegin、ServiceComplete、GetCrossSellOffer、OfferFeedback、CallEndになるようにします。
図5-3 Load GeneratorスクリプトへのOfferFeedbackインフォーマントの追加
Load Generatorスクリプトを保存します。
Load Generatorスクリプトをこの時点で実行できます。実行結果に古いデータが混在しないように、スクリプトを実行する前に既存データを再び削除することをお薦めします。削除方法の詳細は、第3.2項「モデルの学習内容のリセット」を参照してください。
Load Generatorスクリプトを実行した場合は、その結果をDecision Centerで参照できます。Decision Centerにログインし、「Cross Selling Offer」選択肢グループをクリックし、Offer Acceptance Predictorモデルの結果を表示します。「Performance」タブ→「Counts」サブタブをクリックします。オファーの分布とパレート図が、図5-4のように表示されます。
図5-4 Decision Center→「Cross Selling Offer」→「Performance」→「Counts」
Credit CardとSavings Accountの2つのオファーのみが提示され、それぞれの受入れ率が約30%になっていることに注意してください。これは、これまでに設定したロジックの当然の結果です。設定ロジックでは、まずコスト最小化というパフォーマンス目標のみを適用し、顧客の年齢に応じてSavings AccountまたはCredit Cardが最小コストとなるように設定します(第4.4項「選択肢のスコアリング」を参照)。次にLoad Generatorスクリプトで、OfferFeedbackインフォーマントを介して登録されるオファーへの肯定的なレスポンスを30%に指定します。個々のオファーの分析レポートにドリルダウンすると、オファーの受入れとセッション属性との間における密接な相関関係はありません。これは、ランダムな顧客プロファイル・データを使用し、顧客またはその他の属性(通話の長さ、コール・エージェント名、通話理由など)に関係なく、受入れ率が30%になるように強制適用しているためです。
これまで、パフォーマンス目標を使用して提示オファーを決定する方法と、選択肢イベント・モデルを使用して提示オファーの受入れ率を追跡する方法についてそれぞれ説明しました。これまでに使用したのは、分析に関するモデルのみです。次の項では、2番目のパフォーマンス目標(売上の最大化)を追加し、そのモデルの学習内容を使用して、提示するオファーに影響を与える方法について説明します。また、2人以上の子供を持つ顧客にLife Insuranceオファーが提示された場合に、その受入れ確率を高める人為的なバイアスを導入します。これによって、このバイアスがモデルの結果にどのように影響するかを調べます。
これまでに作成したモデルでは、顧客特性、通話特性および抱合せ販売結果との間における相関関係の学習が行われます。このモデルは、オファー受入れの確率を予測する予測計算にも使用できます。この確率情報を使用することで、提示するオファーを決定する際にオファー値を調整できます。たとえば、オファーAの受入れ確率がオファーBの2倍と予測される場合は、提示するオファーの選択時に、オファーAを優先して選択するのが妥当です。この項では、2番目のパフォーマンス目標として売上の最大化を導入します。売上の最大化では、その値やスコアの受入れ確率と売上単価の積として計算します。
たとえば、Brokerage Accountオファーの売上単価が$300で受入れ確率が30%(0.3)と仮定した場合、その売上最大化スコアは$300 x 0.3 = $90になります。Life Insuranceオファーの売上単価は$185で受入れ確率が60%(0.6)と仮定した場合、売上最大化スコアは$185 x 0.6 = $111になります。Brokerage Accountのほうが売上単価の値が高くても、売上最大化スコアが高くなるLife Insuranceオファーを優先して選択するほうが有利になります。
ここでは、コストと売上最大化の両方に基づいて、提示するオファーを選択することに注意してください。前述の例で、コストと売上最大化の重み付けされた合計においてBrokerage AccountがLife Insuranceよりも高い場合は、Brokerage Accountが選択されます。
この項では、最初に売上単価を追加し、その後で2番目のパフォーマンス目標である売上最大化を追加します。次に、売上最大化の目標のスコアとして、売上単価と受入れ確率との積の値を設定します。設定が完了したら、提示するオファーの選択時にコストと売上最大化の両方の目標が適用されるように、Select Offerデシジョンを更新します。最後に、Offer Feedbackに、Life Insuranceオファーの提示先であり特定のプロファイルを持つ顧客に対して、オファー受入れバイアスを導入するロジックを追加します。
この項の内容は次のとおりです。
売上単価選択肢属性を追加する手順は、次のとおりです。
「Inline Service Explorer」の「Choices」で、「Cross Selling Offer」選択肢グループをダブルクリックします。「Choice Attributes」タブで、「Add」をクリックします。
この属性の名前をRevenueに、データ型をIntegerにそれぞれ設定します。オファーごとに異なる値を割り当てるため、「Overridable」オプションが選択されていることを確認し、「OK」をクリックします。
「Cross Selling Offer」選択肢グループの各選択肢に、表5-1に示すように、Revenue属性の値を設定します。
このチュートリアルにおける前述の項で、Costパフォーマンス目標を定義しました。ここでは、2番目のパフォーマンス目標としてMaximize Revenueを追加します。この新しいパフォーマンス・メトリックのスコアの計算では、選択肢の受入れ確率と売上単価を使用します。その計算式は、売上単価×受入れ確率=潜在売上スコアとなります。
2番目のパフォーマンス目標を追加する手順は、次のとおりです。
「Inline Service Explorer」で、「Performance Goals」をダブルクリックし、エディタを起動します。「Add」をクリックして、パフォーマンス・メトリックを追加します。メトリック名をMaximize Revenueとし、「OK」をクリックします。
「Optimization」で、「Maximize」を選択し、メトリックを「Required」にします。コストの$1と売上の$1は等しいため、正規化ファクタは調整不要です。
次に、このメトリックを「Cross Selling Offer」選択肢グループに追加する必要があります。「Inline Service Explorer」で、「Cross Selling Offer」をダブルクリックします。「Scores」タブで「Select Metrics」をクリックします。「Select」ダイアログで「Maximize Revenue」を選択し、「OK」をクリックします。
Maximize Revenue目標のスコア値を計算するには、Offer Acceptance Predictor選択肢イベント・モデルによって決定される受入れ確率値と売上単価が必要です。この値は、「Edit Value」ダイアログで値スコアを「Model prediction」に変更することで取得できます。
パフォーマンス目標であるMaximize Revenueのスコア値を計算する手順は、次のとおりです。
「Inline Service Explorer」の「Choices」で、「Cross Selling Offer」選択肢グループをダブルクリックします。「Scores」タブで、Maximize Revenueメトリックの「Scores」列→省略記号をクリックし、「Edit Value」ダイアログを起動します。
「Value Source」で、「Function or rule call」を選択します。「Function to Call」で、「Multiply」関数を選択します。「Parameters」テーブルで、aパラメータの「Value」セルをクリックします。省略記号をクリックして「Attribute or variable」を選択し、「Choice」フォルダを開きます。そして、「Revenue」を選択して「OK」をクリックします。「Parameters」テーブルで、bパラメータの「Value」セルをクリックします。省略記号をクリックして「Model prediction」を選択します。Offer Acceptance PredictorモデルとAcceptedイベントによって予測される受入れ確率値を選択して「OK」をクリックします。「Edit Value」ダイアログで再び「OK」をクリックします。
実際の受入れ確率値は0から1までの間になり、1は受入れ確率が100%を意味します。この値はNaN(Not a number)になる場合もあり、これは受入れ確率値の計算に十分なデータがモデルにないことを意味します。この場合、Maximize Revenueのスコア値は計算不能で、Select Offerデシジョンによるオファー選択は、組込みのスコア計算ロジックに基づきます(スコアが必須かどうかに応じて処理される)。
Maximize Revenueのスコアを選択肢グループ・レベルで定義することで、グループ内のすべての選択肢においてその定義が継承され、選択肢固有の売上単価値と受入れ確率値が実行時に適用されます。
これまで、新しいパフォーマンス・メトリックとその値の計算方法を定義しました。次に、提示するオファーの選択時に両方のパフォーマンス・メトリックが適用されるように、Select Offerデシジョンを更新します。
Select Offerデシジョンを更新する手順は、次のとおりです。
「Inline Service Explorer」で、「Decisions」フォルダを開き、「Select Offer」をダブルクリックします。
「Selection Criteria」タブの「Priorities for the "Default" Segment」テーブルには、パフォーマンス目標のCostのみが100%の重み付け値で表示されます。「Goals」をクリックしてパフォーマンス目標の「Maximize Revenue」を選択し、「OK」をクリックします。
優先度のテーブルに、2つのパフォーマンス目標が、それぞれ重み付け値50%で表示されます。デフォルトでは、重み付けは、選択されたすべてのメトリック間で均等に分配されます。Maximize Revenueパフォーマンス目標をCostよりも優先する場合は、このパーセント値を調整して重み付けを高くします。このチュートリアルでは、デフォルトの重み付けの50%を使用します。
表5-2に、Select Offerデシジョンにより特定のオファーに対する合計スコアを計算する例を示します。この例では、オファーのCostスコアを150、Maximize Revenueスコアを215とします。
表5-2 オファーの合計スコアの計算
パフォーマンス目標 | スコア | 重み付け | 「Maximize」/「Minimize」 | 正規化 | 重み付けされたスコア |
---|---|---|---|---|---|
Cost |
150 |
50% |
Minimize |
1 |
-75 |
Maximize Revenue |
215 |
50% |
Maximize |
1 |
107.5 |
表5-2の値に基づいて計算されたスコアの合計は32.5になります。Costの重み付けされたスコアは、「Optimization」が「Minimize」のため負の値になります。オファーの合計スコアは、2つの重み付けされたスコアの加算値です。合計スコアはオファーごとに計算され、最高値を持つオファーが選択されます。
受入れ確率の値を表示するには、対応する選択肢属性を追加し、logInfoを介して表示するか、「Test」ビューの「Response」タブに表示します。
選択肢属性を追加する手順は、次のとおりです。
「Inline Service Explorer」の「Choices」で、「Cross Selling Offers」選択肢グループをダブルクリックします。「Choice Attributes」タブで、「Add」をクリックして属性を追加します。プロパティ・ダイアログで、「Display Label」をLikelihood Of Acceptanceに設定します。「Data Type」をDoubleに設定します。
この選択肢グループ内のすべての選択肢によってこの属性に同じ定義が使用されるため、「Overridable」オプションの選択を解除します。「Send to client」オプションを選択し、「OK」をクリックします。
Likelihood Of Acceptance属性の「Value」列で、省略記号をクリックし、その値を設定します。「Edit Value」ダイアログで、「Value Source」を「Model prediction」に設定します。Offer Acceptance PredictorモデルとAcceptedイベントを選択し、「OK」をクリックします。
インライン・サービスに対するすべての変更を保存します。
受入れ確率値を表示するには、次に示すように、logInfo文をGet Cross Sell Offerアドバイザに追加します。
「Inline Service Explorer」で、「Integration Points」→「Advisors」にある「Get Cross Sell Offer」をダブルクリックします。
「Asynchronous Logic」タブで、受入れ確率の値を出力する行を追加して、既存コードを更新します。更新後のコードは次のようになります。
logInfo("Integration Point - Get Cross Sell Offer"); logInfo(" Customer age = " + session().getCustomer().getAge() ); // 'choices' is array returned by the 'Select Offer' decision. The // name 'choices' was set (and can be changed) in the 'Choice Array' // text box in the 'Select Offer' decision's 'Pre/Post Selection // Logic' tab. if (choices.size() > 0) { //Get the first offer from array Choice offer = choices.get(0); //For the selected offer, record that it has been 'presented' offer.recordEvent("presented"); //Set the session attribute 'OfferExtended' with the offer's ID. session().setOfferExtended(offer.getSDOId()); logInfo(" Offer presented: '" + offer.getSDOLabel() + "'"); //Cast selected offer to type CrossSellingOfficeChoice - //the base Choice type of choice group 'Cross Selling Offer' CrossSellingOfferChoice cso = (CrossSellingOfferChoice) offer; logInfo(" Likelihood of Acceptance = " + cso.getLikelihoodOfAcceptance()); }
アドバイザの変更結果を確認するには、すべてを保存し、インライン・サービスをデプロイします。
「Test」ビューで、Get Cross Sell Offer統合点を選択し、「customerId」に8
などの値を入力します。「Send」をクリックします。「Test」ビューの「Response」サブタブに、図5-6に示すような結果が表示されます。
「Log」サブタブには、次のような結果が表示されます。
14:07:37,908 Integration Point - Get Cross Sell Offer 14:07:37,908 Customer age = 57 14:07:37,908 Offer presented: 'Savings Account' 14:07:37,908 Likelihood of Acceptance = 0.30354643094453865
Likelihood Of AcceptanceでNaN(Not A Number)値を取得した場合は、受入れ確率値の計算に十分なデータがモデルにないことを意味します。モデルの収束(受入れ確率値がNaNでなくなる)に必要な反復実行回数は、アプリケーションとデータの質によって異なります。
このケースでは、オファーの受入れ確率を30%にして(第5.1.7項「Load Generatorスクリプトの更新」を参照)、ランダムな顧客プロファイル・データを使用するため、Offer Acceptance Predictorモデルは短時間で収束し、数百回の反復実行で受入れ確率を計算できます。モデルが収束する前に、オファー選択プロセスは、組込みのスコア計算ロジックに基づいて決定します(スコアが必須かどうかに応じて処理される)。
次の図に、各オファーの合計スコアをCostとMaximize Revenueの2つのスコアの重み付けされた合計として、Get Cross Sell OfferアドバイザがCross Selling Offer選択肢グループからオファーを取得するフローを示します。
これまで、Offer Feedbackインフォーマントにおいて、提示されたオファーが受け入れられたかどうかを示すPositiveインフォーマント・パラメータを指定しました。次に、このインフォーマントがコールされたときに、Positiveパラメータにyesの値が30%の割合で渡されるように、Load Generatorスクリプトを更新しました(第5.1.7項「Load Generatorスクリプトの更新」を参照)。このパーセント値は顧客のプロファイル・データによって変わらないため、どのような顧客に対しても、提示されたすべてのオファーの受入れ確率が30%程度になります。
この段階でLoad Generatorスクリプトを実行しても、モデルによって、顧客属性とオファー受入れとの間において密接な相関関係が示されることはありません。ここでは、2人以上の子供を持つ顧客にLife Insuranceオファーが提示された場合に、肯定的なオファー受入れをOffer Feedbackインフォーマントのロジックに必ず記録する人為的なバイアスを導入します。このロジックでは、デフォルトの受入れ確率(Load Generatorスクリプトに定義済)に加えて、Life Insuranceオファーの受入れ確率を30%よりも高い値に偏向させます。これによって、Decision Centerでは、子供の数とLife Insuranceオファーの受入れ確率との間に明確な相関関係が見られるようになります。
オファー受入れバイアスを導入する手順は、次のとおりです。
「Inline Service Explorer」で、「Integration Points」の「Informants」にある「Offer Feedback」をダブルクリックします。
「Logic」タブで、2人以上の子供を持つ顧客にLife Insuranceオファーが提示された場合にオファー受入れバイアスを追加する行を追加して、既存コードを更新します。更新後のコードは次のようになります。
logInfo("Integration Point - Offer Feedback"); //"yes" or "no" to accept offer. String positive = request.getPositive(); positive = positive.toLowerCase(); //Get the offer id from session attribute 'OfferExtended' String extendedOfferID = session().getOfferExtended(); if (extendedOfferID != null) { //Get the offer from choice group 'Cross Selling Offer' Choice offer = CrossSellingOffer.getChoice(extendedOfferID); if (offer != null){ String offerId = offer.getSDOId(); //Introduce artificial bias for customers with 2 or more //children to always accept "LifeInsurance" if it was //selected after scoring. //If data source is Oracle, change the following method from //getNumberOfChildren() to getNumberofchildren() int numOfChildren = session().getCustomer().getNumberOfChildren(); if ( numOfChildren >= 2 && offerId.equals("LifeInsurance")) { positive="yes"; } //If response is "yes", then record the offer as accepted. if (positive.equals("yes")) { offer.recordEvent ("accepted"); logInfo(" Offer '" + offer.getSDOLabel() + "' accepted"); } } }
すべての変更を保存し、インライン・サービスをデプロイします。
第5.1.7項「Load Generatorスクリプトの更新」で、Get Cross Sell OfferアドバイザとOfferFeedbackインフォーマントが含まれるようにLoad Generatorスクリプトを更新しました。この時点では、オファー選択プロセスは、コストの最小化というパフォーマンス目標にのみ基づいていました。次に、2番目のパフォーマンス目標として売上の最大化を追加し、それにOffer Acceptance Predictorモデルによって計算される受入れ確率の予測値を使用しました。これによってオファー選択プロセスは、両方のパフォーマンス目標に基づくことになります。さらに、特定のプロファイルに合致する顧客にLife Insuranceオファーが提示された場合の受入れバイアスを導入しました。ここで、Load Generatorスクリプトを再度実行して、結果を確認します。
Load Generatorスクリプトを実行する手順は、次のとおりです。
OC4JまたはWebLogicを使用している場合は、JAVA_HOME
\bin\jconsole.exe
を実行してJConsoleを起動します。WebSphereを使用している場合は、JConsoleの構成中に作成したバッチ・スクリプトを実行します。JConsoleの使用方法の詳細は、『Oracle Real-Time Decisionsインストレーションおよび管理ガイド』を参照してください。
「Remote」タブを選択します。インストール中に作成した管理者資格証明と適切なポート番号(通常は12345
)を入力し、「Connect」をクリックします。
「MBean」タブをクリックしてから、「OracleRTD」→「InlineServiceManager」→「Tutorial」→「Development」→「Loadable」MBeanに移動します。
「Operations」タブをクリックしてから、deleteAllOperationalData()操作を使用して、このインライン・サービスの操作データをすべて(結果も含めて)削除します。
Load Generatorを起動し、前の項で定義したLoad Generatorスクリプトを開きます。変更は不要です。
Load Generatorスクリプトを実行します。約200回スクリプト実行後、「Pause」アイコンをクリックし、サーバーへのリクエストの送信を一時的に停止します。
RTD_RUNTIME_HOME\logディレクトリにあるserver.log
ファイルにおけるサーバー出力内容を確認します。
すべてのセッションでは、出力された受入れ確率値がNaNになります。これは、受入れ確率値を計算できるだけ十分なデータの学習がモデルにおいて行われていないことを意味します。確率値がなくても、オファーは提示されることに注意してください。オファーは、組込みのスコア計算ロジックを使用して選択されます。
Load Generatorスクリプトの一時停止を解除し、実行回数が2000回になるまでスクリプトを実行します。今回は、サーバー出力に受入れ確率の実際値が出力されます。Life Insurance以外のすべてのオファーでは0.3前後になりますが、Life Insuranceオファーでは導入したバイアスの結果として値が高くなります。
特定のオファーで、モデルが予測する受入れ確率値が顧客のプロファイルに応じて異なることに注目することが重要です。たとえば、顧客が2人(JohnとTom)いて、子供の数のみが異なると仮定します。2人の顧客のLife Insuranceオファーに対する受入れ確率値を調べると(ある時点でのスナップショットとして)、表5-3に示すように、Tomの値のほうが高いことが判明します。これは、Tomには3人の子供がいて、Life Insuranceオファーが提示された場合の受入れ確率が高くなることによります。
顧客に提示されるオファーはCostスコアとMaximize Revenueスコアの組合せに基づいて決定され、オファーごとにモデルによって予測される受入れ確率値にMaximize Revenueが基づくため、2人以上の子供を持つ顧客ではLife InsuranceオファーのMaximize Revenue値が高くなり、結果として、こうした顧客に対しては、他のオファーよりもLife Insuranceの提示率(さらには受入れ率)が高くなります。
Load Generatorの実行結果を参照するには、Decision Centerにログインします。「Cross Selling Offer」選択肢グループを左側のナビゲーション・ボックスでクリックします。ここにOffer Acceptance Predictorモデルの結果が表示されます。「Performance」タブ→「Counts」サブタブをクリックします。図5-8に示すような結果が表示されます。
図5-8 「Cross Selling Offer」選択肢グループの「Performance」→「Counts」
Decision Centerのテーブルはオファーの分布(つまり、オファーごとの提示数と受入れ数)を示しています。Life Insurance以外の他のすべてのオファーでは、図5-8に示すように、受入れ率が30%前後になっています。これは、Load Generatorスクリプトの設定の当然の結果です(第5.1.7項「Load Generatorスクリプトの更新」を参照)。Life Insuranceの受入れ率は30%よりも高くなっています。これは、第5.2.7項「特定の顧客に対するオファー受入れバイアスの導入」で人為的なバイアスを導入したためです。このバイアスによって、すべてのオファーの受入れ率が30%程度になることに加えて、2人以上の子供を持つ顧客にLife Insuranceオファーが提示されたときは必ず受け入れるようにされます。
人為的なバイアスを設定したことで、Life InsuranceオファーではNumberOfChildren属性がオファー受入れの重要指標となることが、モデル結果に反映されます。Decision Centerレポートには、このことが示されます。「Cross Selling Offer」選択肢グループ→「Analysis」タブ→「Drivers」サブタブをクリックします。「Report Settings」セクションで、「Minimum Predictiveness」の値を0に変更し、「Go」をクリックします。属性の一覧が、予測値の高い順に表示されます。「Max Predictiveness」の最高値は、NumberOfChildren属性になります。この属性が、追加した唯一の人為的なバイアスのためです。対応するオファーはLife Insuranceで、図5-9に示すようなレポートになります。
図5-9 「Cross Selling Offer」→「Analysis」→「Drivers」
Life Insuranceオファー固有のレポートを表示することで、このオファーに対してNumberOfChildren属性が持つ重要性をさらに分析できます。Decision Centerのナビゲーション・ボックスで、「Cross Selling Offer」選択肢グループを開き、選択肢の「Life Insurance」→「Analysis」タブ→「Drivers」タブをクリックします。このレポートには、この特定のオファー(Life Insurance)の受入れに対する重要な誘因が示されます。
「Report Settings」セクションで、「Minimum Predictiveness」の値を0
に変更し、「Go」をクリックします。属性の一覧が、予測値の高い順に表示されます。NumberOfChildren属性が、最も高い予測値を持ちます。属性名をクリックし、詳細レポートを表示します。その中の1つに、図5-10に示すようなグラフが表示されます。
図5-10に示すグラフは、NumberOfChildrenの値が2以上の場合、オファー受入れと密接な正の相関関係があることを示しています。これは、この属性値(2以上)の場合、このオファーの受入れ数が期待値よりも大きくなることを意味します。同様に、値が0または1の場合も相関関係が非常に密接になりますが、この相関関係は負で、子供がいないか子供が1人の顧客には期待するほどLife Insuranceオファーが受け入れられないことを意味します。