Sitecore Cortex and ML: Part 7 - How to Configure Customers Segmentation—A Live Demo

Finally we have functional solution. When we run task agent and processing engine executes all steps, contact’s facets will be populated with RFM values and the number of the corresponding cluster contact belongs to.

Each of R, F and M values is in a range from 1 to 3.

RFM values

But what these numbers and their combinations mean and how we can use it? Below is a table with descriptions and recommendations for each combination (small cubes from image above).

Leaving customers

RFM Group Recommendations
111 Lost Most likely these clients have already left. It makes sense to send them an automatic chain of letters with an offer to return.
112 Single
113
121 Leaving These customers have already done some important actions on your service. You can try to get them back.
122
123
131 Leaving - Permanent These customers you need to try to be sure to return. Offer them bonuses and loyalty programs.
132 Leaving - Permanent good
133 Leaving - Permanent VIP

Sleeping customers

RFM Group Recommendations
211 Sleeping These customers remember your service. Try to engage them with promotions.
212
213
221 Sleeping - Rare with low value Maybe they're former clients. Find out why they are going to leave or left. We send them newsletters with interesting promotions.
222 Sleeping - Rare with middle value
223 Sleeping - Rare with high value
231 Sleeping - Permanent with low value These customers remember your service. Try to engage them with promotions.
232 Sleeping - Permanent with middle value
233 Sleeping - Permanent with high value

Regular customers

RFM Group Recommendations
311 Novice - Low value We send a chain of letters with a description of the benefits and answers to questions.
312 Novice with middle value
313 Novice with high value We send a chain of letters with a description of the benefits and answers to questions. Add an interesting offer to keep the interest.
321 Regular with low value We should try to increase their involvement. We send them mails with related products and services.
322 Regular - Middle value
323 Regular - High value These are good clients. Do not bore them with mailing. Only send a normal mails.
331 Very regular - Low value You can try to engage customers even more. We send them links to related products and services.
332 Very regular - Middle value These are the best customers. You can try to sell them a new product or service. Send them special offers
333 VIP

So first we will create our custom segmentation rule and use it in List Manager to create segmented lists of users based on their RFM values.

First we will create new template for RFM pattern:

RFM values

Next we will create a folder with all of our RFM combinations:

RFM patterns

And then we will create rule condition “Where contacts RFM is”:

where the contact RFM value is [RfmId,Tree,root=/sitecore/system/Settings/Foundation/ProcessingEngine/RFM Patterns,rfm]

RFM rule condition

Source code of RfmMatch condition:


public class RfmMatch : ICondition, IContactSearchQueryFactory
{
    public Guid RfmId { get; set; }
    public bool Evaluate(IRuleExecutionContext context)
    {
        var contact = context.Fact();
        var facet = contact.GetFacet(RfmContactFacet.DefaultFacetKey);
        if (facet == null) return false;

        var rfm = GetRfm();
        if (rfm == null) return false;

        return facet.R == rfm.R && facet.F == rfm.F && facet.M == rfm.M;
    }

    public Expression< />> CreateContactSearchQuery(IContactSearchQueryContext context)
    {
        var rfm = GetRfm();
        if (rfm == null) return x => false;

        return contact => contact.GetFacet(RfmContactFacet.DefaultFacetKey).R == rfm.R
              && contact.GetFacet(RfmContactFacet.DefaultFacetKey).F == rfm.F
              && contact.GetFacet(RfmContactFacet.DefaultFacetKey).M == rfm.M;
    }

    public CustomerBusinessValue GetRfm()
    {
        int r, f, m;
        Item rfmPattern = Database.GetDatabase("master").GetItem(new ID(RfmId));
        if (rfmPattern == null) return null;

        if (int.TryParse(rfmPattern["R"], out r))
        {
            if (int.TryParse(rfmPattern["F"], out f))
            {
                if(int.TryParse(rfmPattern["M"], out m))
                {
                    return new CustomerBusinessValue
                    {
                        R = r,
                        F = f,
                        M = m
                    };
                }
            }
        }

        return null;
    }
}

Now we can navigate to List Manager and create segmented list, for example for VIP customers. We can use this list to send them special offers.

RFM rule builder

VIP list

Also we can create similar rule condition for personalization:

RFM personalization rule

Source code of PersonalizeRfm rule condition:


public class PersonalizeRfm : StringOperatorCondition where T : RuleContext
{
    public Guid RfmId { get; set; }

