Methodology

How we compute probability and uplift.

Every recommendation surfaced in the demo and in production is a calibrated probability multiplied by an expected value. This page documents how those numbers are produced, what we assume, and how we know the models are actually working — written so a Halfords commercial lead and a Halfords data scientist can both read it.

Step 1

Score

Per-customer, per-action probability with a calibrated classifier.
Step 2

Uplift

Incremental effect of contacting vs. not contacting, per action.
Step 3

Rank

Expected value = uplift × margin × eligibility. Highest wins.
01 · Framing

From ‘who might buy’ to ‘what should we do next’.

A propensity score alone answers “how likely is this customer to take action A?”. That is not the same as “will A happen because we contacted them?”. Next best action requires the second question, otherwise budget is spent on sure things and lost causes instead of persuadables.

For each candidate action a (MOT reminder, Motoring Club upgrade, Bike Care booking, EV charger quote, …) and each customer i, we estimate two quantities:

p_i,a = P(convert | customer = i, treatment = a)
τ_i,a = P(convert | i, treated with a) − P(convert | i, not treated)

p is the calibrated probability shown in the UI. τ is the causal uplift used for ranking. They agree only when the base rate is near zero; otherwise they diverge, which is why we always model both.

02 · Data

Feature families and the Halfords signal we lean on.

Models are trained on a customer-level table joined from Motoring Club membership, transaction history, Autocentre service records, MOT dates (DVSA-derived where consented), online sessions, and fitting-bay bookings. Feature engineering falls into six families:

  • Recency / frequency / monetary — visits, spend, time since last service, basket composition.
  • Vehicle context — vehicle age, months to next MOT, fuel type, historical fail codes, aftermarket parts fitted.
  • Cycling context — bike ownership, e-bike flag, months since last Bike Care visit, seasonality.
  • Membership — Motoring Club tier, tenure, benefit utilisation rate, renewal window.
  • Engagement — email open/click decay, app opens, store vs. online mix.
  • Exogenous — local weather, fuel price index, school-holiday calendar, store catchment demographics.

Features are computed as of a fixed reference date so no post-treatment information leaks into training. Categorical values use target encoding with out-of-fold smoothing; numerics are winsorised at the 1st/99th percentile before tree models see them.

03 · Probability

Model families and calibration.

The propensity head p_i,a is a gradient-boosted decision tree (LightGBM, occasionally XGBoost) trained with log-loss. GBDTs win on tabular retail data with mixed types, missingness, and non-linear interactions. Deep tabular models (TabNet, FT-Transformer) are benchmarked but only shipped when they beat GBDT by ≥2% calibrated log-loss on a holdout, which is rare.

Raw GBDT scores are not probabilities. We calibrate with isotonic regression on a held-out fold, then verify with a reliability diagram and the Expected Calibration Error:

ECE = Σ_b (|B_b| / N) · | acc(B_b) − conf(B_b) |

We ship at ECE ≤ 0.03 across deciles. Anything above that and marketing spend allocation becomes systematically biased — usually over-contacting the top decile.

04 · Uplift

Estimating the causal lift, not the correlation.

Uplift τ_i,a is the average treatment effect conditional on covariates. We use two families depending on data availability:

  • Meta-learners on RCT data — where we have a clean holdout (e.g. Motoring Club renewal campaign), we fit T-learner and X-learner variants with GBDT base models. X-learner dominates when treatment is rare.
  • Causal forests on observational data — for always-on channels (app push, in-store attach) we use a doubly- robust causal forest with propensity-of-treatment as a nuisance model. Assumes overlap and unconfoundedness given the feature set.

Formally, for treatment T ∈ {0,1} and outcome Y:

τ(x) = E[ Y(1) − Y(0) | X = x ]
τ̂_X(x) = g(x) · μ̂_0(x, D_1) + (1 − g(x)) · μ̂_1(x, D_0)

Ranking uses τ̂, not . This is what stops the model recommending an MOT reminder to someone who has already booked online — high propensity, zero uplift.

05 · Ranking

From probabilities to a single recommended action.

For each customer we compute expected value per action and rank:

EV_i,a = τ̂_i,a · margin_a · eligibility_i,a − cost_a
NBA_i = argmax_a EV_i,a   subject to fatigue, suppression, and capacity constraints

Eligibility encodes hard business rules (consent, stock at the local Autocentre, MOT window). Fatigue caps how often a customer can be contacted per channel per fortnight. Capacity constraints solve as a bipartite assignment when a channel is oversubscribed — e.g. Saturday fitting-bay slots — using a greedy top-k with fairness reshuffling.

06 · Evaluation

Metrics we report before anything goes live.

Probability quality

Log-loss & Brier

Proper scoring rules. Both must beat the base-rate baseline out-of-time.
Calibration

ECE ≤ 0.03

Reliability diagram inspected by decile; isotonic re-fit if drift > 0.05.
Ranking

AUC-ROC & PR-AUC

PR-AUC leads for rare actions (e.g. EV charger install) where positives are < 2%.
Business

Lift @ decile

Top-decile conversion vs. random. Reported at 5, 10, 20% audience cuts.
Uplift

Qini & AUUC

Uplift curves and the Qini coefficient. Random policy = 0, perfect = 1.
Causal

Holdout revenue delta

A permanent 5–10% control cell measures £ / customer / period vs. treated.

Models graduate from lab to production only when they beat the incumbent on all four of: calibrated log-loss, Qini, top-decile lift, and holdout revenue delta — measured on an out-of-time window, not a random split.

07 · Assumptions

What has to be true for the numbers to mean anything.

  • Overlap. Every customer has non-zero probability of receiving each action. Violated if a channel is only ever used for one segment; we detect via propensity histograms and trim.
  • Unconfoundedness (observational only). Treatment assignment is independent of the outcome given the features. We stress-test with sensitivity analysis (Rosenbaum bounds) and prefer RCT holdouts wherever the commercial cost allows.
  • SUTVA. One customer’s treatment doesn’t affect another’s outcome. Broken by household-level effects (two cars, one email); we cluster households and treat at household level.
  • Stationarity within horizon. The joint distribution of features and outcomes is stable over the scoring horizon. Enforced by monthly retraining and PSI monitoring on the top 30 features.
  • Label fidelity. Conversions are attributed within a defined window (e.g. 14 days for MOT booking, 30 days for Club upgrade). Attribution rules are frozen before training.
  • Ethics & consent. Models never use protected attributes as features. Suppression lists (bereavement, complaint, regulatory) are applied post-ranking and audited quarterly.
08 · Monitoring

What we watch after go-live.

  • Population Stability Index per feature; alert at PSI > 0.2, retrain at PSI > 0.25.
  • Calibration drift weekly on the last 4 weeks of scores vs. realised outcomes.
  • Uplift decay from the permanent holdout; if the Qini coefficient drops > 20% vs. launch, the action is paused and re-estimated.
  • Guardrail metrics — unsubscribe rate, complaint rate, average contacts per customer per week. Any breach reverts to the previous policy automatically.

Want the full technical annex?

We share the extended methodology — hyperparameter search spaces, fairness audits, and MLOps runbook — under NDA with Halfords’ data science and CRM teams.

Request the annex