Simple Customer Segmentation Using RFM Analysis | by Chi Nguyen | Towards Data Science

RFM analysis is a customer behavior segmentation technique. Based on customers’ historical transactions, RFM analysis focuses on 3 main aspects of customers’ transactions: recency, frequency and purchase amount. Understanding these behaviors will allow businesses to cluster different customers into groups.
Here is the dataset of a store whose customers are coming from all over the world. It includes information such as invoice number, invoice date, customer id, stock code, description of the product, purchased quantity and country where the customer lives. In this article, I will only show you my method of doing the RFM analysis, and not my steps in cleaning the dataset. Figure 1 & 2 below are the results of my dataset after being edited and transformed.
Firstly, I will clarify the definition of RFM in my analysis.
Recency (R): How recently customers have made their purchases.
Frequency (F): How often customers have made their purchases.
Monetary (M): How much money customers have paid for their purchases.
Next, I will calculate these 3 components for each of the customers.
Recency (R)
import datetime###Calculate total_amount of money for each orderdf5.InvoiceDate = pd.to_datetime(df5.InvoiceDate)df5['amount'] = df5.Quantity*df5.UnitPricedf6=df5.copy()###Taking a reference date to calculate the gap between this reference date and the last purchase date of each customer.The gap can be referred as the recency of each customerreference_date = df6.InvoiceDate.max() + datetime.timedelta(days = 1)df6['days_from_last_purchase'] = (reference_date - df6.InvoiceDate).astype('timedelta64[D]')lastpurchase_day = df6[['CustomerID','days_from_last_purchase']].groupby('CustomerID').min().reset_index()lastpurchase_day.rename(columns={'days_from_last_purchase':'recency'}, inplace=True)
After calculating number of days since the last purchase of each customer, I have an output as below:
Frequency (F)
###Calculate number of orders purchased by each customerfreq = df6[['CustomerID','InvoiceNo']].groupby(['CustomerID','InvoiceNo']).count().reset_index().\groupby(["CustomerID"]).count().reset_index()freq.rename(columns = {'InvoiceNo':'frequency'}, inplace = True) 
The result of customers’ frequency is as the following:
Monetary (M)
###Total amount of money spent per customermoney = df6[['CustomerID','amount']].groupby('CustomerID').sum().reset_index()money.rename(columns = {'amount':'monetary'}, inplace = True) 
Output:
Eventually, when I combine these 3 indicators, here is the RFM information for each customer.
RFM Score
After having RFM information for each customer, I will give each buyer a RFM score based on her/his RFM data. The benchmark for my scoring will depend on the percentile of each indicator. In details, you can see the code below for more reference:
###Calculating quantile valuesquintiles = rfm[['recency', 'frequency', 'monetary']].quantile([.2, .25, .3, .35, .4, .5, .6, .7, .8, .9]).to_dict()###Benchmark to give score for recency indicatordef r_score(r):    if r < quintiles['recency'][.2]:        return 3     elif r < quintiles['recency'][.8]:        return 2    else:         return 1###Benchmark to give score for frequency & monetary indicator.   def fm_score(f):     if f > quintiles['frequency'][.8]:        return 3    elif f > quintiles['frequency'][.2]:         return 2    else:         return 1
Applying this rule to the data frame:
rfm2 = rfm.copy()rfm2['r_score'] = rfm2.recency.apply(lambda x: r_score(x))rfm2['f_score'] = rfm2.frequency.apply(lambda x: fm_score(x))rfm2['m_score'] = rfm2.monetary.apply(lambda x: fm_score(x))rfm2['rfm'] = rfm2['r_score'].map(str)+rfm2['f_score'].map(str) + rfm2['m_score'].map(str)
Each customer now has a RFM score:
Now, this is my favorite step as I can divide the group in whichever way I want. However, it is important to consider your business situations when categorizing customers. Different business purposes will generate different types of grouping and in turn different strategies.
In this section, I will divide my customers into 7 groups, each of which is labeled as below:
###Loyal Customers, who are the champions of all the customers with highest score of RFM. rfm2_group1 = rfm2[rfm2['rfm']=='333']rfm2_group1['label'] = 'champion'###Customers who have the most potential to become the Champions. They recently buy the products and they make their purchases quite frequently. Moreover, the amount they spent is quite great. rfm2_group2 = rfm2[rfm2['rfm'].str.contains('332|331|323|313')] rfm2_group2['label'] = 'potential1'###Customers whose frequency score and monetary score are slightly lower than potential 1 grouprfm2_group3 = rfm2[rfm2['rfm'].str.contains('321|322|311|312')] rfm2_group3['label'] = 'potential2'###Customers who used to pay a lot of money and come to the store frequently. They did not purchase recently. rfm2_group4 = rfm2[rfm2['rfm'].str.contains('233')]rfm2_group4['label'] = 'needing_attention1'###Customers who do not come to store often and not frequently make purchases.rfm2_group5 = rfm2[rfm2['rfm'].str.contains('223|213|212|231|232|211|221|222')]rfm2_group5['label'] = 'needing_attention2'###Customers who haven't paid a visit to the store for a long time. However, once in a while, they do spend lot of moneyrfm2_group6 = rfm2[rfm2['rfm'].str.contains('132|123|113|133')]rfm2_group6['label'] = 'lost1'###Customers who churnrfm2_group7 = rfm2[rfm2['rfm'].str.contains('111|112|121|122|131')]rfm2_group7['label'] = 'lost2'
Above is a simple analysis of RFM. However, RFM may be a lot more meaningful when combined with other deep dive analysis. I hope that this article may be a helpful source of reference for your future work.