Telecom churn prediction

Four classification models compared on 7,043 telecom customers, and a weekly risk-scoring recommendation that came out of the comparison.

Period
April 2026
Tools
Python, scikit-learn, pandas
Data
7,043 customers, 21 columns, public telecom churn dataset

7,043

customers

4

models compared

46

dimensions after one-hot encoding

The question

Which customers are about to leave, and can a model rank them well enough that a retention team can act on the ranking rather than on a hunch.

Accuracy is the wrong measure here. Roughly a quarter of the customers churn, so a model that predicts nobody churns scores about 74% and is useless. The work is reported on ROC AUC and F1 for that reason.

Method

A stratified 80/20 split, then stratified k-fold cross-validation on the training half. All preprocessing was fitted on the training split only, so nothing from the held-out set reaches the model through a scaler or an encoder.

Four models: logistic regression as the baseline, then k-nearest neighbours, a decision tree, and a random forest. Every stochastic component runs with a fixed seed.

Models compared
ModelHow it was read
Logistic regressionThe baseline. AUC 0.835, and the easiest to explain to someone non-technical
K-nearest neighboursCame in below the baseline. The data has 46 dimensions after one-hot encoding, and distance degrades in high dimensions
Decision treeReadable, and weaker alone than the ensemble built from it
Random forestSelected. Contract type and tenure are the dominant drivers

The random forest was selected on the comparison rather than on a single headline number. The notebook does not record a separate AUC figure for it, so none appears here.

What it found

Contract type is the single strongest signal. Month-to-month customers churn at roughly four times the rate of customers on annual plans. Tenure is second, and most churn happens inside the first year.

That combination is actionable in a way a raw probability is not. A customer around the six-month mark still on a monthly plan is a specific person to call, with a specific offer to make.

The recommendation

Run the model weekly, score every active customer, and send the top 20% by risk score to the retention team each Monday.

Limitations

The notebook carries its own limitations table rather than leaving them to a reader. They are reproduced here because a model without its caveats is a model someone will over-trust.

Stated limitations
LimitationWhy it mattersWhat I would do next
Static snapshotCustomer behaviour moves. A model trained on old data degradesRetrain monthly and track AUC over time
No customer service dataCall centre contact is probably a strong churn signal and is not in this datasetAdd support ticket data if it is available
Binary outcome onlyIt says someone might churn, never whenSurvival analysis for time to churn
Default 0.5 thresholdThe cutoff is not tuned to the business cost of missing a churnerTune on the cost of a false negative against a false positive
Limited feature engineeringNo interaction terms were triedExplore combinations such as high charges with no tech support

The reproducibility checklist is in the notebook: a fixed random state on every stochastic component, preprocessing fitted on the training set only, stratified splits and stratified cross-validation throughout, and the data loaded from a pinned source.

The full notebook

Jupyter notebook · 38 KB

Every cell, including the model comparison and the limitations table.

The notebook as a rendered page

HTML · 374 KB

Opens in a browser with no Python installed.