Mathew K Analytics

Lesson 44 · Python for Retail E-commerce Analytics

Predicting Customer Churn in Retail Using Python Analytics

In this lesson, you will learn how to predict which customers are at risk of churning in a retail business. Customer churn means the loss of customers who…

⬇ Download notebookOpen in Colab ↗

What you'll learn

Data

No separate download needed — the notebook creates or downloads everything it uses.

📓 Full notebook

Download .ipynb

Predicting Customer Churn in Retail#

  • In this lesson, you will learn how to predict which customers are at risk of churning in a retail business.
  • Customer churn means the loss of customers who stop buying from your store.
  • Predicting churn helps businesses retain valuable buyers and boost long-term revenue.
  • You will analyze real retail transaction data to spot signs of customer inactivity.
  • The business insight is identifying patterns that suggest when a customer is likely to leave, so teams can take action.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')

What Retail Datasets Contain#

  • Most retail datasets include transactions, orders, products, and customer data.
  • Transactions represent what, when, and how much customers buy.
  • Sales metrics like quantity, price, and revenue help measure customer activity.
  • It is easy to make mistakes by confusing quantities with revenue, or by ignoring missing data.
  • Always check dataset columns before starting analysis.
# Beginner Example 1: Load the Online Retail Transactions dataset
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/00502/online_retail_II.xlsx'
df = pd.read_excel(url, sheet_name='Year 2010-2011')
df['InvoiceDate'] = pd.to_datetime(df['InvoiceDate'])
print('Shape:', df.shape)
print(df.head(3))
Shape: (541910, 8)
  Invoice StockCode                         Description  Quantity  \
0  536365    85123A  WHITE HANGING HEART T-LIGHT HOLDER         6   
1  536365     71053                 WHITE METAL LANTERN         6   
2  536365    84406B      CREAM CUPID HEARTS COAT HANGER         8   

          InvoiceDate  Price  Customer ID         Country  
0 2010-12-01 08:26:00   2.55      17850.0  United Kingdom  
1 2010-12-01 08:26:00   3.39      17850.0  United Kingdom  
2 2010-12-01 08:26:00   2.75      17850.0  United Kingdom  
# Beginner Example 2: Look at unique customers
unique_customers = df['Customer ID'].nunique()
print('Number of unique customers:', unique_customers)
Number of unique customers: 4372
# Beginner Example 3: Calculate total revenue per transaction
df['Revenue'] = df['Quantity'] * df['Price']
print(df[['Invoice', 'Customer ID', 'Revenue']].head(3))
  Invoice  Customer ID  Revenue
0  536365      17850.0    15.30
1  536365      17850.0    20.34
2  536365      17850.0    22.00
# Intermediate Example 1: Calculate each customer's total revenue
customer_revenue = df.groupby('Customer ID')['Revenue'].sum().reset_index()
customer_revenue = customer_revenue.rename(columns={'Revenue': 'TotalRevenue'})
print(customer_revenue.head(3))
   Customer ID  TotalRevenue
0      12346.0          0.00
1      12347.0       4310.00
2      12348.0       1797.24
# Intermediate Example 2: Calculate the number of purchases per customer
customer_freq = df.groupby('Customer ID')['Invoice'].nunique().reset_index()
customer_freq = customer_freq.rename(columns={'Invoice': 'NumPurchases'})
print(customer_freq.head(3))
   Customer ID  NumPurchases
0      12346.0             2
1      12347.0             7
2      12348.0             4
# Intermediate Example 3: Find each customer's last purchase date
last_dates = df.groupby('Customer ID')['InvoiceDate'].max().reset_index()
last_dates = last_dates.rename(columns={'InvoiceDate': 'LastPurchaseDate'})
print(last_dates.head(3))
   Customer ID    LastPurchaseDate
