
All companies have more and more customer data based on behaviors and simple but powerfull way to categorize this clients is RFM segmentation.
The RFM segmentation is a solution for split our customers on segments(clusters) according to their behavior like recency, frequency and the monetary value.
The RFM segmentation will allow us:
- Drive customer segmentation strategy
- Trigger automated marketing campaigns
- Build smarter remarketing campaigns
The goal for this method is to categorize our customers on segments using three variables Recency, Frequency and Monetary value (hence the name RFM).
Today, the RFM model is used by digital marketers to send relevant marketing messages, keep their customers engaged and maximize the lifetime value of each customer.
The RFM segmentation should be one of the first customers segmentation of any organization.
So there, we will explain all steps to do for a successful RFM segmentation.
Here, we will use real-world customer dataset with 31 variables describes 83,590 instances (customers) from a hotel in Lisbon, Portugal.
You can download data files from there (you may be should login in before downloading).
All script of this article are there.
- Compute RFM Score
Here, we have two revenue sources, LodgingRevenue and OtherRevenue so we should create a new variable ‘Monetary_value’ which is the sum of the other two.
Next, we keep only the minimum ‘DaysSinceLastStay’ as Recency.
Finally, we count the number of reservation to get the frequency variable.
############################################################
# We keep only some variable for the segmentation
############################################################colonnes_RFM = ['DocIDHash','ID', 'LodgingRevenue','OtherRevenue',
'DaysSinceLastStay']
df_rfm = df[colonnes_RFM]############################################################
# Create Recency variable
############################################################
df_rfm.rename(columns={'DaysSinceLastStay':'recency'}, inplace=True)
rfm = pd.merge(rfm, df_rfm.groupby(['DocIDHash'])[['recency']].
.min().reset_index(), how='inner', on='DocIDHash')############################################################
# Create Frequency variable
############################################################
rfm = df_rfm.groupby(['DocIDHash'])[['ID']].nunique().
reset_index().rename(columns={'ID':'frequency'})############################################################
# Create Monetary Value variable
############################################################
df_rfm['monetary_value'] = df_rfm['LodgingRevenue'] +
df_rfm['OtherRevenue']
rfm = pd.merge(rfm, df_rfm.groupby(['DocIDHash']).
[['monetary_value']].sum().reset_index(), how='inner',
on='DocIDHash')############################################################
# Then we compute quantiles
############################################################
quantiles = rfm.quantile(q=[0.20,0.40, 0.60,0.80])
quantiles = quantiles.to_dict()############################################################
# This two function to cast the continues variables Recency,
# Frequency and Monetary Value to discontinues variables
############################################################# Convert recency variable
def RClass(x,p,d):
if x <= d[p][0.2]:
return 1
elif x <= d[p][0.40]:
return 2
elif x <= d[p][0.60]:
return 3
elif x <= d[p][0.8]:
return 4
else:
return 5# Convert Frequency and Monetary Value variables
# Create New discontinue variables from continues ones
def FMClass(x,p,d):
if x <= d[p][0.20]:
return 5
elif x <= d[p][0.40]:
return 4
elif x <= d[p][0.60]:
return 3
elif x <= d[p][0.80]:
return 2
else:
return 1
rfm['R_Quartile'] = rfm['recency'].apply(RClass, args=
('recency',quantiles,))
rfm['F_Quartile'] = rfm['frequency'].apply(FMClass, args=
('frequency',quantiles,))
rfm['M_Quartile'] = rfm['monetary_value'].apply(FMClass, args=
('monetary_value',quantiles,))############################################################
# Get The RFM Score
############################################################
rfm['RFMScore'] = rfm['R_Quartile'].astype('str') +
rfm['F_Quartile'].astype('str') +
rfm['M_Quartile'].astype('str')
RFM Scores allow you to create classes that will allow your team to look how often a customer shops with you and how valuable they are.
These patterns created will allow your team to create very personalized messaging.
So there we can see how many customers we have by segment :
######################################################
# shape of each segment created
######################################################
rfm.groupby(['RFMScore'])['DocIDHash'].nunique().
reset_index().rename(columns={'DocIDHash':'Nb
Customers'})########### We get
RFMScore Nb Customers
111 85
112 69
113 78
...
315 5
So, as you can see it, the shape of some segment is very small and personalizes marketing message for this small segments can be optimized.
The solution is to aggregate this small segment on bigger segments:
╔═══════════╦══════════════════════════════════════════════════════╗
║ Segment ║ Score ║
╠═══════════╬══════════════════════════════════════════════════════╣
║ Champions ║111, 112, 122, 121, 212, 211, 221 ║
║ ║------------------------------------------------------║
║ ║ Marketing Actions ║
║ ║------------------------------------------------------║
║ ║Give them something extra that the regulars do not get║
║ ║For example, limited series of products or special ║ ║ ║discounts to make them feel valued : You might make ║
║ ║them your ambassadors, giving them a margin of your ║
║ ║profits for bringing you, new customers ║
╠═══════════╬══════════════════════════════════════════════════════╣
║ Loyal ║123, 222, 231, 311, 312, 321, 322,331
║ ║------------------------------------------------------║
║ ║ Marketing Actions ║
║ ║------------------------------------------------------║
║ ║Your goal for this segment is to make them even more ║
║ ║satisfied to preserve their current behavior. As you ║
║ ║know these customers well use highly personalized ║
║ ║communication ║
╠═══════════╬══════════════════════════════════════════════════════╣
║Potential ║113, 115, 114, 125, 124, 133, 134, 135, 214, 215, 224,║
║Loyalist ║225, 235, 213, 233, 234, 243, 313, 314, 315, 324,325, ║
║ ║333, 343 ║
║ ║------------------------------------------------------║
║ ║ Marketing Actions ║
║ ║------------------------------------------------------║
║ ║These customers already bought from you more than once║ ║ ║but the size of their basket was not too big. Try to ║
║ ║motivate them to increase the number of items in their║ ║ ║cart by showing them cross-selling recommendations. ║
╠═══════════╬══════════════════════════════════════════════════════╣
║New ║154, 155, 244, 245 254, 255, 355 ║
║Customers ║------------------------------------------------------║
║ ║ Marketing Actions ║
║ ║------------------------------------------------------║
║ ║Possibly this is their first purchase : You do not ║
║ ║know these customers yet so they still have the ║
║ ║potential to turn up as highly valuable. ║
║ ║You should offer them discounts for an additional ║
║ ║product to see whether they are the kinds of the ║
║ ║customer to whom you can upsell. ║
╠═══════════╬══════════════════════════════════════════════════════╣
║Promising ║141, 142, 143, 144, 145, 151, 152,153, 241,242, 253, ║
║ ║252,251, 351, 352, 353 ║
║ ║------------------------------------------------------║
║ ║ Marketing Actions ║
║ ║------------------------------------------------------║
║ ║Possibly this is their first purchase for high value: ║
║ ║You need to motivate them to make another purchase ║
║ ║because it can be another high monetary value purchase║ ║ ║The high value they bring allow you to invest in this ║
║ ║segment to turn them into regular spenders. ║
╠═══════════╬══════════════════════════════════════════════════════╣║Need ║131, 132, 223, 232, 323, 332, 341, 342 ║
║Attention ║------------------------------------------------------║
║ ║ Marketing Actions ║
║ ║------------------------------------------------------║
║ ║They are considering to buy a new product, and you ║
║ ║should motivate them to choose you over competitors. ║
║ ║You should communicate to this segment a time-limited ║ ║ ║promotional campaigns. ║
║ ║Use product recommendations based on their behavior to║
║ ║recommend a new product=> show them you know them. ║
╠═══════════╬══════════════════════════════════════════════════════╣
║About To ║335, 345, 354, 445, 453, 435, 425, 415 ║
║Sleep ║------------------------------------------------------║
║ ║ Marketing Actions ║
║ ║------------------------------------------------------║
║ ║They don't make a purchase since a long time but they ║
║ ║still approachable using discounts. This discounts ║
║ ║motivate them and revive their interest. ║
╠═══════════╬══════════════════════════════════════════════════════╣
║At Risk ║411, 412, 421, 422, 413, 414, 423, 424, 431, 432, 441,║
║ ║442,513, 514, 521, 523, 524, 531, 532,533, 541,542 ║
║ ║------------------------------------------------------║
║ ║ Marketing Actions ║
║ ║------------------------------------------------------║
║ ║The customer value of the members of this segment is ║
║ ║above average but thy don't made a purchase recently. ║
║ ║It's seems that they still buying products but from ║ ║ ║your competitors. ║
║ ║You should prepare discounts and gifts for this ║
║ ║segments. They already give you high value so you can ║
║ ║invest on them. Use product-recommandation engine. ║
╠═══════════╬══════════════════════════════════════════════════════╣
║Cannot ║511, 512, 522, 452,451,551, 552, 553 ║
║Lose Them ║------------------------------------------------------║
║ ║ Marketing Actions ║
║ ║------------------------------------------------------║
║ ║This segments is similar to the above segment, the ║
║ ║only difference is about the recency. This segment is ║
║ ║made a purchase less recently than 'At Risk' segment. ║ ║ ║Use the same strategy than the above segment but this ║
║ ║segment is less valuable than the above one. ║
╠═══════════╬══════════════════════════════════════════════════════╣
║Hibernating║334, 344, 435, 425, 415, 433, 434, 443, 444, 534, 543,║
║customers ║544, 454, 455 ║
║ ║------------------------------------------------------║
║ ║ Marketing Actions ║
║ ║------------------------------------------------------║
║ ║The customer value of the members of this segment is ║
║ ║bellow average. Do not overspend on this segment. ║
║ ║You can include them on standard communication and ║ ║ ║give them some discounts or free product after xxx ║
║ ║euros spent. ║
╠═══════════╬══════════════════════════════════════════════════════╣
║Lost ║555, 554, 545, 535,525,515 ║
║customers ║------------------------------------------------------║
║ ║ Marketing Actions ║
║ ║------------------------------------------------------║
║ ║This customers generate a small part of revenue. This ║
║ ║segments have a lowest priority. Do not resources and ║
║ ║time on them. But you can send them some discounts and║
║ ║free products and analyses behavior after that. ║
╚═══════════╩══════════════════════════════════════════════════════╝
So then we can aggregate RFMScore on new segments according the above details :
################################################################
# Create segments by aggregating RFM SCores
################################################################
# First we download the segments names by RFM Score
segments_names = pd.read_csv('./results/segments.csv')
rfm = pd.merge(rfm, segments_names, how='inner', left_on='RFMScore',
right_on='segments').drop('segments', axis=1)
# Get the number of customers for each segment after aggregation
rfm.groupby(['segment_name'['DocIDHash'].nunique().reset_index().ren
ame(columns={'DocIDHash':'Nb Customers'})
As you can see, the number of customers by segment is acceptable and marketing actions can be useful.
2. Create classes using CAH
If the segments created above this section are not what you want you can use other methods to create your own segments.
Here we will present you one of them to create a personalized segments.
This method is CAH clustering to aggregate segments created by the RFM method.
The first step consist on determinate the centroid of each RFM segment (mean values of each variable of the created clusters) :
rfm_centroid = rfm.groupby('RFMScore')
[['recency','frequency','monetary_value']].mean()
And then we run a CAH clustering :
from matplotlib import pyplot as plt
from scipy.cluster.hierarchy import dendrogram, linkage################################################
##Generate Links matrix
################################################
Z = linkage(rfm_centroid,method='ward',metric='euclidean')################################################
##Print dendrogram
################################################
plt.title("CAH : Aggregated segments")
dendrogram(Z,labels=rfm_centroid.index, orientation='left',
color_threshold=2300)
plt.show()###############################################
## you can change the value of color_threshold to select the number of cluster that you want
Here, we keep only 4 clusters (you can keep more or less segments if you want by changing the color_threshold value):
╔═══════════╦══════════════════════════════════════════════════════╗
║ Segment ║ Score ║
╠═══════════╬══════════════════════════════════════════════════════╣
║Best ║111 ║
║Customers ║------------------------------------------------------║
║ ║ Marketing Actions ║
║ ║------------------------------------------------------║
║ ║Give them something extra that the regulars do not get║
║ ║For example, limited series of products or special ║ ║ ║discounts to make them feel valued : You might make ║
║ ║them your ambassadors, giving them a margin of your ║
║ ║profits for bringing you, new customers ║
╠═══════════╬══════════════════════════════════════════════════════╣
║Big ║211, 351, 451, 311, 411, 511, 551, 251 ║
║Spenders ║------------------------------------------------------║
║ ║ Marketing Actions ║
║ ║------------------------------------------------------║
║ ║Propose them your most expensive product.This segment ║
║ ║have the greatest purchasing power. ║
╠═══════════╬══════════════════════════════════════════════════════╣
║Almost ║412, 413, 414, 415, 452, 555, 554, 454, 455, 512, 513,║
║Lost ║514, 552, 553, 453 ║
║ ║------------------------------------------------------║
║ ║ Marketing Actions ║
║ ║------------------------------------------------------║
║ ║These customers already bought, a long time ago, from ║
║ ║you but You are loosing them. Try to motivate them by ║
║ ║promotion and gifts. ║
╠═══════════╬══════════════════════════════════════════════════════╣
║Promising ║252, 155, 353, 352, 253, 254, 354, 114, 115, 214, 255,║
║ ║312, 314, 113, 213, 212, 313, 112, 355, 315, 215 ║
║ ║------------------------------------------------------║
║ ║ Marketing Actions ║
║ ║------------------------------------------------------║
║ ║These customers already bought from you but the size ║ ║ ║of their basket was not too big. Try to motivate them ║
║ ║to increase the number of items in their cart by ║ ║ ║showing them cross-selling recommendations. ║
╚═══════════╩══════════════════════════════════════════════════════╝
3. Go Further RFM Segmentation
The RFM Segmentation can be the first step on your customer knowledge but we can improve it easily by profiling each segment.
The profiling step consist on determinate characteristics behavior for each segment :
Examples:
- The average age of this class is 44 years
- The favorite channel distribution of this segment is “Travel Agent/Operator”
- The average spend by this segments is 13 465 euros
- They have 45 reservation in average
- The last reservation is since -1 days (customers coming tomorrow)
- They are from France/Germany and UK
- …
All scripts are there : https://github.com/Faouzizi/RFM-Analysis
Conclusion
After that, you are able to create your own RFM segmentation and communicate effectively according to the target.
Hope that this article can help you 🙂