Customer Segmentation for Analysts: A Practical Guide
Customer segmentation for analysts, worked through on a real online shop's 4,293 customers: computing recency, frequency and monetary value, scoring them into quintiles, turning scores into named segments, finding that a quarter of customers bring two thirds of revenue, and deciding what to do with each group.
GloryTecks Team
Training & Placement Faculty
Last updated: 25 September 2026
Treating every customer the same wastes money: discounts go to people who would have bought anyway, while valuable customers drifting away get the same newsletter as everyone else. Segmentation groups customers so each group can be treated appropriately. For analysts, the most practical starting point is RFM: recency, frequency and monetary value, three numbers that describe purchase behaviour and can be computed from any transaction table (Wikipedia: RFM).
This guide segments the customers of a real UK online gift retailer (UCI: Online Retail), the same data used in a published RFM case study of this retailer (Chen, Sain and Guo, 2012).
Step 1: Compute recency, frequency and monetary value
For each customer, as of a snapshot date:
- Recency: days since the last purchase. Lower is better.
- Frequency: number of distinct orders.
- Monetary: total spend.
import io
import urllib.request
import zipfile
import pandas as pd
url = "https://archive.ics.uci.edu/static/public/352/online+retail.zip"
with zipfile.ZipFile(io.BytesIO(urllib.request.urlopen(url).read())) as archive:
raw = pd.read_excel(archive.open("Online Retail.xlsx"), dtype={"InvoiceNo": str, "StockCode": str})
services = {"POST", "DOT", "M", "m", "C2", "D", "S", "B", "BANK CHARGES", "AMAZONFEE", "CRUK"}
sales = raw[~raw["InvoiceNo"].str.startswith("C") & ~raw["StockCode"].isin(services)
& ~raw["StockCode"].str.startswith("gift_") & (raw["Quantity"] > 0) & (raw["UnitPrice"] > 0)
& raw["CustomerID"].notna() & (raw["InvoiceDate"] < "2011-12-01")]
sales = sales.assign(customer=sales["CustomerID"].astype(int), revenue=sales["Quantity"] * sales["UnitPrice"])
snapshot = pd.Timestamp("2011-12-01")
rfm = sales.groupby("customer").agg(last_purchase=("InvoiceDate", "max"),
frequency=("InvoiceNo", "nunique"),
monetary=("revenue", "sum"))
rfm["recency"] = (snapshot - rfm["last_purchase"]).dt.days
print(len(rfm), "customers")
print(rfm[["recency", "frequency", "monetary"]].median().round(1).to_dict(), "(medians)")4293 customers
{'recency': 49.0, 'frequency': 2.0, 'monetary': 653.2} (medians)Only purchases with a customer ID can be attributed, and cancellations, postage and fees are excluded, so the measures reflect real product purchases. The typical customer last bought 49 days before the snapshot, has placed two orders and spent about 650 pounds.
Step 2: Score each measure from 1 to 5
Raw values are on very different scales and heavily skewed, so each is converted to a quintile score: the top fifth of customers gets 5, the bottom fifth 1 (pandas: qcut). For recency the order is reversed, so the most recent buyers score 5:
rfm["R"] = pd.qcut(rfm["recency"], 5, labels=[5, 4, 3, 2, 1]).astype(int) # recent = high score
rfm["F"] = pd.qcut(rfm["frequency"].rank(method="first"), 5, labels=[1, 2, 3, 4, 5]).astype(int)
rfm["M"] = pd.qcut(rfm["monetary"], 5, labels=[1, 2, 3, 4, 5]).astype(int)
def segment(row):
if row.R >= 4 and row.F >= 4:
return "champions"
if row.R >= 3 and row.F >= 3:
return "loyal"
if row.R >= 4:
return "new or occasional"
if row.F >= 3:
return "at risk"
return "lapsed"
rfm["segment"] = rfm.apply(segment, axis=1)
summary = rfm.groupby("segment").agg(customers=("R", "size"), median_days_since=("recency", "median"),
median_orders=("frequency", "median"), revenue=("monetary", "sum"))
summary["share of customers"] = summary["customers"] / summary["customers"].sum()
summary["share of revenue"] = summary["revenue"] / summary["revenue"].sum()
print(summary.drop(columns="revenue").sort_values("share of revenue", ascending=False).round(3).to_string()) customers median_days_since median_orders share of customers share of revenue
segment
champions 1105 10.0 6.0 0.257 0.678
loyal 795 37.0 3.0 0.185 0.127
at risk 676 135.0 3.0 0.157 0.099
lapsed 1377 168.0 1.0 0.321 0.078
new or occasional 340 16.0 1.0 0.079 0.017Frequency needs one extra step: half the customers have placed only one or two orders, so many share the same value and quintile cut points would collide. Ranking first breaks the ties so each fifth has the same number of customers. The segment rules combine recency and frequency, the two measures that describe behaviour; monetary value is kept for reporting what each segment is worth. There are many valid ways to define RFM scores and segments, and the right one depends on the business (Wikipedia: RFM).
Step 3: Read the segments as a business would
- Champions: a quarter of customers, bought within the last 10 days at the median, six orders each, and 68% of revenue. Protect this group above all.
- Loyal: regular buyers, slightly less recent, 13% of revenue. The pool from which future champions come.
- At risk: used to buy regularly, three orders at the median, but typically not for 135 days. Together they brought 10% of revenue; winning them back is often cheaper than finding new customers of the same value.
- Lapsed: a third of all customers, one order, last seen about five and a half months ago. Individually low value; target cheaply, if at all.
- New or occasional: bought recently but rarely. The next purchase decides whether they become loyal.
The concentration is striking but typical: 26% of customers bring 68% of revenue. For a shop where many customers are wholesalers, losing a few champions matters more than acquiring many one-off buyers.
Step 4: Turn segments into actions and measure them
| Segment | Example action | Success measure |
|---|---|---|
| Champions | Early access, account management, no blanket discounts | Retention and order frequency |
| Loyal | Recommendations to broaden what they buy | Movement into champions |
| At risk | Personal win-back contact or offer | Share reactivated within 60 days |
| New or occasional | Welcome series, second-order incentive | Second-purchase rate |
| Lapsed | Low-cost reminder, then stop | Reactivation relative to cost |
Test actions before rolling them out: send the win-back offer to a random half of the at-risk group and compare their reactivation with the other half's. Without a control group, customers who would have returned anyway make any campaign look successful.
Common segmentation mistakes
- Too many segments. Eleven finely named groups look sophisticated, but a marketing team can act on four or five. Merge segments that would receive the same treatment.
- Segments without actions. If two segments would be treated identically, the distinction adds reporting work and no value.
- Using a stale snapshot. A customer who was a champion six months ago may be at risk today; recency moves every day.
- Ignoring the business model. For a wholesaler, frequency reflects restocking cycles; for a gift shop selling to consumers, a single large yearly order may be perfectly healthy. Set thresholds with people who know the customers.
- Discounting the best customers by default. Champions often buy without incentives; blanket offers to them can cost more than they return.
Keeping segments useful
- Refresh regularly. Recency changes daily; recompute monthly or weekly and track how customers move between segments, since movement is often more informative than the snapshot.
- Watch the edges. Customers without IDs, one-off wholesale orders and returns can distort scores; state what is excluded.
- Add other dimensions when needed: product categories, channel or region. Clustering methods such as k-means can find data-driven groups, but rule-based RFM segments are easier to explain and act on.
- Combine with cohorts. Cohort analysis shows whether newly acquired customers are becoming loyal over time, which RFM snapshots alone cannot.
What is RFM analysis?
Should I use RFM or clustering?
How often should segments be updated?
Can RFM work without monetary data?
For how segments fit with funnels and retention, see product analytics 101. Customer segmentation is part of the business analytics concepts module of the Data Analytics course.
Sources
- RFM (market research) (Wikipedia) — Wikipedia
- Data mining for the online retail industry: A case study of RFM model-based customer segmentation using data mining — Journal of Database Marketing & Customer Strategy Management, 2012
- Online Retail (UCI Machine Learning Repository) — UCI Machine Learning Repository
- pandas.qcut — pandas documentation
GloryTecks Team
Training & Placement Faculty
The GloryTecks faculty team mentors learners across Data Science, AI and Data Engineering, with a focus on real-time projects and placement readiness in Hyderabad.
Want to master Data Analytics?
Join GloryTecks’ expert-led Data Analytics training in Hyderabad with real-time projects and 100% placement support.
Related articles
Data Cleaning: A Practical Step-by-Step Guide
A step-by-step data cleaning guide on 541,909 real transaction lines: profiling before touching anything, removing duplicates, standardising messy text, fixing inconsistent categories, investigating extreme values, keeping a cleaning log, and validation checks that caught a problem the cleaning itself created.
How to Tell a Story with Data: A Practical Framework
A framework for telling a story with data: five steps, context, change, cause, consequence and choice, organised with the main message first so the audience never gets lost, applied to a real online retailer's year from a flat summer to a pre-Christmas surge, with the chart for each step and the traps to avoid.
SQL for Data Analysts: The Queries You Need Daily
The SQL an analyst writes every day, each query run on a real sample database: profiling a table before trusting it, reconciling totals, monthly reports that keep empty months, share of total with a window, period-over-period change with LAG, new versus returning customers and the latest record per customer.