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.
| Model | How it was read |
|---|---|
| Logistic regression | The baseline. AUC 0.835, and the easiest to explain to someone non-technical |
| K-nearest neighbours | Came in below the baseline. The data has 46 dimensions after one-hot encoding, and distance degrades in high dimensions |
| Decision tree | Readable, and weaker alone than the ensemble built from it |
| Random forest | Selected. 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.
| Limitation | Why it matters | What I would do next |
|---|---|---|
| Static snapshot | Customer behaviour moves. A model trained on old data degrades | Retrain monthly and track AUC over time |
| No customer service data | Call centre contact is probably a strong churn signal and is not in this dataset | Add support ticket data if it is available |
| Binary outcome only | It says someone might churn, never when | Survival analysis for time to churn |
| Default 0.5 threshold | The cutoff is not tuned to the business cost of missing a churner | Tune on the cost of a false negative against a false positive |
| Limited feature engineering | No interaction terms were tried | Explore 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.
Jupyter notebook · 38 KB
Every cell, including the model comparison and the limitations table.