Quant Memo
Foundational

Training Error vs Generalization Error

The error a model reports on the data it was trained on and the error it will make on new data are two different numbers, and confusing them is the single most common way quant models fail in production.

Prerequisites: Overfitting, Cross-Validation for Time Series

Ask a model how well it performs and it will happily answer with a number computed on the same data it learned from. That number is close to useless for deciding whether to trust the model, because a sufficiently flexible model can drive that number to zero by memorizing the data rather than learning the pattern in it. The number that actually matters — how the model performs on data it has never seen — is a different quantity entirely, and it cannot be read off the training run at all.

The analogy: the practice exam versus the real exam

A student who is handed the exact exam questions a week in advance, together with the answer key, will score 100% by memorizing answers without understanding a single concept. That score tells you nothing about how they will do on a different set of questions covering the same material. The only honest test is one built from questions the student has never seen. A model evaluated on its own training data is that student grading their own take-home exam with the answer key already in hand.

In a backtest, "training error" is how well the strategy would have performed on the exact historical window used to fit its parameters. "Generalization error" is how it performs on new market data going forward. A strategy can look flawless on the first and lose money on the second, and the gap between them is the single most expensive number in quantitative research to get wrong.

The two quantities, named precisely

Let L(y^,y)L(\hat y, y) be a loss function — a number that says how wrong a prediction y^\hat y was compared to the truth yy, where smaller is better. Training error is

R^train=1ni=1nL(f(xi),yi)\hat R_{\text{train}} = \frac{1}{n} \sum_{i=1}^{n} L\big(f(x_i), y_i\big)

In words: run the model ff on each of the nn training examples, measure how wrong it was, and average. It is a single, computable number — literally a report card on data the model already saw.

Generalization error is

R(f)=E(x,y)P[L(f(x),y)]R(f) = \mathbb{E}_{(x,y)\sim P}\big[ L(f(x), y) \big]

In words: the average loss the model would produce if you could feed it every possible future (x,y)(x, y) pair drawn from the true, unknown process PP that generates the data. It is an expectation over a distribution nobody has direct access to — you can never compute it exactly, only estimate it, and the honest way to estimate it is a held-out test set the model never touched during fitting. The gap between the two, R(f)R^trainR(f) - \hat R_{\text{train}}, is called the generalization gap, and it grows with how flexible the model is relative to how much data it was given.

Worked example 1: polynomial regression on ten data points

Ten days of a noisy return series are fit with two models: a straight line (degree 1) and a ninth-degree polynomial that can bend through every point exactly, using all ten as training data and five fresh days as a held-out test.

ModelTraining MSEHeld-out MSEGap
Degree 1 (line)0.04500.04800.0030
Degree 9 (wiggly curve)0.00050.21000.2095

The degree-9 model's training error is ninety times smaller than the line's — it looks like a dramatically better fit. But its held-out error is more than four times worse than the line's. It did not learn the underlying relationship; it threaded a curve through ten specific noisy points, and that curve is wrong everywhere else. The line's training and held-out errors stay close together, which is the signature of a model that generalizes: what it learned on old data still roughly holds on new data.

Worked example 2: classification error counts

A signal classifies each day as "up" or "down." With k=1k=1 nearest-neighbor (the prediction is just whichever training day looked most similar), evaluated on its own 200 training days, it is wrong on 0 of them — 0% training error, because every training point's nearest neighbor is itself. On 100 fresh test days it is wrong on 34 — 34% test error, barely better than a coin flip.

R^train=0200=0%,R^test=34100=34%,gap=34 points\hat R_{\text{train}} = \frac{0}{200} = 0\%, \qquad \hat R_{\text{test}} = \frac{34}{100} = 34\%, \qquad \text{gap} = 34\text{ points}

Switching to k=15k=15 (average over the 15 most similar days, which smooths out one-off coincidences) gives 12 training errors out of 200 (6%) and 15 test errors out of 100 (15%):

R^train=6%,R^test=15%,gap=9 points\hat R_{\text{train}} = 6\%, \qquad \hat R_{\text{test}} = 15\%, \qquad \text{gap} = 9\text{ points}

The k=15k=15 model has a worse training score than k=1k=1 — 6% instead of 0% — but a much better test score and a far smaller gap. Training error alone would have picked the wrong model.

Bias–variance explorer
model complexity →sweet spot
test error 1.54train error 0.92underfitting

Drag the complexity slider in the explorer above. Training error falls monotonically as complexity increases — a more flexible model can always fit the training data better — while test error falls, bottoms out, and then rises again. The point where they start to diverge is where the model has stopped learning signal and started memorizing noise, exactly what happened between the line and the degree-9 curve above.

true population P n training points, sampled once everything outside the dots is what generalization error measures
The dots are the only data the model ever fits on. Training error only ever grades performance on those dots; generalization error grades performance on the whole shaded population, most of which the model never touched.

Training error measures fit to data already seen; generalization error measures performance on data not yet seen. They can move in opposite directions as a model gets more flexible — that divergence, not either number alone, is what tells you whether a model has learned or memorized.

What this means in practice

Every backtest is a training-error number wearing a costume. If parameters were tuned — even lightly, even just picking which lookback window "worked best" — on the same historical window being reported, the reported Sharpe ratio is contaminated by the same phenomenon as the degree-9 polynomial: it fits the specific noise of that historical sample. The only defense is a genuine out-of-sample test: data the fitting process never touched, evaluated exactly once, ideally arranged in time order so no future information leaked backward (see Walk-Forward Analysis). A strategy whose backtest Sharpe collapses on paper-traded or live data has not been unlucky — it has simply had its generalization error revealed for the first time.

Practice

  1. A model has 2% training error and 2.1% test error. Another has 0% training error and 8% test error. Which would you trust more for live deployment, and why?
  2. Why is it mathematically guaranteed that training error can only go down (or stay flat) as you add more flexibility to a model, while test error has no such guarantee?
  3. A researcher reports a backtest Sharpe ratio of 3.0 computed on the same five years of data used to select the strategy's three parameters. What number would you ask for before believing it?

The trap is treating a low training error as evidence of a good model rather than evidence of a flexible one. A sufficiently complex model can always drive training error toward zero regardless of whether there is any real pattern to learn — an interpolating model can pass through every training point exactly and still be worthless on new data. Never report or trust a performance number computed on the same data used to fit or select the model; it answers "did this model memorize its homework," not "will this model work tomorrow."

Related concepts

Practice in interviews

Further reading

  • Hastie, Tibshirani & Friedman, The Elements of Statistical Learning, ch. 7
  • Vapnik, The Nature of Statistical Learning Theory
ShareTwitterLinkedIn