All workData & Analytics · 2025 · Shipped

Customer Churn Analytics

Turning messy retention data into a model, a dashboard, and decisions a team can act on.

PythonSQLPandasscikit-learnPredictive ModelingMatplotlib
Customer Churn Analytics — project visual
01

Overview

An end-to-end analytics project: ingest raw subscription and behavioural data, clean it, find what actually predicts churn, then hand the business a ranked list of at-risk accounts instead of a chart.

The deliverable was deliberately boring in the best way — a scored table, a short set of drivers, and a dashboard the team could open on a Monday.

02

The problem

Retention data was spread across three exports with inconsistent customer identifiers, mixed date formats, and silently duplicated rows.

The team knew churn was rising but had no way to say who was leaving, when the risk appeared, or which signals showed up first.

03

System architecture & technical approach

A SQL layer resolves identities and builds one row per customer-month, so the model sees behaviour over time rather than a single snapshot. Feature engineering happens in Pandas: tenure buckets, usage deltas, support-ticket velocity, payment friction.

Model selection stayed intentionally interpretable — logistic regression as the baseline, gradient boosting for lift — with SHAP-style driver attribution so every score comes with a reason.

  1. 01

    Raw exports (CSV + DB)

  2. 02

    SQL identity resolution

  3. 03

    Customer-month fact table

  4. 04

    Feature engineering (Pandas)

  5. 05

    Model train / validate

  6. 06

    Risk scores + driver attribution

  7. 07

    Dashboard

04

Technical hurdles & breakthroughs

Leakage from post-churn fields

The first model scored suspiciously well because cancellation-reason and final-invoice fields were populated only for churned accounts. Rebuilt the feature set with a strict as-of cutoff per row, which dropped accuracy but made the model real.

Severe class imbalance

Churners were under 8% of rows, so the baseline model learned to predict 'stays' forever. Moved to stratified sampling, class weighting, and precision-at-top-decile as the headline metric instead of accuracy.

Duplicate customers across exports

Fuzzy-matching on email and billing identifiers with a deterministic tiebreak collapsed thousands of phantom accounts that were quietly skewing every cohort chart.

05

Outcomes & key results

0.87

ROC-AUC on held-out data

3.4×

Lift in the top-decile risk bucket

12k+

Rows deduplicated and reconciled

5

Churn drivers isolated and ranked

  • Most of the value came from data reconciliation, not modelling. A clean fact table beat every clever algorithm I tried on the dirty one.
  • Picking the metric that matches the decision — precision at the top decile, because outreach capacity is finite — changed the whole project.