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

6 May 2026 6 min read

Last updated: 25 September 2026

Share:

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.
python
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)")
text
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:

python
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())
text
                   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.017

Frequency 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

SegmentExample actionSuccess measure
ChampionsEarly access, account management, no blanket discountsRetention and order frequency
LoyalRecommendations to broaden what they buyMovement into champions
At riskPersonal win-back contact or offerShare reactivated within 60 days
New or occasionalWelcome series, second-order incentiveSecond-purchase rate
LapsedLow-cost reminder, then stopReactivation 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?

A way to describe customers by how recently they bought, how often, and how much they spent, usually scored and combined into segments for marketing and reporting.

Should I use RFM or clustering?

Start with RFM: it is transparent, quick and easy to act on. Use clustering when you have many behavioural variables and want the data to suggest groups, then check the clusters make business sense.

How often should segments be updated?

As often as decisions are made from them, typically monthly for retail and weekly for fast-moving businesses. Track movement between segments over time.

Can RFM work without monetary data?

Yes. Recency and frequency alone often capture most of the behaviour, and many subscription or engagement businesses use them without spend.

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

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.

Explore course