End-to-end customer churn prediction pipeline with XGBoost (0.868 accuracy, 0.855 ROC-AUC), FastAPI REST API, Docker deployment, batch inference, and model drift monitoring.
- Project Overview
- Architecture
- Model Performance
- Quick Start
- Data Setup
- API Usage
- Docker Deployment
- Model Monitoring
- Testing
- Tech Stack
- Key Insights from EDA
- Model Training Details
End-to-end ML pipeline for predicting customer churn in banking, covering data preprocessing, feature engineering, model benchmarking, REST API deployment, Dockerised inference, and data drift monitoring.
| What | Detail |
|---|---|
| Dataset | Bank Customer Churn — 10,000 customers |
| Models | Logistic Regression · Random Forest · XGBoost |
| Serving | FastAPI REST API (single + batch endpoints) |
| Deployment | Docker / Docker Compose |
| Monitoring | Custom drift detection + prediction logging |
Customer_Churn_Prediction/
├── .github/
│ └── workflows/
│ └── tests.yml # CI — runs pytest on every push / PR
├── data/
│ ├── raw/ # Raw Kaggle CSV (Churn_Modelling.csv)
│ ├── processed/ # Train/test splits (git-ignored)
│ ├── sample/
│ │ └── churn_sample_100rows.csv # Synthetic 100-row sample
│ └── download_data.py # Automated Kaggle download utility
├── notebooks/
│ └── 01_eda.ipynb # Exploratory Data Analysis
├── src/
│ ├── data_preprocessing.py # Cleaning · feature engineering · scaling
│ ├── train_model.py # LR · RF · XGBoost training + evaluation
│ └── model_monitoring.py # Drift detection + prediction logging
├── api/
│ └── main.py # FastAPI application (single + batch predict)
├── models/ # Serialised models + evaluation artefacts
│ ├── logistic_regression.joblib
│ ├── random_forest.joblib
│ ├── xgboost.joblib
│ ├── preprocessor.joblib
│ ├── model_comparison.csv
│ ├── roc_curves.png
│ ├── confusion_matrices.png
│ ├── feature_importance.png
│ └── monitoring/ # Prediction logs (git-ignored)
├── tests/
│ ├── test_api.py # FastAPI endpoint tests
│ └── test_preprocessing.py # Preprocessing unit tests
├── demo_predict.py # Live API demo script
├── requirements.txt
├── Dockerfile
└── docker-compose.yml
data/raw/Churn_Modelling.csv
│
▼ src/data_preprocessing.py
Clean → Feature Engineering → Encode → Scale
│
├─► data/processed/ (X_train, X_test, y_train, y_test)
└─► models/preprocessor.joblib
data/processed/ ─► src/train_model.py
│
├─► LogisticRegression ─► models/logistic_regression.joblib
├─► RandomForestClassifier ► models/random_forest.joblib
└─► XGBClassifier ─► models/xgboost.joblib
│
models/model_comparison.csv
models/roc_curves.png
models/feature_importance.png
POST /predict ──► preprocess_input()
│
▼ models/preprocessor.joblib
Feature Engineering → Encode → Scale
│
▼ models/{model}.joblib
predict_proba()
│
▼
{ churn_prediction, churn_probability,
model_used, confidence, timestamp }
Every prediction ─► src/model_monitoring.py
│
┌────────┴────────┐
▼ ▼
models/monitoring/ Drift Detection
predictions_log.jsonl (vs training dist.)
metrics_log.jsonl
Trained on 8,000 customers · evaluated on 2,000 held-out customers ·
random_state=42
| Model | Accuracy | Precision | Recall | F1 Score | ROC-AUC |
|---|---|---|---|---|---|
| Logistic Regression | 0.849 | 0.764 | 0.374 | 0.502 | 0.832 |
| Random Forest | 0.861 | 0.806 | 0.419 | 0.550 | 0.858 |
| XGBoost | 0.868 | 0.786 | 0.479 | 0.595 | 0.855 |
Best ROC-AUC: Random Forest (0.858) — preferred for ranking tasks
Best Accuracy: XGBoost (0.868) — preferred for threshold-based decisions
Full metrics saved to models/model_comparison.csv.
- Python 3.11+
- Docker (optional, for containerised deployment)
git clone https://github.com/satyamshivam13/Customer_Churn_Prediction.git
cd Customer_Churn_Prediction
python -m venv venv
# Windows:
venv\Scripts\activate
# Linux / Mac:
source venv/bin/activate
pip install -r requirements.txtSee Data Setup below.
python src/data_preprocessing.pyOutputs:
data/processed/X_train.csv,X_test.csv,y_train.csv,y_test.csvmodels/preprocessor.joblib
python src/train_model.pyOutputs: serialised models, ROC curves, confusion matrices, feature importance plots, model_comparison.csv.
uvicorn api.main:app --reload --host 0.0.0.0 --port 8000- Swagger UI: http://localhost:8000/docs
- Health check: http://localhost:8000/health
python demo_predict.pyThe full 10,000-row dataset (Churn_Modelling.csv) is included in data/raw/ for reproducibility.
# Install Kaggle API client
pip install kaggle
# Configure credentials once:
# 1. Visit https://www.kaggle.com/settings/account → API → Create New API Token
# 2. Save kaggle.json to ~/.kaggle/kaggle.json
# 3. Linux/Mac: chmod 600 ~/.kaggle/kaggle.json
python data/download_data.pypython data/download_data.py --manualFollow the printed instructions.
A 100-row synthetic dataset with the same schema is available for pipeline testing without requiring a Kaggle account:
# Run preprocessing on the sample dataset
python - <<'EOF'
from src.data_preprocessing import ChurnDataPreprocessor
p = ChurnDataPreprocessor()
X_train, X_test, y_train, y_test = p.preprocess_pipeline(
"data/sample/churn_sample_100rows.csv"
)
EOFThe sample file data/sample/churn_sample_100rows.csv contains:
- 100 synthetic rows (no real customer data)
- Same 14-column schema as the Kaggle dataset
- ~33% churn rate (inflated for test coverage of both classes)
curl -X POST "http://localhost:8000/predict?model_name=xgboost" \
-H "Content-Type: application/json" \
-d '{
"CreditScore": 650,
"Geography": "France",
"Gender": "Female",
"Age": 42,
"Tenure": 5,
"Balance": 100000.0,
"NumOfProducts": 2,
"HasCrCard": 1,
"IsActiveMember": 1,
"EstimatedSalary": 50000.0
}'Response:
{
"churn_prediction": "Yes",
"churn_probability": 0.7234,
"model_used": "xgboost",
"confidence": "High",
"timestamp": "2026-01-28T10:30:00.123456"
}Available model names: logistic_regression, random_forest, xgboost (default).
curl -X POST "http://localhost:8000/predict/batch?model_name=xgboost" \
-H "Content-Type: application/json" \
-d '[
{
"CreditScore": 750, "Geography": "France", "Gender": "Male",
"Age": 35, "Tenure": 8, "Balance": 0.0, "NumOfProducts": 1,
"HasCrCard": 1, "IsActiveMember": 1, "EstimatedSalary": 80000.0
},
{
"CreditScore": 400, "Geography": "Germany", "Gender": "Female",
"Age": 58, "Tenure": 2, "Balance": 145000.0, "NumOfProducts": 3,
"HasCrCard": 0, "IsActiveMember": 0, "EstimatedSalary": 45000.0
}
]'Response:
{
"total_customers": 2,
"successful_predictions": 2,
"results": [
{ "customer_index": 0, "success": true, "churn_prediction": "No", "churn_probability": 0.08 },
{ "customer_index": 1, "success": true, "churn_prediction": "Yes", "churn_probability": 0.89 }
]
}import requests
response = requests.post(
"http://localhost:8000/predict",
params={"model_name": "xgboost"},
json={
"CreditScore": 650, "Geography": "France", "Gender": "Female",
"Age": 42, "Tenure": 5, "Balance": 100000.0, "NumOfProducts": 2,
"HasCrCard": 1, "IsActiveMember": 1, "EstimatedSalary": 50000.0,
},
)
print(response.json())docker build -t churn-prediction-api .
docker run -p 8000:8000 -v $(pwd)/models:/app/models churn-prediction-apidocker-compose up -d # start
docker-compose logs -f # stream logs
docker-compose down # stopThe Compose file mounts ./models and ./data as volumes, so trained models are available without rebuilding the image.
src/model_monitoring.py provides:
| Feature | Detail |
|---|---|
| Prediction logging | Every inference written to models/monitoring/predictions_log.jsonl |
| Data drift detection | Mean-shift comparison against training distribution |
| Performance tracking | Log accuracy / precision / recall / F1 / ROC-AUC over time |
| Health checks | Automated model-file and activity checks |
| Reporting | On-demand monitoring report |
python src/model_monitoring.pyfrom src.model_monitoring import ModelMonitor
monitor = ModelMonitor()
# Log a prediction
monitor.log_prediction(
customer_data=data_dict,
prediction="Yes",
probability=0.75,
model_name="xgboost",
)
# Detect data drift
drift = monitor.detect_data_drift(new_data_df)
# Generate report
print(monitor.generate_monitoring_report())pytest tests/ -v| Test file | Coverage |
|---|---|
tests/test_preprocessing.py |
Initialisation · cleaning · feature engineering |
tests/test_api.py |
Root · health · models · predict endpoints |
CI runs pytest automatically on every push and pull request via GitHub Actions.
| Layer | Tools |
|---|---|
| Language | Python 3.11 |
| ML | scikit-learn · XGBoost |
| Data | pandas · numpy |
| Visualisation | matplotlib · seaborn · plotly |
| API | FastAPI · Uvicorn · Pydantic |
| Monitoring | Custom (JSONL logs + drift detection) |
| Testing | pytest · httpx |
| Deployment | Docker · Docker Compose |
| CI/CD | GitHub Actions |
| Development | Jupyter · VS Code |
- Class imbalance — 20.4% churn rate (2,037 / 10,000 customers)
- Age — strong positive correlation (0.29); older customers churn more
- Geography — Germany has the highest churn rate of the three countries
- Active membership — inactive members churn significantly more (−0.16 correlation)
- Product count — customers with 3–4 products have 83–100% churn rate
- Balance — slight positive correlation (0.12)
- Gender — female customers show higher churn tendency
- Tenure — relatively stable across all tenure groups (0–10 years)
| Feature | Description |
|---|---|
TenureGroup |
Bucketed tenure: 0–3 / 3–6 / 6–9 / 9+ years |
BalanceToSalaryRatio |
Balance / (EstimatedSalary + 1) |
AgeGroup |
Young / Middle / Senior / Elderly |
HighProductRisk |
Flag: NumOfProducts >= 3 |
EngagementScore |
Composite of active membership, credit card, products |
Logistic Regression — max_iter=1000, solver lbfgs
Random Forest — n_estimators=100, max_depth=10, min_samples_split=20
XGBoost — n_estimators=100, max_depth=6, learning_rate=0.1, subsample=0.8, colsample_bytree=0.8
| Issue | Fix |
|---|---|
| Models not loading in API | Run python src/train_model.py first |
| Dataset not found | Run python data/download_data.py or place Churn_Modelling.csv in data/raw/ |
| Import errors | Activate the virtual environment; run pip install -r requirements.txt |
| Docker container fails | Ensure models/ contains trained .joblib files |
MIT — see LICENSE.
Satyam Shivam — Data Science & MLOps Portfolio
GitHub: satyamshivam13
- SMOTE for class imbalance
- Hyperparameter tuning (Optuna / GridSearchCV)
- Precision-Recall curves
- MLflow model versioning & experiment tracking
- API authentication
- Frontend dashboard (Streamlit / Gradio)
- A/B testing framework
- Real-time predictions with Kafka
Built with Python, FastAPI, and Docker.