Skip to content

About

Segmentation de 5 878 clients d'un e-commerce britannique (RFM + K-Means, Python). Projet personnel sur le jeu public Online Retail II.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

2 Commits

Folders and files

Repository files navigation

🎯 RFM Customer Segmentation — who actually drives the revenue?

Unsupervised segmentation of an e-commerce customer base using the RFM (Recency, Frequency, Monetary) method and K-Means, on the public Online Retail II dataset (~1 million real transactions from a UK online retailer, 2009–2011).

Goal: split 5,878 customers into homogeneous, actionable groups to answer a question every business owner asks without being able to answer it — "who are the 20% of customers driving 80% of my revenue, and do I actually know them?"

The result in one sentence: 20% of customers (the Champions) generate 74% of revenue. At the other end, a third of the base accounts for just 3.6%.


📦 The data

One transaction file, one row per purchased product:

Column Content
Invoice Order number (C prefix = cancellation)
StockCode / Description Product reference and label
Quantity Quantity (negative for returns)
InvoiceDate Order date and time
Price Unit price (in British pounds £, UK retailer)
Customer ID Customer identifier
Country Shipping country

Cleaning is the real first job. Out of 1,067,371 raw rows, 261,822 (≈ 25%) are removed before any analysis:

  • rows with no Customer ID (a purchase can't be tied to a customer);
  • cancellations (Invoice starting with C) and Quantity ≤ 0;
  • Price ≤ 0.

That leaves 805,549 clean rows and 5,878 unique customers over ~2 years. Lesson #1: in real e-commerce, a quarter of the raw data is noise — returns, cancellations, anonymous orders. You analyze what's left.


🔍 Exploratory analysis — the average lies

From the clean transactions, we compute three indicators per customer (reference date = the day after the last sale in the dataset):

  • Recency — days since their last purchase (lower is better);
  • Frequency — number of distinct orders;
  • Monetary — total spend.
Indicator Median Mean Max
Recency (days) 96 201 739
Frequency (orders) 3 6.3 398
Monetary (£) 899 3,019 608,822

On all three variables, the mean is far above the median: a handful of customers pull everything up (one single customer spent £608,822). The 25th percentile of frequency is 1 — meaning a quarter of customers ordered only once. Every distribution has a long right tail: it's this skew that dictates what comes next.

RFM distributions


🤖 The segmentation

Preparing the data (the step that makes 80% of the result)

K-Means works on distances: left unchecked, the £608,822 customer crushes everything and Monetary (in the thousands) dominates Frequency (in the units). Two moves fix this:

  1. log1p on R, F and M to compress the long tail (on a log scale the distributions become almost symmetric);
  2. StandardScaler to put the three axes on the same scale.

Choosing the number of segments

We test k from 2 to 8, crossing two criteria:

Choosing k

  • Elbow method: inertia drops sharply until k=4, then flattens.
  • Silhouette score: local maximum at k=4 (0.365).

We keep k=4: it's the only point where the elbow and the silhouette agree. The silhouette peak at k=2 (0.438) is discarded — mathematically the cleanest split, but it merely cuts "big vs small customers," with no business value.

Naming the clusters

A cluster labeled "3" means nothing to anyone. By reading each group's average profile, we give them a business-owner-friendly name:

Segment Avg. Recency Avg. Frequency Avg. Monetary Reading
Champions 27 d 19.3 £11,014 Recent, very frequent, big baskets
Loyal 28 d 3.0 £865 Come back often, small baskets
Cooling down 228 d 5.1 £2,002 Good customers going quiet
Lost / to reactivate 396 d 1.4 £326 One purchase, gone for ~13 months

📊 Result — who drives the revenue?

For each segment, we compare its share of customers against its share of revenue:

Segment Customers % of customers % of revenue
Champions 1,188 20.2% 73.7%
Cooling down 1,465 24.9% 16.5%
Loyal 1,251 21.3% 6.1%
Lost / to reactivate 1,974 33.6% 3.6%

Share of customers vs share of revenue by segment

The contrast is stark: 1 in 5 customers drives nearly three quarters of revenue, while a third of the base (the Lost) accounts for just 3.6%.


💡 The business takeaway

Segmentation doesn't describe — it tells you what to do. Two opposite levers come straight out of the numbers:

  • Protect the Champions — 20% of customers, 74% of revenue. Losing them doesn't cost 20% of the top line, it costs 74%. That's where the first euro of retention should go.
  • Reactivate the Lost — a third of the base, dormant. They've already bought once: the sleeping potential is huge, and a targeted win-back costs far less than cold acquisition.

Treating every customer the same is watering with a firehose. Segmentation turns an undifferentiated base into four precise marketing actions.


🗂️ Repository structure

.
├── analyse.py          # Cleaning + RFM table + EDA
├── segmentation.py     # log + scaling + choosing k + K-Means + charts
├── rfm_table.csv       # RFM table (generated by analyse.py)
├── eda_rfm.png         # R, F, M distributions
├── choix_k.png         # Elbow + silhouette
├── rfm_segments.png    # % of customers vs % of revenue by segment
├── data/               # online_retail_II.csv (not versioned)
└── README.md

▶️ Running the project

python -m venv .venv
source .venv/bin/activate        # Windows: .venv\Scripts\activate
pip install pandas matplotlib scikit-learn openpyxl

python analyse.py                # → rfm_table.csv + eda_rfm.png
python segmentation.py           # → choix_k.png + rfm_segments.png

Download the dataset from Kaggle — Online Retail II and place it in data/ as online_retail_II.csv.


🚀 Next steps

  • Cross the segmentation with country or seasonality (recency shifts with the period).
  • Add a quantile-based RFM score (1–5 grid) alongside the clustering — more readable for a marketing team.
  • Estimate a customer lifetime value (CLV) per segment to quantify the ROI of a win-back.
  • Track how customers drift from one segment to another over time (transition matrix).

🧰 Stack

Python · pandas · scikit-learn · matplotlib

Built as a learning project: from raw transactional data to four actionable customer segments.

About

Segmentation de 5 878 clients d'un e-commerce britannique (RFM + K-Means, Python). Projet personnel sur le jeu public Online Retail II.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages