Author: Patrick Maina
A production ML system that predicts customer churn for a Telecommunication company. The project includes a trained XGBoost model, a REST API backend deployed on Railway, and an interactive Streamlit dashboard deployed on Streamlit Community Cloud.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β GitHub β
β Push to main β CI/CD (GitHub Actions) β
β βββ Run tests β
β βββ Report status to Railway β
ββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββ
β Railway β
β FastAPI API β βββ Streamlit Community Cloud
β /predict /predict/batchβ (streamlit/app.py)
β /health β
ββββββββββββββββββββββββββββ
- Backend: FastAPI on Railway β handles all predictions, preprocessing, and SHAP explanations (Explainable AI)
- Frontend: Streamlit on Streamlit Community Cloud β pure HTTP client, calls the backend API
- Registry: Railway builds and deploys from this repository's Dockerfile
- CI/CD: GitHub Actions runs tests, and Railway deploys after checks pass
- Single Prediction β Enter customer details and get an instant churn prediction with probability score, risk level (low/medium/high), and a SHAP feature contribution chart explaining the top 10 drivers
- Batch Prediction β Upload a CSV of customers, get predictions for all of them, and download the results
- Explainability β SHAP values aggregated back to original feature names, showing which factors increase or decrease churn risk
- REST API β
POST /predictandPOST /predict/batchendpoints for programmatic access
The telecommunications industry has become very competitive over the years, with customer retention emerging as a critical challenge. One of the major issues facing telecom providers is customer churn; a scenario where users discontinue their service, either due to dissatisfaction from the provider, or due to the availability of better alternatives. High churn rates can significantly impact a company's overall revenue and scaling potential.
SyriaTel, a leading telecom provider, is experiencing a significant loss of customers who are choosing to leave its services for competitors. To address this challenge, the company seeks to build a robust predictive model capable of identifying customers who are at risk of churning. By leveraging data-driven insights and predictive modeling, SyriaTel aims to understand the key drivers of customer attrition, determine methods of improving long-term retention, and enhance long-term customer loyalty and profitability.
- Determine the key characteristics and behavior patterns that likely contribute to customer churn
- Build a robust predictive model that identifies customers with a high likelihood of discontinuing their service
- Provide data-driven insights and recommendations that will proactively engage and retain high-risk customers
This project uses the Telecom Churn Dataset from Kaggle (3,333 customers). Key attributes include:
- State and Area Code β geographic identifiers
- International and Voice Mail Plans β subscription plan flags
- Call rates β day, night, evening, and international charge rates
- Customer Service Calls β number of support interactions
Loading, inspecting for missing values/duplicates, and computing descriptive statistics.
Standardizing column names, converting Area_Code to object type, dropping Phone_Number, and removing highly correlated features (threshold: 0.9).
Univariate and bivariate analysis using distribution plots, correlation heatmaps, box plots, and bar charts.
One-hot encoding for categorical features, MinMaxScaler for numeric features, and SMOTENC for class imbalance.
Trained six models (Logistic Regression as baseline, Decision Tree, Random Forest, Gradient Boosting, XGBoost, and others) evaluated on recall and AUC-ROC.
ROC curves, AUC scores, confusion matrices, and RandomizedSearchCV for the top two models.
Analyzing Customer Service Calls by Rate of Churn
Distribution of Numerical Features
Feature Correlation Heatmap
The XGBoost Classifier achieved a recall score of 0.82 and AUC of 0.911. The Gradient Boosting model achieved a slightly higher AUC of 0.921 but lower recall of 0.81. Given the nature of churn prediction where missing a churner is more costly than a false alarm, the XGBoost model is recommended. Key churn drivers identified: Customer_Service_Calls, Total_Day_Charge, and International_Plan.
-
Targeted Incentives for High-Churn Area Codes β Customers in area codes
415and510exhibit higher churn tendencies. Offering specialized discounts, loyalty rewards, or exclusive promotions in these regions can serve as an effective retention incentive. -
Enhance Customer Service Efficiency β A high number of customer service interactions is correlated with increased churn. Investing in staff training and better conflict resolution frameworks can significantly boost customer satisfaction.
-
State-Specific Retention Strategies β States such as Texas, New Jersey, Maryland, Miami, and New York report above-average churn. Developing localized marketing and enhanced customer support in these regions would strengthen retention.
-
Review and Optimize Call Rate Plans β Customers who churn often experience high day, evening, night, and international call rates. Introducing more competitive or bundled plans could make services more attractive.
git clone https://github.com/Patricknmaina/customer_churn_prediction.git
cd customer_churn_prediction
uv syncdocker compose upThis starts both services:
- FastAPI backend at
http://localhost:8000 - Streamlit dashboard at
http://localhost:8501
uv run pytest tests/ -v --tb=shortuv run trainThis runs the full training pipeline and saves updated artifacts to artifacts/.
The backend is deployed as a Docker container via DigitalOcean App Platform. The CI/CD pipeline handles all deployments automatically on push to main.
1. Authenticate with DigitalOcean:
doctl auth init2. Create the container registry:
doctl registry create customer-churn-registry --subscription-tier basic3. Build and push the image manually:
doctl registry login --expiry-seconds 1200
docker build --target api -t registry.digitalocean.com/customer-churn-registry/churn-api:latest .
docker push registry.digitalocean.com/customer-churn-registry/churn-api:latest4. Create the App Platform app:
doctl apps create --spec .do/app.yaml5. Get the App ID and live URL:
doctl apps list
doctl apps get <APP_ID> --format DefaultIngressEvery push to main automatically:
- Runs tests (
uv run pytest) - Builds a new Docker image tagged with the commit SHA and
latest - Pushes the image to DOCR
- Triggers a new App Platform deployment
Required GitHub repository secrets:
| Secret | Value |
|---|---|
DIGITALOCEAN_ACCESS_TOKEN |
Your DigitalOcean API token |
DOCR_REGISTRY |
customer-churn-registry |
DIGITALOCEAN_APP_ID |
App ID from doctl apps list |
Add these at: GitHub repo β Settings β Secrets and variables β Actions
This repo now includes railway.toml for Railway config-as-code.
Current Railway configuration:
- Builder:
DOCKERFILE - Dockerfile path:
Dockerfile.api - Healthcheck path:
/health - Healthcheck timeout:
300seconds - Restart policy:
ON_FAILURE(max retries:10) - Replicas:
1
- Create a new Railway project and service from this GitHub repository.
- Confirm the service is using the repo
Dockerfile(or leave default detection). - In service variables, set:
PYTHONUNBUFFERED=1
- Deploy once and verify
GET /healthreturns:status: "healthy"model_loaded: true
- Copy the public Railway backend URL for frontend configuration.
- The API container now binds to Railway's dynamic port using
${PORT:-8000}. - Model artifacts are baked into the image (
artifacts/), so inference works on Railway without external storage. - If you retrain locally, commit updated
artifacts/and redeploy.
GitHub Actions now runs tests only. Deployment is handled by Railway GitHub Autodeploy.
- Open your Railway service.
- Enable GitHub Autodeploy for
main. - Enable
Wait for CIin Railway deployment settings. - Select this workflow as the required check:
CI β Backend Tests.
With this setup:
- A push to
maintriggers GitHub tests. - Railway deploys only after CI succeeds.
- Failed CI blocks deployment.
1. Go to share.streamlit.io and sign in with GitHub
2. Click Create app β Deploy a public app from GitHub
3. Fill in:
- Repository:
Patricknmaina/customer_churn_prediction - Branch:
main - Main file path:
streamlit/app.py
4. Click Advanced settings and add:
API_URL = https://<your-railway-backend>.up.railway.app
5. Click Deploy!
Community Cloud reads streamlit/requirements.txt, installs the four frontend dependencies, and serves the app at https://<your-app-name>.streamlit.app.
When new data is available or the model needs updating:
# 1. Retrain locally
uv run train
# 2. Commit the updated artifacts
git add artifacts/
git commit -m "retrain model - <reason>"
git pushGitHub CI validates the push and Railway deploys the updated image after checks pass.
| Category | Tools |
|---|---|
| ML | XGBoost 3.0, scikit-learn 1.6, SHAP 0.42+, imbalanced-learn 0.13 |
| API | FastAPI 0.115+, Uvicorn 0.32+, Pydantic 2.10+ |
| Frontend | Streamlit 1.40+, Plotly 6.1, pandas 2.2, requests |
| Packaging | uv, joblib |
| Containerization | Docker (multi-stage build), Docker Compose |
| CI/CD | GitHub Actions |
| Hosting | Railway (backend), Streamlit Community Cloud (frontend) |
| Registry | Railway-managed deployment pipeline |
| Testing | pytest 8+, pytest-cov, httpx |
customer_churn_prediction/
βββ api/ # FastAPI backend
β βββ main.py # App entrypoint, endpoints (/health, /predict, /predict/batch)
β βββ schemas.py # Pydantic request/response models
βββ streamlit/ # Streamlit dashboard
β βββ app.py # Interactive UI (Home, Single Prediction, Batch Prediction tabs)
β βββ requirements.txt # Frontend-only dependencies for Streamlit Community Cloud
βββ scripts/ # ML pipeline
β βββ config.py # Central constants (paths, features, thresholds, model params)
β βββ data_prep/ # Cleaning and preprocessing
β βββ eda/ # EDA visualization utilities
β βββ modeling/ # Training, evaluation, hyperparameter tuning
β βββ serving/ # ChurnPredictor inference engine (predict.py)
βββ tests/ # Full test suite mirroring scripts/ structure
βββ artifacts/ # Serialized model artifacts (committed for CI/CD builds)
β βββ model.joblib
β βββ scaler.joblib
β βββ encoder.joblib
β βββ label_encoder.joblib
β βββ feature_names.json
β βββ dropped_features.json
βββ .do/
β βββ app.yaml # DigitalOcean App Platform deployment spec
βββ .github/workflows/
β βββ deploy-api.yml # CI pipeline (backend tests)
βββ Dockerfile # Multi-stage build (api target, streamlit target)
βββ docker-compose.yml # Local development (both services)
βββ pyproject.toml # Project metadata and dependencies
βββ data/
βββ churn.csv # Raw dataset (Kaggle Telecom Churn)
MIT License - see LICENSE file for details


