Acquiring a new customer costs 5x to 7x more than retaining an existing one. Customer Churn Prediction is the quintessential classification problem in enterprise data science. In this class, we build an end-to-end churn prediction pipeline using Logistic Regression, Random Forests, and XGBoost.
| Model | Interpretability | Handling Non-Linearity | Feature Scaling Required? |
|---|---|---|---|
| Logistic Regression | High (odds ratios from coefficients). | Poor (requires manual interaction terms). | Yes (mandatory for gradient descent). |
| Random Forest | Medium (feature importance). | High (deep bagged trees). | No (invariant to monotonic scale). |
| XGBoost / LightGBM | High (via SHAP values). | State-of-the-art (gradient boosting). | No (handles missing data natively). |
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report, roc_auc_score
from xgboost import XGBClassifier
# Generate synthetic subscription customer records
np.random.seed(42)
n = 2000
df = pd.DataFrame({
'tenure_months': np.random.randint(1, 60, n),
'monthly_charges': np.random.uniform(20, 120, n),
'support_tickets': np.random.poisson(lam=2, size=n),
'contract_annual': np.random.choice([0, 1], n, p=[0.7, 0.3])
})
# Churn probability increases with high tickets, low tenure, and month-to-month contracts
logits = (df['support_tickets'] * 0.4) - (df['tenure_months'] * 0.05) - (df['contract_annual'] * 1.2)
probs = 1 / (1 + np.exp(-logits))
df['churned'] = (probs > 0.50).astype(int)
X = df.drop(columns=['churned'])
y = df['churned']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, stratify=y, random_state=42)
# Train XGBoost Classifier
xgb_model = XGBClassifier(
n_estimators=150,
max_depth=4,
learning_rate=0.08,
subsample=0.8,
colsample_bytree=0.8,
eval_metric='logloss',
random_state=42
)
xgb_model.fit(X_train, y_train)
# Predict probabilities
y_prob = xgb_model.predict_proba(X_test)[:, 1]
y_pred = (y_prob >= 0.35).astype(int) # Business-optimized threshold
print(f"ROC-AUC Score: {roc_auc_score(y_test, y_prob):.4f}")
print("\n--- Classification Report (Threshold = 0.35) ---\n")
print(classification_report(y_test, y_pred, target_names=['Retained', 'Churned']))
In XGBoost, set parameter scale_pos_weight = (total_negatives / total_positives) to automatically scale gradient updates for the minority class without needing external SMOTE resamplers.
Broaden your statistical analysis, Python data wrangling, and production engineering expertise:
Handle class imbalance using SMOTE and stratified cross-validation.
Select optimal classification thresholds to maximize business ROI.
Segment customers before predicting their probability of attrition.
Deploy your churn model to a live REST endpoint for instant CRM scoring.