This was my final project for IBM's Unsupervised Machine Learning course, on the same Telco Customer Churn dataset I used for a churn classifier. The question was different: without using the churn label at all, can we split 7,043 customers into groups that a marketing team would recognise, and does that split say anything about risk?
It does. One segment, which I call the fibre newcomers, is 27% of customers and 65% of the revenue lost to churn.
Feature engineering mattered more than the algorithm
The obvious input is the 18 raw service flags (phone, internet type, each add-on). Run through PCA, they need 10 components to explain 80% of the variance, and K-means on them reaches a silhouette of 0.18 at k = 5: weak, overlapping clusters.
I replaced them with six engineered behavioural features: tenure, contract length in months, monthly charges, the number of protection services, the number of streaming services, and a fibre flag. Three principal components now explain 87% of the variance, and they read naturally as spend and service depth, commitment and fibre versus protection. The silhouette doubles:
| Feature set | Components for 80%+ variance | Silhouette at k = 5 |
|---|---|---|
| 18 raw service flags | 10 | 0.18 |
| 6 engineered features | 3 | 0.37 |
Five algorithms, same k
| Model | Silhouette | Davies–Bouldin | Bootstrap stability (ARI) |
|---|---|---|---|
| K-means, engineered features | 0.37 | 1.06 | 0.99 |
| Hierarchical (Ward) | 0.34 | 1.11 | 0.79 |
| Gaussian mixture | 0.28 | 1.25 | 0.95 |
| DBSCAN (19 clusters) | 0.30 | 1.42 | n/a |
K-means wins on every internal metric and is the most stable: refitting with different random seeds reproduces the same segments (adjusted Rand index 0.99). Stability is the metric I would not skip; a segmentation that changes every time you refit cannot be used to run campaigns.
The five segments
| Segment | Share | Profile | Churn | Share of churned revenue |
|---|---|---|---|---|
| Fibre newcomers | 27% | 17 months' tenure, month-to-month, all on fibre, $85/month | 56% | 65% |
| Budget newcomers | 27% | 12 months, $39/month, a third without internet | 26% | 14% |
| Premium fibre loyalists | 17% | 58 months, annual contracts, $103/month, most add-ons | 19% | 17% |
| Loyal DSL bundlers | 16% | 52 months, the longest contracts, protection bundles | 6% | 3% |
| Phone-only veterans | 14% | 46 months, no internet, $23/month | 1.4% | 0.2% |
Churn ranges from 1.4% to 56% across segments, even though the clustering never saw the churn column. The fibre newcomers are 27% of customers and 35% of revenue, but 65% of the revenue lost to churn. That is where a retention budget goes first, and the profile tells you what to offer: they are on month-to-month contracts, so the obvious lever is a contract incentive.
A negative result worth keeping
I also tried training one churn classifier per segment instead of a single global model. On the same test customers: global model AUC 0.843, one model per segment 0.843, global model plus a segment feature 0.844. Splitting the data five ways costs more in sample size than it gains in specificity. Segments are a communication and targeting tool here, not a modelling shortcut, and it is useful to know that before building five pipelines.
Limits
The data is a point-in-time extract with no customer history. The engineered features embed judgement calls, such as which services count as "protection". DBSCAN's small clusters are real sub-groups but too small to act on.
- Code, notebook and the 10-page report: github.com/engomaressam/customer-segmentation-kmeans
- Kaggle notebook: Telco customer segmentation: K-means vs 4 methods
Omar Essam El Sherbiny. Head of Data at WalaPlus. Data platforms on Google Cloud, data governance, applied ML. More at omaressam.web.app.


Top comments (0)