0      12346.0 2011-01-18 10:17:00
1      12347.0 2011-12-07 15:52:00
2      12348.0 2011-09-25 13:13:00
# Advanced Example 1: Calculate Recency, Frequency, and Monetary (RFM) features
REFERENCE_DATE = df['InvoiceDate'].max() + pd.Timedelta(days=1)
rfm = df.groupby('Customer ID').agg({
    'InvoiceDate': lambda x: (REFERENCE_DATE - x.max()).days,
    'Invoice': 'nunique',
    'Revenue': 'sum'
}).reset_index()
rfm.columns = ['CustomerID', 'Recency', 'Frequency', 'Monetary']
print(rfm.head(3))
   CustomerID  Recency  Frequency  Monetary
0     12346.0      326          2      0.00
1     12347.0        2          7   4310.00
2     12348.0       75          4   1797.24
# Advanced Example 2: Visualize RFM segments
plt.figure(figsize=(8,6))
sns.scatterplot(data=rfm, x='Recency', y='Monetary', size='Frequency', alpha=0.6, legend=False)
plt.xlabel('Recency (days since last purchase)')
plt.ylabel('Total Monetary Value')
plt.title('Customer Segments: Recency vs Monetary')
plt.show()
No description has been provided for this image
# Advanced Example 3: Create a simple churn flag
inactive_threshold = 90
rfm['ChurnFlag'] = (rfm['Recency'] > inactive_threshold).astype(int)
print(rfm[['CustomerID', 'Recency', 'ChurnFlag']].head(5))
   CustomerID  Recency  ChurnFlag
0     12346.0      326          1
1     12347.0        2          0
2     12348.0       75          0
3     12349.0       19          0
4     12350.0      310          1
# Error Example: What if Revenue has missing values?
missing_revenue = df['Revenue'].isnull().sum()
print('Transactions with missing revenue:', missing_revenue)
Transactions with missing revenue: 0
# Error Example: Handle missing or negative quantities
n_invalid_qty = (df['Quantity'] <= 0).sum()
print('Transactions with invalid (zero or negative) quantity:', n_invalid_qty)
df_clean = df[df['Quantity'] > 0]
Transactions with invalid (zero or negative) quantity: 10624
# Error Example: Mistakenly grouping by product, not customer
product_freq = df.groupby('StockCode')['Invoice'].nunique().reset_index()
print(product_freq.head(3))
# This is not helpful for churn!
  StockCode  Invoice
0     10002       73
1     10080       24
2     10120       29

Best Practices in Retail Analytics for Churn#

  • Use RFM analysis to profile customers by activity and value.
  • Segment users by frequency and recent behavior, not just by total spend.
  • Regularly visualize trends to catch changes early.
  • Always handle missing and outlier values before making business recommendations.
  • Successful retail analytics combines smart grouping with business logic on what makes a customer at risk.

Pattern Example: Segmenting Customers by Churn Risk#

  • Segment your customers based on RFM score values.
  • High recency, low frequency, and low monetary can often signal churn.
  • Business teams use these segments to target promotions or win-back campaigns.
# Best Practice: Identify high-risk (churn) segment for targeted offers
at_risk_customers = rfm[(rfm['Recency'] > 90) & (rfm['Frequency'] <= 2)]
print('Number of at-risk customers:', at_risk_customers.shape[0])
print(at_risk_customers[['CustomerID', 'Recency', 'Frequency', 'Monetary']].head(5))
Number of at-risk customers: 1092
   CustomerID  Recency  Frequency  Monetary
0     12346.0      326          2       0.0
4     12350.0      310          1     334.4
6     12353.0      204          1      89.0
7     12354.0      232          1    1079.4
8     12355.0      214          1     459.4
# End-to-End Example: Generate a churn prediction report
report = at_risk_customers[['CustomerID', 'Recency', 'Frequency', 'Monetary']].copy()
report['RecommendedAction'] = 'Send Re-engagement Offer'
report.to_csv('churn_report.csv', index=False)
print('Churn prediction report saved as churn_report.csv')
Churn prediction report saved as churn_report.csv

Congratulations, you have completed the hands-on churn prediction lesson!#

  • For further learning, search YouTube for 'retail churn analytics with Python'.
  • Try adapting these techniques to your own store data for real performance improvements.

Found this useful?

All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.