Müşteri Kaybı Tahmini: Modelden Arama ListesineCustomer Churn Prediction: From Model to Call List
7.043 telekom müşterisinin verisiyle bir kayıp modeli kurdum. Doğruluk oranı bu veride neredeyse hiçbir şey anlatmıyor; en riskli %10'luk dilim ise kaybedilen gelirin dörtte üçünü taşıyor.I built a churn model on 7,043 telecom customers. Accuracy says almost nothing on this data, while the riskiest 10% carries three quarters of the revenue being lost.
- Python
- scikit-learn
- Sınıflandırma
- Churn
- Lift analizi
Abonelik iş modellerinde asıl sorun müşterinin ayrılması değil, ayrıldığını ancak ayrıldıktan sonra öğrenmek. Bu çalışmada 7.043 telekom müşterisinin verisiyle uçtan uca bir kayıp (churn) tahmini kurdum: kimin ayrılma riski taşıdığını, riski hangi davranışların açıkladığını ve sınırlı bir elde tutma kapasitesinin nereye yönlendirilmesi gerektiğini ölçtüm.
Projenin çıktısı bir olasılık listesi değil, öncelik sırasına dizilmiş bir arama listesi. Bunun neden farklı bir şey olduğunu da raporun ortasında somut sayılarla gösteriyorum: bu veride doğruluk oranı neredeyse hiçbir şey anlatmıyor.
Veri ve temizlik
Veri, IBM'in açık Telco Customer Churn seti: kurgusal bir telekom şirketinin müşteri kayıtları, churn literatüründe karşılaştırma amacıyla standart hâle gelmiş bir veri. Müşteri başına tek satır, 21 sütun; hedef değişken müşterinin aboneliğini sonlandırıp sonlandırmadığı. Raporda yer alan bütün sayılar bu dosyadan hesaplandı — sentetik veri üretilmedi, hiçbir metrik temsilî değil.
| Bulgu | Karar | Gerekçe |
|---|---|---|
TotalCharges metin okunuyor; 11 hücre boşluk | Sayısala çevrildi | Ham hâlinde sütunun tamamı kategorik sanılıyor |
Eksik 11 kaydın tamamında tenure = 0 | Yapısal eksiklik; medyanla doldurulmadı | Henüz faturalandırılmamış yeni abonelikler — değer eksik değil, henüz yok |
Yinelenen customerID | Kontrol edildi: yok | Aynı müşterinin iki kez sayılması metrikleri bozardı |
customerID tahmin değişkeni değil | Modelden çıkarıldı | Kimlik alanları ezberleme ve sahte performans üretir |
Eksik veriyi doldurmadan önce desenine bakmak gerekiyor. Burada eksiklik tek bir değişkenle tamamen açıklanıyor; medyan yazmak bu on bir müşteriye var olmayan bir geçmiş atfederdi. On bir satır 7.043'ün içinde kaybolur ama aynı desen büyük veride binlerce satır olsaydı karar ciddi biçimde önem kazanırdı.
Kayıp nerede yoğunlaşıyor?
Model kurmadan önce dört kırılım, modelin sonradan bulduğu yapının büyük kısmını zaten gösteriyor.
Aydan aya sözleşmeli müşterilerin kayıp oranı, iki yıllık sözleşmelilerin 15 katı. Tek bir değişkende bu keskinlikte bir ayrım nadirdir.
| Kırılım | Grup | Müşteri | Kayıp oranı |
|---|---|---|---|
| İnternet hizmeti | Fiber optik | 3.096 | %41,9 |
| DSL | 2.421 | %19,0 | |
| Yok | 1.526 | %7,4 | |
| Ödeme yöntemi | Elektronik çek | 2.365 | %45,3 |
| Posta çeki | 1.612 | %19,1 | |
| Banka transferi (otomatik) | 1.544 | %16,7 | |
| Kredi kartı (otomatik) | 1.522 | %15,2 | |
| Teknik destek | Yok | 3.473 | %41,6 |
| Var | 2.044 | %15,2 |
Dört kırılım da aynı profili işaret ediyor: bağlılığı zayıf, aylık ödemeli, ek hizmet ve destek almayan, kıdemi düşük müşteri. Ödeme yönteminin bu kadar ayırt edici olması dikkat çekici — otomatik ödeme talimatı vermek, ilişkiyi sürdürme niyetinin göstergesi gibi davranıyor.
Yöntem ve veri sızıntısı
Sayısal değişkenler standartlaştırıldı, kategorikler one-hot kodlandı ve üç model aynı veri hattından geçti. Sınıf dengesizliği için üçünde de class_weight="balanced" kullanıldı: model azınlık sınıfını kaçırmayı daha pahalı sayıyor.
onisle = ColumnTransformer([
("num", Pipeline([("i", SimpleImputer(strategy="median")),
("s", StandardScaler())]), sayisal),
("cat", Pipeline([("i", SimpleImputer(strategy="most_frequent")),
("o", OneHotEncoder(handle_unknown="ignore"))]), kategorik),
])
X_tr, X_te, y_tr, y_te = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y)Sızıntının en sinsi biçimi, ölçekleme ortalamasını veya doldurma medyanını tüm veri üzerinden hesaplamaktır; test setinin bilgisi böylece modele sızar ve rapor edilen performans gerçekte ulaşılamayacak kadar iyi çıkar. Bütün dönüşümleri Pipeline içine almak bunu yapısal olarak engelliyor: her katlamada parametreler yeniden ve yalnızca eğitim verisinden öğreniliyor.
Üç model, tek test seti
| Model | Doğruluk | Kesinlik | Duyarlılık | F1 | ROC-AUC | PR-AUC | 5 katlı CV |
|---|---|---|---|---|---|---|---|
| Lojistik regresyon | 0,738 | 0,504 | 0,783 | 0,614 | 0,841 | 0,633 | 0,845 ± 0,014 |
| Rastgele orman | 0,759 | 0,534 | 0,743 | 0,621 | 0,837 | 0,641 | 0,841 ± 0,013 |
| Extra Trees | 0,757 | 0,532 | 0,709 | 0,608 | 0,826 | 0,626 | 0,830 ± 0,013 |
| Taban oran | 0,735 | — | 0,000 | — | 0,500 | 0,265 | — |
Üç modelin çapraz doğrulanmış ROC-AUC'leri 0,830 ile 0,845 arasında; aradaki fark standart sapmaların mertebesinde. Model seçimi bu problemin zor kısmı değil. Yorumlanabilir olduğu ve en yüksek duyarlılığı verdiği için lojistik regresyon üretim adayı olarak seçildi.
Doğruluk neden kullanılamaz?
Müşterilerin %73,5'i kalıyor. "Hiç kimse ayrılmaz" diyen, hiçbir şey öğrenmemiş bir model %73,5 doğruluk alır. Lojistik regresyonun %73,8'i bunun yalnızca 0,3 puan üzerinde.
Doğruluğa bakan biri modeli işe yaramaz sanır. Oysa aynı model, ayrılacak müşterilerin %78,3'ünü yakalıyor: 581 müşteriyi işaretliyor, 293'ü gerçekten ayrılıyor, yalnızca 81 kayıp müşteri gözden kaçıyor. Doğruluğun düşük kalması bir kusur değil, bilinçli bir takas — class_weight modeli kaçırmamaya zorluyor, bedeli de yanlış alarm.
| Metrik | Churn'deki rolü |
|---|---|
| Doğruluk | Yanıltıcı. Dengesiz sınıfta taban oranı aşmak kolay; tek başına raporlanmamalı. |
| Duyarlılık (recall) | Birincil. Kaçırılan her müşteri, geri kazanma şansı olmadan giden gelirdir. |
| Kesinlik (precision) | Maliyet tarafı: düşük kesinlik, elde tutma bütçesinin boşa gitmesi demektir. |
| ROC-AUC | Eşikten bağımsız sıralama kalitesi; modelleri kıyaslamak için en uygun tek sayı. |
| PR-AUC | Azınlık sınıfında denge. Taban oran %26,5; PR-AUC 0,633 bunun 2,4 katı. |
| İlk %N yakalama | İş metriği. Ekip kapasitesiyle doğrudan eşleşen tek ölçü. |
Eşik de bir varsayım. 0,5 matematikten değil alışkanlıktan geliyor ve kapasiteye göre değişmeli: 0,3 eşiğinde kayıpların %92,8'i yakalanıyor ama 809 müşteri aranıyor; 0,7 eşiğinde 373 arama ile kayıpların %60,2'sine ulaşılıyor ve her iki aramadan biri isabetli oluyor. Üretimde bu eşik, eğitim verisinden ayrılan bir doğrulama kümesinde seçilmelidir — test setinde değil.
Kayıpla ilişkili etkenler
İki bağımsız yöntem aynı sıralamayı veriyor. Permütasyon öneminde tenure tek başına ROC-AUC'yi 0,152 puan düşürüyor; onu InternetService (0,043), Contract (0,040) ve MonthlyCharges (0,038) izliyor.
| Değişken | Katsayı | Odds oranı | Yorum |
|---|---|---|---|
| Fiber optik internet | +0,705 | 2,02 | Kayıp bahis oranını iki katına çıkarıyor |
| Aydan aya sözleşme | +0,663 | 1,94 | Bağlayıcılığın olmaması riski neredeyse iki katına çıkarıyor |
| Elektronik çek | +0,239 | 1,27 | Otomatik ödemeye kıyasla belirgin biçimde riskli |
| Teknik destek yok | +0,164 | 1,18 | Destek paketi almamak riski artırıyor |
| Kıdem (standartlaştırılmış) | −1,124 | 0,33 | En güçlü koruyucu etki; bahis oranını üçte bire indiriyor |
| 2 yıllık sözleşme | −0,781 | 0,46 | Uzun sözleşme riski yarıdan fazla azaltıyor |
MonthlyCharges katsayısının negatif çıkması (odds oranı 0,52) ilk bakışta çelişki gibi görünüyor; tek başına bakıldığında pahalı paketlerde kayıp daha yüksek. Bu bir hata değil, koşullu etki: model zaten "fiber optik" bilgisine sahip ve pahalı olmanın riskini oradan okuyor. Fiber olduğu bilindikten sonra, yüksek aylık ücret daha kapsamlı ve daha bağlı bir aboneliğe işaret ediyor.
Risk grupları ve aksiyonlar
Model çıktısı olasılık eşiklerine göre üç gruba ayrıldı. Tablodaki kayıp oranları gerçekleşen değerlerdir; test setindeki 1.409 müşterinin gerçek sonuçlarından hesaplandı.
| Grup | Olasılık | Müşteri | Gerçekleşen kayıp | Ort. aylık ücret | Ort. kıdem | Risk altındaki aylık gelir |
|---|---|---|---|---|---|---|
| Yüksek | > 0,60 | 489 | 264 (%54,0) | 77,59 $ | 15 ay | 20.358 $ |
| Orta | 0,30 – 0,60 | 320 | 83 (%25,9) | 61,53 $ | 26 ay | 4.882 $ |
| Düşük | < 0,30 | 600 | 27 (%4,5) | 54,45 $ | 49 ay | 1.975 $ |
Gruplamanın işe yaramasının sebebi şu: yüksek risk grubu müşterilerin yalnızca %35'ini kapsıyor ama kaybedilen aylık gelirin %74,8'ini taşıyor. Üstelik bu grubun ortalama aylık ücreti (77,59 $) düşük risk grubundan (54,45 $) belirgin biçimde yüksek — kaybedilen müşteriler aynı zamanda daha değerli müşteriler.
Kişisel temas
Ortalama 15 aylık kıdem, aydan aya sözleşme, fiber optik, destek paketi yok. Elde tutma ekibince aranma; sözleşme yükseltme teklifi, ücretsiz teknik destek, fatura veya hız şikâyetinin çözülmesi. Ölçüm: kontrol grubuna kıyasla 90 günlük elde tutma farkı.
Otomatik ve düşük maliyetli
Risk yükseliyor ama henüz kritik değil; kıdem ortalama 26 ay. Otomatik ödeme talimatına geçiş teşviki, kullanılmayan özelliklere yönelik kısa rehberler, yenileme öncesi hatırlatma. Ölçüm: otomatik ödemeye geçiş oranı ve risk puanındaki değişim.
Rahat bırak
Ortalama 49 aylık kıdem, gerçekleşen kayıp yalnızca %4,5. Olağan iletişim; aşırı kampanya temasından kaçınılmalı. Bu grup zaten kalıyor ve gereksiz temas ters etki yapabilir. Ölçüm: şikâyet sayısı ve uzun vadeli kayıp oranı.
Puandan arama listesine
Asıl soru şuydu: bu hafta kimi arayacağız? Cevabı doğruluk oranı değil, lift veriyor. Müşteriler risk puanına göre sıralanıp üstten belli bir yüzde alındığında o dilimde gerçekte kaç kayıp olduğuna bakılıyor.
| Aranan dilim | Müşteri | Dilimdeki kayıp oranı | Yakalanan kayıp | Lift |
|---|---|---|---|---|
| İlk %10 | 140 | %75,7 | 106 / 374 (%28,3) | 2,85× |
| İlk %20 | 281 | %65,8 | 185 / 374 (%49,5) | 2,48× |
| İlk %30 | 422 | %57,6 | 243 / 374 (%65,0) | 2,17× |
| İlk %50 | 704 | %46,3 | 326 / 374 (%87,2) | 1,74× |
En riskli %10'u aradığında her dört müşteriden üçü gerçekten ayrılacak olan müşteri. Rastgele arama yapılsaydı bu oran %26,5 olurdu. Müşterilerin yarısını arayacak kapasite varsa kayıpların %87'sine ulaşılıyor.
- Puanla
- Sırala
- Kapasiteyle
Kes - Kontrol Grubuyla
Ölç
Dört adımın üçü teknik, biri değil. Model, ayrılmaya en yakın müşterileri seçiyor; bu müşterilere yapılan müdahalenin işe yaradığını varsaymak churn projelerinin en yaygın hatası. İşaretlenen müşterilerin rastgele seçilmiş bir bölümüne dokunmayıp iki grubu karşılaştırmak, artımlı etkiyi görmenin tek yolu.
Sınırlar
| Sınırlama | Etkisi |
|---|---|
| Veri kesitsel | Her müşteri için tek anlık görüntü var; kullanımdaki düşüş veya artan şikâyet gibi zaman içindeki davranış değişimi modellenemiyor. Gerçek bir sistemde zaman serisi özellikleri performansı belirgin biçimde artırır. |
| Kayıp tanımı verili | Tahmin ufku seçilebilir değil; üretimde ufuk (ör. 30 gün) iş kararına göre belirlenmelidir. |
| Kurgusal şirket verisi | IBM'in örnek veri seti gerçek bir operasyondan gelmiyor; bulgular yöntem gösterimi olarak güçlü, sektörel genelleme olarak sınırlı. |
| Nedensellik yok | Bütün bulgular ilişkisel. "Fiber optiği ucuzlatırsak kayıp azalır" gibi bir çıkarım bu veriyle desteklenemez. |
| Maliyet verisi yok | Temas başına maliyet ve müşteri yaşam boyu değeri bilinmediği için eşik beklenen kâra göre optimize edilemedi; kapasite varsayımıyla ilerlendi. |
| Adalet denetimi yapılmadı | Model çıktılarının demografik segmentler arasında dengeli davranıp davranmadığı ayrıca incelenmelidir. |
Sonuç
Üç model de birbirine yakın çıktı: çapraz doğrulanmış ROC-AUC 0,830 ile 0,845 arasında. Model seçimi bu problemin zor kısmı değildi; zor kısım, çıkan olasılığı doğru soruya bağlamaktı.
Doğruluk oranına bakan biri modeli çöpe atardı — %73,8, hiçbir şey yapmayan modelin 0,3 puan üstünde. Lift tablosuna bakan biri ise şunu görüyor: en riskli %10'luk dilimde kayıp oranı %75,7, rastgele aramanın 2,85 katı isabet; yüksek risk grubu ise kaybedilen aylık gelirin dörtte üçünü taşıyor. Aynı model, aynı sayılar — farklı olan tek şey sorulan soru.
Analizin tamamı Python ve scikit-learn ile yapıldı; bütün betiklerde random_state=42 sabitlendi, aynı veriyle aynı sayılar üretilir. Veri seti: IBM Telco Customer Churn (7.043 müşteri, 21 değişken).
In subscription businesses the real problem is not that customers leave, but that you only find out after they have. In this project I built an end-to-end churn prediction on 7,043 telecom customers: who carries the risk of leaving, which behaviours explain that risk, and where a limited retention capacity should be pointed.
The output is not a list of probabilities but a ranked call list. Why that is a different thing is shown with concrete numbers in the middle of the report: on this data, accuracy says almost nothing.
Data and cleaning
The data is IBM's open Telco Customer Churn set: customer records from a fictional telecom company, a standard benchmark in churn work. One row per customer, 21 columns; the target is whether the customer ended their subscription. Every number in this report was computed from that file — no synthetic data was generated and no metric is representative.
| Finding | Decision | Reasoning |
|---|---|---|
TotalCharges read as text; 11 cells blank | Converted to numeric | Left raw, the whole column is treated as categorical |
All 11 missing records have tenure = 0 | Treated as structural; not median-imputed | These are new subscriptions not yet billed — the value is not missing, it does not exist yet |
Duplicate customerID | Checked: none | Counting a customer twice would corrupt the metrics |
customerID is not a predictor | Dropped from the model | Identifier fields invite memorisation and fake performance |
Look at the pattern before imputing. Here the missingness is fully explained by a single variable; writing a median would attribute a history these eleven customers never had. Eleven rows vanish inside 7,043, but the same pattern across thousands of rows would make this decision matter a great deal.
Where churn concentrates
Before any modelling, four breakdowns already reveal most of the structure the model later finds.
Month-to-month customers churn at 15 times the rate of two-year contracts. A split that sharp in a single variable is rare.
| Breakdown | Group | Customers | Churn rate |
|---|---|---|---|
| Internet service | Fiber optic | 3,096 | 41.9% |
| DSL | 2,421 | 19.0% | |
| None | 1,526 | 7.4% | |
| Payment method | Electronic check | 2,365 | 45.3% |
| Mailed check | 1,612 | 19.1% | |
| Bank transfer (automatic) | 1,544 | 16.7% | |
| Credit card (automatic) | 1,522 | 15.2% | |
| Tech support | No | 3,473 | 41.6% |
| Yes | 2,044 | 15.2% |
All four point to the same profile: a loosely committed, month-to-month customer without add-on services or support and with little tenure. That payment method discriminates this strongly is striking — setting up automatic payment behaves like a signal of intent to stay.
Method and data leakage
Numeric variables were standardised, categoricals one-hot encoded, and three models run through the same pipeline. For the class imbalance all three used class_weight="balanced", which makes missing a churner more expensive.
preprocess = ColumnTransformer([
("num", Pipeline([("i", SimpleImputer(strategy="median")),
("s", StandardScaler())]), numeric),
("cat", Pipeline([("i", SimpleImputer(strategy="most_frequent")),
("o", OneHotEncoder(handle_unknown="ignore"))]), categorical),
])
X_tr, X_te, y_tr, y_te = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y)The sneakiest form of leakage is computing a scaling mean or an imputation median over the whole dataset: the test set's information reaches the model and the reported performance comes out better than anything achievable in practice. Putting every transform inside a Pipeline prevents this structurally — in each fold the parameters are relearned from the training data alone.
Three models, one test set
| Model | Accuracy | Precision | Recall | F1 | ROC-AUC | PR-AUC | 5-fold CV |
|---|---|---|---|---|---|---|---|
| Logistic regression | 0.738 | 0.504 | 0.783 | 0.614 | 0.841 | 0.633 | 0.845 ± 0.014 |
| Random forest | 0.759 | 0.534 | 0.743 | 0.621 | 0.837 | 0.641 | 0.841 ± 0.013 |
| Extra Trees | 0.757 | 0.532 | 0.709 | 0.608 | 0.826 | 0.626 | 0.830 ± 0.013 |
| Base rate | 0.735 | — | 0.000 | — | 0.500 | 0.265 | — |
The three cross-validated ROC-AUCs sit between 0.830 and 0.845 — a gap on the order of the standard deviations. Model selection is not the hard part of this problem. Logistic regression was chosen as the production candidate for being interpretable and giving the highest recall.
Why accuracy cannot be used
73.5% of customers stay. A model that learns nothing and says "nobody leaves" scores 73.5% accuracy. Logistic regression's 73.8% is a mere 0.3 points above that.
Someone reading accuracy would call the model useless. Yet it catches 78.3% of the customers who actually leave: it flags 581 customers, 293 of them really churn, and only 81 churners slip through. The modest accuracy is not a flaw but a deliberate trade — class_weight pushes the model not to miss, and false alarms are the price.
| Metric | Role in churn |
|---|---|
| Accuracy | Misleading. With imbalanced classes the base rate is easy to beat; never report it alone. |
| Recall | Primary. Every missed customer is revenue lost with no chance to win it back. |
| Precision | The cost side: low precision means the retention budget is spent on nothing. |
| ROC-AUC | Threshold-free ranking quality; the best single number for comparing models. |
| PR-AUC | Balance in the minority class. The base rate is 26.5%; PR-AUC of 0.633 is 2.4 times that. |
| Top-N capture | The business metric. The only measure that maps directly onto team capacity. |
The threshold is an assumption too. The 0.5 cut-off comes from habit, not mathematics, and should follow capacity: at 0.3, 92.8% of churn is caught but 809 customers are called; at 0.7, 373 calls reach 60.2% of churners and roughly every second call lands. In production that threshold belongs on a validation split carved out of the training data — not on the test set.
What drives churn
Two independent methods give the same ordering. In permutation importance, tenure alone costs 0.152 of ROC-AUC, followed by InternetService (0.043), Contract (0.040) and MonthlyCharges (0.038).
| Variable | Coefficient | Odds ratio | Reading |
|---|---|---|---|
| Fiber optic internet | +0.705 | 2.02 | Doubles the odds of churning |
| Month-to-month contract | +0.663 | 1.94 | No commitment nearly doubles the risk |
| Electronic check | +0.239 | 1.27 | Clearly riskier than automatic payment |
| No tech support | +0.164 | 1.18 | Going without a support package raises risk |
| Tenure (standardised) | −1.124 | 0.33 | The strongest protective effect; cuts the odds to a third |
| Two-year contract | −0.781 | 0.46 | A long contract more than halves the risk |
The negative coefficient on MonthlyCharges (odds ratio 0.52) looks like a contradiction at first, since churn is higher among expensive plans on their own. It is not an error but a conditional effect: the model already knows about "fiber optic" and reads the risk of being expensive from there. Given fiber, a higher monthly bill points to a broader, more committed subscription.
Risk groups and actions
The model's output was cut into three groups by probability. The churn rates below are realised values, computed from the actual outcomes of the 1,409 test customers.
| Group | Probability | Customers | Realised churn | Avg. monthly charge | Avg. tenure | Monthly revenue at risk |
|---|---|---|---|---|---|---|
| High | > 0.60 | 489 | 264 (54.0%) | $77.59 | 15 months | $20,358 |
| Medium | 0.30 – 0.60 | 320 | 83 (25.9%) | $61.53 | 26 months | $4,882 |
| Low | < 0.30 | 600 | 27 (4.5%) | $54.45 | 49 months | $1,975 |
The grouping works because the high-risk band covers only 35% of customers yet carries 74.8% of the monthly revenue that was lost. Its average monthly charge ($77.59) is also clearly higher than the low-risk group's ($54.45) — the customers being lost are also the more valuable ones.
Personal contact
Average tenure 15 months, month-to-month contract, fiber optic, no support package. A call from the retention team; a contract upgrade offer, free tech support, or resolution of a billing or speed complaint. Measure: 90-day retention difference against a control group.
Automated and low-cost
Risk is rising but not yet critical; average tenure 26 months. Incentives to switch to automatic payment, short guides for unused features, a reminder before renewal. Measure: switch rate to automatic payment and change in risk score.
Leave them alone
Average tenure 49 months, realised churn only 4.5%. Normal communication; avoid heavy campaign contact. This group is already staying and needless contact can backfire. Measure: complaint volume and long-term churn.
From score to call list
The original question was: who do we call this week? Accuracy does not answer it; lift does. Sort customers by risk score, take the top slice, and count how many in it actually churned.
| Slice called | Customers | Churn rate in slice | Churners captured | Lift |
|---|---|---|---|---|
| Top 10% | 140 | 75.7% | 106 / 374 (28.3%) | 2.85× |
| Top 20% | 281 | 65.8% | 185 / 374 (49.5%) | 2.48× |
| Top 30% | 422 | 57.6% | 243 / 374 (65.0%) | 2.17× |
| Top 50% | 704 | 46.3% | 326 / 374 (87.2%) | 1.74× |
Call the riskiest 10% and three out of every four are genuinely about to leave. Calling at random would hit 26.5%. With capacity to call half the base, 87% of the churn is reached.
- Score
- Rank
- Cut by
Capacity - Measure vs
Control
Three of the four steps are technical and one is not. The model picks the customers closest to leaving; assuming that an intervention on them works is the most common mistake in churn projects. Leaving a randomly chosen share of the flagged group untouched and comparing the two is the only way to see the incremental effect.
Limitations
| Limitation | Effect |
|---|---|
| The data is cross-sectional | One snapshot per customer; behavioural change over time — falling usage, rising complaints — cannot be modelled. In a real system, time-series features would lift performance considerably. |
| The churn definition is given | The prediction horizon is not selectable; in production it (e.g. 30 days) should follow the business decision. |
| Fictional company data | IBM's sample set does not come from a real operation; the findings are strong as a demonstration of method, limited as a sector generalisation. |
| No causality | All findings are associational. "Cheaper fiber would reduce churn" cannot be supported by this data. |
| No cost data | Without contact cost and customer lifetime value, the threshold could not be optimised for expected profit; a capacity assumption was used instead. |
| No fairness audit | Whether the model behaves evenly across demographic segments needs separate examination. |
Conclusion
All three models landed close together: cross-validated ROC-AUC between 0.830 and 0.845. Model selection was not the hard part of this problem; attaching the resulting probability to the right question was.
Someone reading accuracy would have thrown the model away — 73.8%, 0.3 points above doing nothing. Someone reading the lift table sees this: in the riskiest 10% the churn rate is 75.7%, 2.85 times better than calling at random, and the high-risk group carries three quarters of the monthly revenue lost. Same model, same numbers — the only difference is the question being asked.
The whole analysis was done in Python with scikit-learn; random_state=42 is fixed in every script, so the same data produces the same numbers. Dataset: IBM Telco Customer Churn (7,043 customers, 21 variables).