    protected override bool Execute(T ruleContext)
    {
        if (!Tracker.Current.IsActive || Tracker.Current.Contact == null) return false;

        var xConnectFacets = Tracker.Current.Contact.GetFacet("XConnectFacets");
        if (xConnectFacets.IsEmpty || xConnectFacets.Facets == null ||
            !xConnectFacets.Facets.ContainsKey(RfmContactFacet.DefaultFacetKey)) return false;

        RfmContactFacet facet = xConnectFacets.Facets[RfmContactFacet.DefaultFacetKey] as RfmContactFacet;

        if (facet == null) return false;

        var rfm = GetRfm();
        if (rfm == null) return false;

        return facet.R == rfm.R && facet.F == rfm.F && facet.M == rfm.M;
    }

    public CustomerBusinessValue GetRfm()
    {
        int r, f, m;
        Item rfmPattern = Database.GetDatabase("master").GetItem(new ID(RfmId));
        if (rfmPattern == null) return null;

        if (int.TryParse(rfmPattern["R"], out r))
        {
            if (int.TryParse(rfmPattern["F"], out f))
            {
                if (int.TryParse(rfmPattern["M"], out m))
                {
                    return new CustomerBusinessValue
                    {
                        R = r,
                        F = f,
                        M = m
                    };
                }
            }
        }

        return null;
    }
}

For demo purposes we create two renderings “Demo” and “Demo VIP”, both will be rendered with different static images. Let`s personalize renderings for Home page. Scenario: if current contact matches VIP rfm-pattern then we show him “Demo VIP” rendering otherwise “Demo”.

Content Personalization

When we open Home page in browser we will see “Demo” rendering, because our user is not VIP:

Usual Person

Next we choose any VIP user from previously created segmented list, copy his email and submit form by clicking ‘Identify’ button. Once page is reload we will see “Demo VIP” rendering content:

VIP Person

But we have 27 RFM patterns and it is not convenient for content managers to make personalization, targeting or advertising campaign based on 27 rules. Exactly for this we use clustering. Our ML engine divided all customers in several clusters based on similarity of their purchasing ability. In our demo scenario we use 5 clusters, this number can be changed according to marketing needs.

Let`s check how ML divides customer into clusters. When ML completes train of model we will calculate Evaluation metrics of resulted train model and run test data prediction to see statistics and cluster groups. It help us to understand what kind of customers belongs to concrete cluster.

RFM cluster groups

As you see customers were divided into following clusters:

  • Cluster 4: Lost, Single, Sleeping, Novise with small monetary value (the worst customers)

  • Cluster 3: Leaving, Sleeping with average monetary and frequency but very rare (a little bit better than cluster 4)

  • Cluster 1: Single, Leaving, Sleeping, Novise with biggest monetary value but very rare (better than cluster 3)

  • Cluster 2: Sleeping, Regular, VIP with biggest monetary value (our VIP customers)

  • Cluster 5: Regular (our regular customers)

And now we can create rule conditions similar to RFM patterns, but for Cluster number instead of RFM:

Cluster rule conditions

Source code of ClusterMatch rule condition:


public class ClusterMatch : ICondition, IContactSearchQueryFactory
{
    public NumericOperationType Comparison { get; set; }

    public int Number { get; set; }
    public bool Evaluate(IRuleExecutionContext context)
    {
        var contact = context.Fact();
        var facet = contact.GetFacet(RfmContactFacet.DefaultFacetKey);
        if (facet == null) return false;
        int cluster = facet.Cluster;

        return Comparison.Evaluate(cluster, Number);
    }

    public Expression< />> CreateContactSearchQuery(IContactSearchQueryContext context)
    {
        return contact => Comparison.Evaluate(contact.GetFacet(RfmContactFacet.DefaultFacetKey).Cluster, Number);
    }
}

Source code of PersonalizeCluster rule condition:


public class PersonalizeCluster : StringOperatorCondition where T : RuleContext
{
    public int Number { get; set; }

    protected override bool Execute(T ruleContext)
    {
        if (!Tracker.Current.IsActive || Tracker.Current.Contact == null) return false;

        var xConnectFacets = Tracker.Current.Contact.GetFacet("XConnectFacets");
        if (xConnectFacets.IsEmpty || xConnectFacets.Facets == null ||
            !xConnectFacets.Facets.ContainsKey(RfmContactFacet.DefaultFacetKey)) return false;

        RfmContactFacet facet = xConnectFacets.Facets[RfmContactFacet.DefaultFacetKey] as RfmContactFacet;

        if (facet == null) return false;

        return facet.Cluster == Number;
    }
}

Table of contents Dive into Sitecore Cortex and Machine Learning - Introduction


Source code https://github.com/x3mxray/Cortex.Demo.RFM


Do you need help with your Sitecore project?
VIEW SITECORE SERVICES