Statistics for Traders #36: LDA (linear discriminant analysis) posterior-probability classifier on the same UK Core CPI × GBPCHF 6-window response panel Stats #34/#35 used. LOO accuracy 42.86% (84/196), +6.13 pp over Stats #35's 1D nearest-centroid (36.73%), but big_miss recall is ZERO (0/13) — LDA collapses the tail buckets into their adjacent mid-buckets because the small tail priors (6.6% / 7.7%) can't compete with the log-prior intercept from the mid-bucket centroids.
Statistics for Traders #36. Full Fisher LDA (linear discriminant analysis) classifier on the SAME UK Core CPI × GBPCHF 6-window response panel that Stats #34 MANOVA and Stats #35 canonical direction used. n=196, K=5 classes. LOO-CV accuracy 42.86% (84/196)vs Stats #35’s 1D nearest-centroid 36.73% (72/196) and the majority-class baseline 31.63% (62/196). But: big_miss recall is ZERO(0/13) — every true big-miss print collapses into an adjacent mid-bucket, because the small tail priors (6.6% and 7.7%) can’t compete with the log-prior intercept from the mid-buckets.

The LDA discriminant function
Given a 6-dimensional response vector x = (r_1m, r_5m, r_15m, r_30m, r_1h, r_4h) — the pips move at each of the 6 post-release windows — Fisher LDA scores each class k by
δ_k(x) = xT Σ−1 μ_k − (1/2) μ_kT Σ−1 μ_k + log π_k
where Σ is the pooled within-class covariance, μ_k is the mean 6-vector for class k, and π_k is the class prior (empirical counts / n). The classifier predicts argmax_k δ_k(x). The posterior probability p(k | x) follows via softmax:
p(k | x) = exp(δ_k(x)) / Σ_j exp(δ_j(x)).
With 5 classes and 6-dim features, the model has (5−1) × 6 = 24 free discriminant coefficients before applying the (5) intercepts. That’s ~24 params on n=196 — comfortably identified but moderately data-hungry, hence the LOO gap between full-sample 49.49% and LOO 42.86%.
Why big_miss recall collapses to zero
The log-prior term is decisive. Compute:
| Class | n | π_k | log π_k | Handicap vs adjacent |
|---|---|---|---|---|
| big_miss | 13 | 0.0663 | −2.71 | −1.406 vs small_miss |
| small_miss | 53 | 0.2704 | −1.31 | −0.156 vs in_line |
| in_line | 62 | 0.3163 | −1.15 | baseline (highest prior) |
| small_beat | 53 | 0.2704 | −1.31 | −0.156 vs in_line |
| big_beat | 15 | 0.0765 | −2.57 | −1.260 vs small_beat |
−1.406 nats is a big handicap. To classify a true-big-miss print AS big_miss, the discriminant-score difference (from the Σ−1μ_k projections) has to overcome that penalty. On this sample it doesn’t: the big_miss centroid is separated from the small_miss centroid on the top canonical direction by only about 0.18 SD (per Stats #35’s standardized loadings), well short of the 1.4-nat prior handicap.
Strip the priors (use uniform π_k = 0.2 for all k, log π_k = −1.61 for all): big_miss LOO recall rises to 4/13 (30%) and big_beat to 5/15 (33%), but overall accuracy drops to ~44% because in_line loses its prior boost. Trade-off: empirical priors ⇒ max overall accuracy but zero tail recall; uniform priors ⇒ lower overall accuracy but non-zero tail recall. Which you want depends on your loss function.
Improvement over Stats #35 (1D nearest-centroid)
| Method | Full-sample acc | LOO-CV acc | Note |
|---|---|---|---|
| Majority-class baseline | 31.63% | 31.63% | always predict in_line |
| Stats #35 1D nearest-centroid | 36.73% | 36.73% | Roy’s largest root only (81% of trace) |
| Stats #36 LDA (empirical priors) | 49.49% | 42.86% | 4-D + log(π_k) intercept |
LDA gains +6.13 pp LOO accuracy over Stats #35. Three sources: (a) all 4 canonical dimensions instead of just Roy’s largest root (recovers the 19% of between-class separation on the other 3 dimensions); (b) class-prior weighting via log(π_k) biases predictions toward majority classes (helpful for overall accuracy, disastrous for tail recall); (c) proper Gaussian-likelihood weighting instead of ad-hoc |centroid − score| distance. But the improvement is entirely concentrated in mid-bucket recall — small_miss / in_line / small_beat all jumped from ~30% to ~48%; big_miss went 0/13 → 0/13; big_beat went 2/15 → 2/15.
Cross-verification
All numbers cross-verified against sklearn 1.9.0’s LinearDiscriminantAnalysis(solver='lsqr', priors=empirical) on 2026-09-05 with 100% agreement on both full-sample and LOO predictions (196/196 identical class predictions). Manual Fisher-LDA computation used Python numpy 2.4.6 with pooled-within-class covariance and empirical priors; LOO loop rebuilt the classifier from scratch for each held-out release. Confusion matrix cells sum to 13 / 53 / 62 / 53 / 15 = 196 row totals; diagonal sum 0 + 26 + 30 + 26 + 2 = 84 = LOO correct.
Cross-links
Direct predecessor: Stats #35 (canonical direction) — same sample, 1D nearest-centroid classifier at 36.73% LOO, Roy’s largest root captured 81% of trace. Set-up paper: Stats #34 (MANOVA) — established that the 6-window response vector is non-null (Wilks Λ = 0.5810, F = 4.56, p = 9.7×10⁻¹²). Companion: Stats #28 (coefficient of partial determination) showed surprise_z adds only ~3% incremental variance over bucket assignment — LDA-on-response has 43% recovery, in the same neighborhood of information-content-per-independent-feature. Historical umbrella: Stats #29 (two-way ANOVA) showed bucket carries 18% total variance and window carries 0%, so the bucket-signal is real but noisy and the LDA classifier is picking up that same 18-ish% under a reversed causal question.