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.