Friday Feb 17, 2012

Facet Based Predictions

The analytical models method detailed in a previous post are not only extremely valuable for reporting, but can also be used to predict likelihoods for things other than regular choices. We can for instance generate predictions based on statistics for an attribute of a choice, rather than the choice itself. We use the term facet based prediction to describe this advanced form of generating predictions.

This novel approach to modeling can be applied to significantly improve predictive accuracy and model quality. It can also facilitate the rapid transfer of existing learnings to newly created choices based on their facet values. These capabilities can be of use to practically all implementations, but they are of utmost importance in cases where the number of choices is very high or individual choices have short shelf life. In these instances, there might simply not be enough time or data to be able to predict likelihoods for individual choices. We could predict likelihoods for certain facets of our choices; as long as their cardinality remains relatively low.

Consider the following example in which we recommend products based on the acceptance of other products in the same category. In our ILS, Oracle Real-Time Decisions will be used to recommend a single product based on a single performance goal: Likelihood.

Choice Groups Setup

Products that may be recommended are stored in a choice group Products (we will use static choices, but this approach could be implemented for dynamic choices also). Product choices have an attribute Category which will contain a category name. We will use a second and separate dynamic choice group Categories to record acceptance of the different product categories.

Choice Group Setup

Note that we never intend to return any choices from the Categories choice group to a client. It is configured using a dummy source and will not contain any actual choices. This group is only used within the ILS for predicting likelihoods. Statistics for this group may however be viewed in decision center reports.

Recording Events

Similar to the example for analytical models, we will record events against a dynamically generated choice representing a facet value rather than against the actual choice. In this example, both the actual choice and the event to record will be passed through a request represented as Strings.

// create a new choice to represent the category facet
CategoriesChoice c = new CategoriesChoice(Categories.getPrototype());
// set properties of the choice
c.setSDOId("Category" + "$" + Products.getChoice(request.getChoice()).getCategory());
// record event in model (catching an exception just in case)
try { c.recordEvent(request.getEvent()); } catch (Exception e) { logError(e); }

Model Setup

Our model setup is practically identical to before, but this time we'll enable "Use for prediction".

Predicting Likelihoods

A function PredictLikelihood will be used to predict likelihoods for our products. The function takes a Products choice and an Event (String) as parameters and returns a Double value representing the predicted likelihood.
// get instance of the model used for predicting Category Events
CategoryEvents m = CategoryEvents.getInstance();
// return the likelihood based on the generated SDOId and the "Accepted" event
return m.getChoiceEventLikelihood("Categories$"+product.getCategory(), event );

 

Choice Group Scores Setup

On the scores tab for the Products choice group we configure the Likelihood performance goal to be populated by the PredictLikelihood function using parameters this and "Accepted". The keyword this refers to the particular choice being scored and will ensure each choice is scored according to its category facet.

That is all that is required to score choices against a facet. We can now create decisions and advisors that use these predictions to recommend products based on their categories.

In this example, we have predicted likelihoods based on a single product facet. As a result, products in the same category will be scored the same. In practical implementations this will rarely be an issue, because there will presumably be multiple performance goals. Also, likelihoods may be mixed with product specific attributes like price or cost; resulting in score differentiation between products regardless of equality in likelihoods.

In a later post, we will discuss how we can expand on this to include multiple product facets in our likelihood prediction.

Monday Jan 23, 2012

Analytical Models

As explained in a previous post, we can record events against unsourced dynamic choices created on-the-fly using the getPrototype method. Choices instantiated in this fashion, and the events recorded against them, will be visible in decision center reports.

This enables us to create extensive reporting based on arbitrary input from different sources without the need to specify all the possible choice values upfront. Creating so-called analytical models can be very useful for analysis.

Recording Client Input

Consider the following example which shows how this approach can be used to create an analytical model based on informant input. In our ILS, Oracle Real-Time Decisions will be used to find and report on correlations between a regular session attribute and arbitrary codes passed through an informant.

Choice Group Setup

A choice group Reason is used to store codes passed through the informant. During initialization, the choice group will attempt to grab choices from the ReasonEntityArray, but the array is a dummy entity that will always return nothing, because we've not defined a value for it.

Reason choice group configuration, dynamic choices tab.

Reason choice group configuration, group attributes tab.

Informant Setup

When invoked, a RecordReason informant will record an event for the ReasonCode input parameter. The logic for this informant is pretty straightforward.

// create a new choice based on the request attribute (a string that describes the reason)
ReasonChoice c = new ReasonChoice(Reason.getPrototype());
// set properties of the choice (SDOId should be of the form "{ChoiceGroupId}${ChoiceLabel}")
c.setSDOId("Reason" + "$" + request.getReasonCode());
// record choice in model (catching an exception just in case)
try { c.recordChoice(); } catch (Exception e) { logTrace("Exception: " + e); }

Model Setup

In order to actually find and report on correlations, we will need to define at least one event model on our choice group. For this example, we'll keep things as simple as possible.

Reasons choice event model configuration.

Reports

The reports in decision center will show the reason codes sent to the informant as if they were dynamic choices and calculate statistics and correlations against session attributes.

(In this example, an Oracle Real-Time Decisions Load Balancer script was used to send four different codes to the ILS with a severe bias towards certain age groups.)

Decision center report for Reason choice, analysis tab.

