Value Finder analysis¶
Every Value Finder simulation populates a dataset, the pyValueFinder dataset. This dataset contains a lot more information than is what is currently presented on screen.
The data held in this dataset can be analysed to uncover insights into your decision framework. This notebook provides a sample analysis of the Value Finder simulation results.
In the data folder we’ve stored a copy of such a dataset, generated from an (internal) demo application (CDHSample). To run this notebook on your own data, you should export the pyValueFinder dataset from Dev Studio then follow the instructions below.
This is how Value Finder results of the sample data are presented in Pega (8.6, it may look different in other versions):
For the sample provided, the relevant action setting is 1.2%. There are 10.000 customers, 3491 without actions, 555 with only irrelevant actions and 5954 with at least one relevant action.
PDSTools defines a class ValueFinder that wraps the operations on this dataset. The “datasets” import is used for the example but you won’t need this if you load your own Value Finder dataset.
Just like with the ADMDatamart class, you can supply your own path and filename as such:
vf = ValueFinder(path = '[PATH TO DATA]', filename="[NAME OF DATASET EXPORT]")
If only a path is supplied, it will automatically look for the latest file.
It is also possible to supply a dataframe as the ‘df’ argument directly, in which case it will use that instead.
[2]:
from pdstools import ValueFinder, datasets
import polars as pl
# vf = ValueFinder(path = '...', filename='...')
vf = datasets.sample_value_finder()
When reading the data, we filter out unnecessary data, and the result is kept in the df
property:
[3]:
vf.df.head(5).collect()
[3]:
PreviousComponent | WorkID | TreatmentKeycode | EndDate | DecisionTime | ClickthroughURL | LastStage | Treatment | Bundlehead | IsPropositionActive | DecisionReference | Prediction | Propensity | MaturityCap | TemplateType | ActionContext | FinalPropensity | DynamicTemplateName | SubjectHash | UpdateopName | ShortDescription | Segment | IsSMSEnabled | BundleType | InteractionID | Value | TemplateName | IsEmailEnabled | ModelPerformance | Benefits | Keycode | Division | OriginalSubjectID | StartingEvidence | PropensityThreshold | StartDate | Rank | … | Lastchannel | ModelEvidence | Adminputsource | Application | DynamicTemplateGroup | SMSMessage | SpecifySMSMessage | Organization | Label | Interaction | Weight | Direction | Weight_2 | Operator | Name | Channel | UniqueID | DeliverOffline | StartingPropensity | Issue | CustomerHash | Pricing | CustomerID | Priority_2 | Istransactional | Contextweight | SubjectType | AdjustedPropensityOmni | Stage | DynamicTemplateIssue | IsWebEnabled | BundleName | EmailSubject | SpecifyEmailSubject | Communicateto | IsPaidEnabled | Cost |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
str | str | str | str | datetime[ns] | str | str | str | bool | str | str | str | f64 | f64 | str | str | f64 | str | str | str | str | str | bool | str | str | f64 | str | bool | str | str | str | str | str | u32 | f64 | str | u16 | … | str | i64 | str | str | str | str | bool | str | str | str | f64 | cat | f64 | str | str | cat | str | bool | str | cat | i64 | str | str | f64 | bool | str | cat | f64 | enum | str | bool | str | str | bool | str | bool | f64 |
"Customers" | "Opp_NBA_AlDF_Simulat-1" | "" | "20181231T163800.000 GMT" | 2021-08-24 11:12:49.350 | "/MS/index.html?Site=NonBundled… | null | "Deposit_SMSTreatment" | false | "Always" | " 6320879002230024255" | null | 0.269231 | 0.1768 | "" | "Customer" | 0.278077 | "ChannelAction_Template" | "0.4388105018174723" | "Piyush Vashisht" | "Best of all, with Student Chec… | null | true | "FixedBundle" | "6320879002230024255" | null | "" | true | "0.5" | "Students under age 23 are elig… | "SDSC2" | "Div" | "Customer-1" | 100 | 0.0 | "20160201T163800.000 GMT" | 3 | … | null | 96 | "modelReferences" | "CDHSample" | "CreditCards" | "" | false | "DMOrg" | "Student Checking" | "——" | null | "Outbound" | null | "Otto Perdeck" | "StudentChecking" | "SMS" | null | false | "0.5" | "Sales" | 10 | "No monthly maintenance fee whe… | "Customer-1" | null | false | null | "CDHSample-Data-Customer" | null | "Applicability" | "Sales" | null | null | null | null | null | null | null |
"Customers" | "Opp_NBA_AlDF_Simulat-1" | "MOBILE" | null | 2021-08-24 11:12:37.780 | null | null | "Mobile_ExternalSMSTreatment" | null | "Always" | " 6320879002230024184" | null | 0.5 | 0.02 | "DB" | "Customer" | 0.713095 | "Usage_ChannelAction_Template" | "0.940830237245977" | "Piyush Vashisht" | "Manage accounts from your mobi… | null | true | "FixedBundle" | "6320879002230024184" | null | "Mobile_SMSDBTemplate" | true | "0.5" | null | "UMGUMA1" | "Div" | "Customer-100" | 25 | 0.0 | null | 3 | … | null | 0 | "modelReferences" | "CDHSample" | "Mobilebanking" | "You are entitled for an offer" | true | "DMOrg" | "Get the U+ Mobile App" | "——" | null | "Outbound" | null | "Otto Perdeck" | "GetTheUMobileApp" | "SMS" | null | true | "1" | "Usage" | 1 | null | "Customer-100" | null | false | null | "CDHSample-Data-Customer" | null | "Applicability" | "Usage" | null | null | null | null | null | null | null |
"Customers" | "Opp_NBA_AlDF_Simulat-1" | "" | null | 2021-08-24 11:12:02.932 | null | null | "Recommendations_SMSTreatment" | null | "Always" | " 6320879002230023934" | null | 0.5 | 0.02 | "" | "Customer" | 0.421306 | "Collections_ChannelAction_Temp… | "0.8026197582592971" | "Piyush Vashisht" | "Setup autopay to avoid missing… | null | true | "FixedBundle" | "6320879002230023934" | null | "" | null | "0.5" | null | "CRSAT1" | "Div" | "Customer-1000" | 25 | 0.0 | null | 3 | … | null | 0 | "modelReferences" | "CDHSample" | "Recommendations" | "" | false | "DMOrg" | "Setup Autopay today" | "——" | null | "Outbound" | null | "Otto Perdeck" | "SetupAutopayToday" | "SMS" | null | false | "1" | "Collections" | 0 | null | "Customer-1000" | null | false | null | "CDHSample-Data-Customer" | null | "Applicability" | "Collections" | true | null | null | null | null | null | null |
"Customers" | "Opp_NBA_AlDF_Simulat-1" | "" | "20181231T163800.000 GMT" | 2021-08-24 11:11:52.857 | "/MS/index.html?Site=NonBundled… | null | "Deposit_SMSTreatment" | false | "Always" | " 6320879002230023873" | null | 0.269231 | 0.1768 | "" | "Customer" | 0.244777 | "ChannelAction_Template" | "0.2919499647730856" | "Piyush Vashisht" | "Best of all, with Student Chec… | null | true | "FixedBundle" | "6320879002230023873" | null | "" | true | "0.5" | "Students under age 23 are elig… | "SDSC2" | "Div" | "Customer-10000" | 100 | 0.0 | "20160201T163800.000 GMT" | 3 | … | null | 96 | "modelReferences" | "CDHSample" | "CreditCards" | "" | false | "DMOrg" | "Student Checking" | "——" | null | "Outbound" | null | "Otto Perdeck" | "StudentChecking" | "SMS" | null | false | "0.5" | "Sales" | 10 | "No monthly maintenance fee whe… | "Customer-10000" | null | false | null | "CDHSample-Data-Customer" | null | "Applicability" | "Sales" | null | null | null | null | null | null | null |
"Customers" | "Opp_NBA_AlDF_Simulat-1" | "" | null | 2021-08-24 11:12:01.129 | null | null | "Bundles_SMSTreatment" | null | "Always" | " 6320879002230023923" | null | 0.15 | 0.1082 | "" | "Customer" | 0.24831 | "ChannelAction_Template" | "0.45582757506999766" | "Piyush Vashisht" | "All the essentials are include… | null | true | "FixedBundle" | "6320879002230023923" | null | "" | null | "0.6029929577464789" | "Free Online Banking with e-Sta… | "SBSC1" | "Div" | "Customer-1001" | 100 | 0.0 | null | 3 | … | null | 91 | "modelReferences" | "CDHSample" | "CreditCards" | "" | false | "DMOrg" | "Student Choice" | "——" | null | "Outbound" | null | "Otto Perdeck" | "StudentChoice" | "SMS" | null | false | "0.5" | "Sales" | 5 | "No fee for all your basic need… | "Customer-1001" | null | false | null | "CDHSample-Data-Customer" | null | "Applicability" | "Sales" | true | "Student Choice" | null | null | null | null | null |
The piechart shown in platform is based on a propensity threshold. For the sample data, this threshold follows from a propensity quantile of 5.2%.
The plot.pie_charts
function shows the piecharts for all of the stages in the engagement policies (in platform you only see the last one) and calculates the threshold automatically. You can also give the threshold explicitly.
[4]:
vf.plot.pie_charts()
vf.plot.pie_charts(quantiles=[0.052])
Hover over the charts to see the details. For the sample data, the rightmost pie chart corresponds to the numbers in Pega as shown in the screenshot above.
Red = customers not receiving any action
Yellow = customers not receiving any “relevant” actions, sometimes also called “under served”
Green = customers that receive at least one “relevant” action, sometimes also called “well served”
With “relevant” defined as having a propensity above the threshold. This defaults to the 5th percentile.
Insights into the propensity distribution per stage is crucial. We can plot this distribution with plot.propensity_threshold
. You often see a spike at 0.5, which corresponds to models w/o responses (their propensity defaults to 0.5/1 = 0.5).
The dotted vertical line represents the computed threshold.
[5]:
vf.plot.propensity_threshold()
These different propensities represent
pyModelPropensity = the actual propensities from the models
pyPropensity = model or random propensity, depending on the ModelControl (or, when models are executed from an extension point after the standard Predictions, their propensity, but such a configuration is not supported by Value Finder)
FinalPropensity = the propensity after possible adjustments by Thompson Sampling; Thompson Sampling basically smoothes the propensities, you would expect any peak at 0.5 caused by empty models to be smoothed out
We can also look at the propensity distributions across the different stages. This is based on the model propensities, not any of the subsequent overrides:
[6]:
vf.plot.propensity_distribution()
The effect of the selection of the propensity threshold on the number of actions for a customer can be simulated by supplying a list of either quantiles or propensities to the plot.pie_charts()
function. This will generate the aggregated counts per stage, which we can plot as such:
[7]:
import numpy as np
vf.plot.pie_charts(quantiles=np.arange(0.01, 1, 0.01))
The further to the left you put the slider threshold, the more “green” you will see. As you raise the threshold, more customers will be reported as getting “not relevant” actions.
The same effect can also be visualized in a funnel. Use plot.distribution_per_threshold()
to show the threshold on the x-axis. Again, you can pass a list of quantiles or thresholds to plot custom values here.
[8]:
vf.plot.distribution_per_threshold()
[9]:
vf.plot.distribution_per_threshold(quantiles=np.arange(0.01, 1, 0.01))
You can zoom in into how individual actions are distributed across the stages. There usually are very many actions so this typically requires to zoom in into one particular group, issue etc.
In the sample data, we can filter to just the Sales actions as shown with the ‘query’
functionality below (and this snippet may not work when using your own data if there is no Sales issue).
Use the plot.funnel_chart()
function for an overview of this funnel effect throughout the stages. As a rule of thumb, if there are only a few actions in each stage, this is not a good sign. If certain actions are completely filtered out from one stage to the next, it may also be a warning of strong filtering.
[10]:
vf.plot.funnel_chart("Name", query=pl.col("Issue") == "Sales")
The above chart shows the funnel effect at the level of individual Actions. You may want to start more course-grained as shown below, by setting the level
parameters as 'Issue'
:
[11]:
vf.plot.funnel_chart("Issue")
Or just the groups for the Sales issue (again: this example may not work when using your own dataset if there is no Sales issue):
[12]:
vf.plot.funnel_chart("Group", query=pl.col("Issue") == "Sales")