This approach enables us to generate detailed reporting and analysis of more than just regular choices in the familiar decision center environment. In this example we were using informant input, but this technique can also be applied using the attributes of other choices to gain additional insight into the correlations between session attributes and choice attributes like product group or category (rather than individual choices).

This method can also be used in conjunction with predictive models. We will explore this possibility and its applications in future posts.

Friday Jan 06, 2012

Recording Events

There is always more than one way to skin a cat; it's just that some ways to excoriate a feline are more efficient than others. This is certainly true for the way in which we can record events against choices in RTD, and the differences in performance can be striking.

getChoice

A common approach to record events against static choices is to use the getChoice API.

Choice ch = MyChoiceGroup.getChoice("MyChoiceId");
ch.recordEvent("Clicked");

On the first line, we are asking RTD to go through the list of all choices in MyChoiceGroup and retrieve one particular choice keyed MyChoiceId. On the second, we record a Clicked event against the returned choice. 

Because we are asking RTD to go through the list of all choices, we require that RTD has a full list of choices available; even if we only end up using a single choice. If we use the same code for dynamic choices, RTD will thus have to fetch and instantiate the full list of dynamic choices in order to find the single one we are interested in. This may be an expensive operation, as it may require accessing an external database or web service; execution of complex custom code; and/or instantiating a large number of dynamic choices.

(Note that dynamic choices do not cache at the choice level. They cache at the entity level. These entities hold the data for the dynamic choices but not the choices themselves. The RTD API could perhaps be optimized differently, but the current implementation will instantiate all the dynamic choices and then find the one the API call is looking for. Consider also that the actual source data used for the dynamic choices could come from anywhere and need not come from cached entities at all; it might even be generated on the fly through custom functions. This flexibility in sourcing dynamic choices makes retrieving a single choice non-trivial from the RTD API perspective.)

This approach will certainly work, but may waste precious time and resources retrieving and instantiating dynamic choices that are never used.

getPrototype

For recording an event, it is sufficient that we have a choice that has the desired SDOId; all other choice attributes are irrelevant for this purpose. A more efficient way to record events against dynamic choices is therefore to create a new empty dynamic choice; assign it an SDOId; and record the event against that, rather than retrieving the 'actual' dynamic choice. The result in terms of statistics and learning are the same, but in this approach there is no need for RTD to retrieve any choices at all.

We can instantiate an empty dynamic choice using the getPrototype API.

Choice ch = new MyDynamicGroupChoice(MyDynamicGroup.getPrototype());
ch.setSDOId("MyDynamicGroup" + "$" + "MyChoiceId");
ch.recordEvent("Clicked");

This approach can provide significant performance improvements in implementations with a large number of dynamic choices; or in implementations where retrieving dynamic choices is a non-trivial complex operation and entity caching proves insufficient.

Being able to record events on choices that are not retrievable through the dynamic list is an additional advantage that has several interesting applications which we will explore in future posts.

(Special thanks to Michel Adar for bringing this to my attention and providing an initial draft of this article.)

Friday Dec 18, 2009

Learning and predicting for short and long term events

In many RTD deployments we see that the business wants to optimize decisions based on the long term effect of the decision. For example, selecting a retention offer to display to a customer in the web site should not be driven by the likelihood that the customer will click on the offer, but by the likelihood the customer will have been retained, say after 3 month.

Another simpler example is the decision by a bank to offer a credit card to a customer. The events in this situation may be:

  1. Offer Extended
  2. Clicked
  3. Applied for card
  4. Used card
The goal of the bank is to have the customer use the card. The problem is that the feedback for whether the card is used will come weeks after the initial offering. This not only requires the capability of closing the loop at a later time (the subject of a future entry in this blog), but it also leaves us a long time without the capability of having reliable models.

RTD provides built-in functionality to handle these cases gracefully, utilizing the maximum of available information. This is why the positive events for an RTD model can be more than one and their order matters. The idea behind this feature is that the events are naturally ordered. The use of the card comes after the application and after the click. Therefore, a model for the "Click" event can be used as a proxy for the deeper events for as long as we do not have a good model for them.

Using a closer event as a proxy for the farther one is a good strategy, but it requires management of events, levels of conversion, etc. and it gets even more complicated when you think that the different offers can be at different levels of conversion. RTD does all this management automatically.

Before we describe how RTD makes this all work, there is one more consideration. When comparing offers it is not fair to compare the likelihood of click for one offer with the likelihood of Card Use for another offer.

The way that RTD works is as follows. When computing the likelihood for a choice:

  1. Compute the likelihood for the deepest event for which we have a converged model
  2. If the event is the desired one (usually the deepest) stop here and use this likelihood
  3. Compute the average likelihood across all choices for all the events that are deeper than the one we used in step 1
  4. Using the average likelihoods compute the proportion between the different events and apply that proportion to the likelihood we got in step 1.
For example, if the only likelihood that can be computed for a specific choice is Click, and it is 10%, and the averages across all other choices are:

  • Click : 20%
  • Apply : 12%
  • Use: 8%
Then for our choice we take the 10% and multiply it by 8/20 to get the likelihood of use, which gives 4% if I am not mistaken. The likelihood of Apply for the same choice (and customer) would be 6%.

As mentioned before, if you define the events in the proper order as the positive events for the model RTD will take care of the logistics for you, following the algorithm described above.

Happy Holidays.


About

Issues related to Oracle Real-Time Decisions (RTD). Entries include implementation tips, technology descriptions and items of general interest to the RTD community.

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today