Skip to content

Bias vs Variance Tradeoff

What you’ll learn

  • the decomposition E[(yf^)2]=bias2+variance+σ2\mathbb{E}[(y - \hat{f})^2] = \text{bias}^2 + \text{variance} + \sigma^2, derived line by line
  • what the expectation is taken over, which is the part that confuses everyone
  • the three terms computed by hand from four numbers
  • the same three terms measured by simulation across model capacity
  • why the third term is a hard floor, and how to estimate it
  • why “tradeoff” is slightly the wrong word for modern models

Intuition

Underfitting vs Overfitting diagnosed two failures from measurements. This page explains why there are exactly two, and where a third, unfixable source of error comes from.

The thought experiment: imagine training your model not once but a thousand times, each on a fresh sample from the same source. You now have a thousand models, and at any input x0x_0 a thousand predictions. Two things can be wrong with that cloud of predictions:

  • Bias — the cloud is centred in the wrong place. Every model makes the same mistake.
  • Variance — the cloud is spread out. The models disagree with each other.

And one thing is wrong with the target rather than the models: noise. Even a perfect model cannot predict the part of yy that is not a function of xx.

figureFifty models per panel, each trained on its own samplematplotlib
Three panels of fifty fitted curves each, from fifty different training samples. Degree 1 fits cluster tightly away from the truth; degree 4 fits track it closely; degree 15 fits scatter widely around it.Three panels of fifty fitted curves each, from fifty different training samples. Degree 1 fits cluster tightly away from the truth; degree 4 fits track it closely; degree 15 fits scatter widely around it.
The amber line is the average of the fifty; the dashed green line is the truth. Distance between them is bias. Spread of the faint blue lines around amber is variance.

That figure is the decomposition, drawn. Left panel: amber sits well away from green (high bias) and the blue lines are tight (low variance). Right panel: amber tracks green (low bias) and the blue lines are everywhere (high variance).

The math

Setup

The data is generated by an unknown function plus noise:

y=f(x)+ε,E[ε]=0,Var(ε)=σ2y = f(\mathbf{x}) + \varepsilon, \qquad \mathbb{E}[\varepsilon] = 0, \qquad \operatorname{Var}(\varepsilon) = \sigma^2

You fit f^\hat{f} on a training set DD. Because DD is a random sample, f^\hat{f} is itself random. Fix an input x0\mathbf{x}_0 and ask for the expected squared error there, averaged over both the noise and the choice of training set:

Err(x0)=ED,ε[(yf^D(x0))2]\text{Err}(\mathbf{x}_0) = \mathbb{E}_{D,\,\varepsilon}\left[\left(y - \hat{f}_D(\mathbf{x}_0)\right)^2\right]

That double expectation is the whole subtlety. You never observe it — you have one training set — but it is what “how good is this modelling approach” means.

Derivation

Write fˉ(x0)=ED[f^D(x0)]\bar{f}(\mathbf{x}_0) = \mathbb{E}_D[\hat{f}_D(\mathbf{x}_0)] for the average prediction across training sets. Add and subtract it inside the square:

yf^=εnoise+(ffˉ)bias+(fˉf^)variancey - \hat{f} = \underbrace{\varepsilon}_{\text{noise}} + \underbrace{\left(f - \bar{f}\right)}_{\text{bias}} + \underbrace{\left(\bar{f} - \hat{f}\right)}_{\text{variance}}

Square, and take the expectation of all nine terms. Every cross term vanishes:

  • E[ε]=0\mathbb{E}[\varepsilon] = 0 and ε\varepsilon is independent of DD, so both cross terms involving ε\varepsilon are zero.
  • ED[fˉf^]=0\mathbb{E}_D[\bar{f} - \hat{f}] = 0 by the definition of fˉ\bar{f}, and (ffˉ)(f - \bar{f}) is a constant with respect to DD, so their cross term is zero too.

What remains is three squares:

  Err(x0)=(f(x0)fˉ(x0))2bias2+ED[(f^D(x0)fˉ(x0))2]variance+σ2irreducible  \boxed{\; \text{Err}(\mathbf{x}_0) = \underbrace{\left(f(\mathbf{x}_0) - \bar{f}(\mathbf{x}_0)\right)^2}_{\text{bias}^2} + \underbrace{\mathbb{E}_D\left[\left(\hat{f}_D(\mathbf{x}_0) - \bar{f}(\mathbf{x}_0)\right)^2\right]}_{\text{variance}} + \underbrace{\sigma^2}_{\text{irreducible}} \;}

Three non-negative terms. Two you control, one you do not.

Worked example by hand

You train the same model on four different samples. At one input x0\mathbf{x}_0, the four predictions are:

f^1=3,f^2=5,f^3=4,f^4=8\hat{f}_1 = 3,\quad \hat{f}_2 = 5,\quad \hat{f}_3 = 4,\quad \hat{f}_4 = 8

The true value is f(x0)=6f(\mathbf{x}_0) = 6, and the noise has σ2=1\sigma^2 = 1.

Step 1 — the average prediction.

fˉ=3+5+4+84=5\bar{f} = \frac{3 + 5 + 4 + 8}{4} = 5

Step 2 — bias.

bias=fˉf=56=1,bias2=1\text{bias} = \bar{f} - f = 5 - 6 = -1, \qquad \text{bias}^2 = 1

Step 3 — variance.

Var=(35)2+(55)2+(45)2+(85)24=4+0+1+94=3.5\operatorname{Var} = \frac{(3-5)^2 + (5-5)^2 + (4-5)^2 + (8-5)^2}{4} = \frac{4 + 0 + 1 + 9}{4} = 3.5

Step 4 — total expected error.

Err=bias2+Var+σ2=1+3.5+1=5.5\text{Err} = \text{bias}^2 + \operatorname{Var} + \sigma^2 = 1 + 3.5 + 1 = 5.5

Step 5 — verify directly. Compute the mean squared distance from each prediction to the true ff, then add the noise term:

(36)2+(56)2+(46)2+(86)24+σ2=9+1+4+44+1=4.5+1=5.5\frac{(3-6)^2 + (5-6)^2 + (4-6)^2 + (8-6)^2}{4} + \sigma^2 = \frac{9 + 1 + 4 + 4}{4} + 1 = 4.5 + 1 = 5.5

The two routes agree, and 4.5=1+3.54.5 = 1 + 3.5 confirms the decomposition exactly. Note what it says about this model: variance (3.5) is three and a half times bias² (1), so the problem is instability, not systematic error. Simplify or average, do not add capacity.

Measuring it

You cannot compute this on real data — you have one training set and you do not know ff. On simulated data you know both, so the terms can be measured directly.

figure200 training sets per degree, three terms measuredmatplotlib
Log-scale plot of bias squared, variance and total expected error against polynomial degree from 1 to 12, with a dotted line marking the irreducible noise floor at 0.1225 and a vertical marker at the minimum.Log-scale plot of bias squared, variance and total expected error against polynomial degree from 1 to 12, with a dotted line marking the irreducible noise floor at 0.1225 and a vertical marker at the minimum.
Bias falls steeply and then flattens; variance is quiet until degree 6 and then explodes. Their sum has a clear minimum, and neither term alone would have found it.

Measured with 200 simulated training sets of 30 points each, σ=0.35\sigma = 0.35 so σ2=0.1225\sigma^2 = 0.1225:

Degreebias²variancetotalDominant term
10.47430.04740.6442bias — 10× the variance
20.25930.05590.4377bias
40.01680.04610.1854balanced, and the minimum
80.00561.43301.5611variance — 256× the bias²
1232.55712478.052510.73numerical collapse

Reading the plot

  1. Bias falls fast, then stops. From 0.474 at degree 1 to 0.017 at degree 4 — a 96% reduction. Past that there is nothing left to remove, and degree 8 only improves it to 0.006.
  2. Variance is quiet, then explodes. Flat around 0.05 up to degree 4, then 1.43 by degree 8 — a thirtyfold jump for two extra degrees.
  3. The minimum is where the curves cross in importance, not where either is smallest.
  4. Degree 12 is a numerical artefact worth noticing. Bias² rises to 32, which the theory says should not happen — more capacity cannot increase bias. What actually happened is that fitting a degree-12 polynomial to 30 points is so ill-conditioned that the fits are numerically garbage, so even their average is wild. Real instability, showing up in a term that should be monotone.
measure_decomposition.py
import numpy as np
 
TRUE = lambda x: np.sin(1.5 * x) + 0.35 * x
NOISE = 0.35
x_eval = np.linspace(0, 6, 200)
truth = TRUE(x_eval)
 
rng = np.random.default_rng(1)
 
for degree in (1, 2, 4, 8):
    predictions = np.empty((200, len(x_eval)))
    for run in range(200):
        x = rng.uniform(0, 6, 30)
        y = TRUE(x) + rng.normal(0, NOISE, 30)
        predictions[run] = np.polyval(np.polyfit(x, y, degree), x_eval)
 
    mean_prediction = predictions.mean(axis=0)
    bias_squared = float(((mean_prediction - truth) ** 2).mean())
    variance = float(predictions.var(axis=0).mean())
    total = bias_squared + variance + NOISE**2
 
    print(f"degree {degree:2d}  bias^2 {bias_squared:8.4f}  "
          f"variance {variance:8.4f}  total {total:8.4f}")
 
# degree  1  bias^2   0.4743  variance   0.0474  total   0.6442
# degree  2  bias^2   0.2593  variance   0.0559  total   0.4377
# degree  4  bias^2   0.0168  variance   0.0461  total   0.1854
# degree  8  bias^2   0.0056  variance   1.4330  total   1.5611
measure_decomposition.py
import numpy as np
 
TRUE = lambda x: np.sin(1.5 * x) + 0.35 * x
NOISE = 0.35
x_eval = np.linspace(0, 6, 200)
truth = TRUE(x_eval)
 
rng = np.random.default_rng(1)
 
for degree in (1, 2, 4, 8):
    predictions = np.empty((200, len(x_eval)))
    for run in range(200):
        x = rng.uniform(0, 6, 30)
        y = TRUE(x) + rng.normal(0, NOISE, 30)
        predictions[run] = np.polyval(np.polyfit(x, y, degree), x_eval)
 
    mean_prediction = predictions.mean(axis=0)
    bias_squared = float(((mean_prediction - truth) ** 2).mean())
    variance = float(predictions.var(axis=0).mean())
    total = bias_squared + variance + NOISE**2
 
    print(f"degree {degree:2d}  bias^2 {bias_squared:8.4f}  "
          f"variance {variance:8.4f}  total {total:8.4f}")
 
# degree  1  bias^2   0.4743  variance   0.0474  total   0.6442
# degree  2  bias^2   0.2593  variance   0.0559  total   0.4377
# degree  4  bias^2   0.0168  variance   0.0461  total   0.1854
# degree  8  bias^2   0.0056  variance   1.4330  total   1.5611

See it move

The classic dartboard. Each panel is a different model, each dart a different training set. Bias is how far the cluster sits from the bullseye; variance is how wide the cluster is.

sketch The four combinations of bias and variance p5.js
Four targets, each receiving darts from a model with a different bias and variance profile. The centre of the cluster is bias; its width is variance.

The irreducible term

σ2\sigma^2 is the variance of yy given x\mathbf{x} — the part of the target that the features simply do not determine. Two identical districts can sell for different prices; two patients with identical charts can have different outcomes.

No model reduces it. A reported error below σ2\sigma^2 is not a triumph, it is evidence of a leak or of evaluating on training data.

You can estimate it, though: fit a very flexible model with plenty of data and see where the validation error plateaus. That floor is roughly σ2\sigma^2, and it tells you when to stop investing in the model and start investing in better features — because more features are the only thing that reduces σ2\sigma^2. Adding a column that genuinely explains part of the leftover variation moves the floor down; nothing else does.

What moves each term

ActionBiasVarianceNet
Increase model capacityDepends where you are on the curve
Add training data↓↓Almost always good
Add regularisationGood if variance dominates
Add informative features↑ slightlyUsually good
Add noise featuresBad
Bagging / random forest↓↓The whole point
Boosting↓↓The whole point, from the other direction
Early stoppingGood if variance dominates

The last two rows are why Phase 5 exists. Bagging averages many high-variance, low-bias models and cancels the variance; boosting combines many high-bias, low-variance models and cancels the bias. Both are direct applications of this decomposition rather than clever tricks.

Diagnosing from two numbers

You cannot measure bias and variance separately on real data, but the pair (training error, validation error) tells you which term dominates — and that is enough to choose the next action:

diagram Diagram mermaid

The loop matters as much as the branches: every action changes the two numbers, so the diagnosis has to be repeated rather than made once. The costly mistake is taking the “variance” action — collect more data — while sitting in the “bias” branch, where more data changes nothing at all.

Pitfalls

quizCheck yourself
  1. In the decomposition, what is the expectation taken over?

    Show answer

    B — Both the noise in the target and the random choice of training set — the model itself is a random object — Variance measures how much the fitted model changes when you resample the training data. Without averaging over training sets there is no variance term at all.

  2. Four models predict 3, 5, 4 and 8 at a point where the truth is 6, with noise variance 1. What is the variance term?

    Show answer

    B — 3.5 — The mean prediction is 5, so the variance is ((3-5)² + 0 + (4-5)² + (8-5)²)/4 = 14/4 = 3.5. Bias² is 1 and the total is 5.5.

  3. Between degree 4 and degree 8, bias² falls from 0.0168 to 0.0056 while variance rises from 0.046 to 1.433. What should you do?

    Show answer

    B — Use degree 4 — the tiny bias gain costs a thirtyfold increase in variance, and the total error is eight times worse — The total is what matters: 0.185 against 1.561. Bias had almost nothing left to give, and variance had a great deal left to take.

  4. Your validation MSE has plateaued at 0.13 and you estimate the noise floor at 0.12. What now?

    Show answer

    B — Stop tuning the model; the only way lower is better features, because sigma-squared is a property of the data, not the model — You are within 8% of the theoretical floor. No model can go below sigma-squared, and only a feature that genuinely explains more of the target moves that floor.

🧪 Try It Yourself

Exercise 1 – Decompose four predictions

Exercise 2 – Verify the decomposition

Exercise 3 – Measure both terms by simulation

Exercise 4 – Watch averaging kill variance

Exercise 5 – Find the noise floor

Recap

  • Err=bias2+variance+σ2\text{Err} = \text{bias}^2 + \text{variance} + \sigma^2, exactly, with every cross term vanishing.
  • The expectation is over the noise and the random training set — variance only exists because the model is itself a random object.
  • Hand-worked: predictions 3, 5, 4, 8 against a truth of 6 give bias² 1, variance 3.5, total 5.5, and both routes agree.
  • Measured: bias² falls 0.474 → 0.017 by degree 4, while variance rises 0.046 → 1.433 by degree 8. The minimum total is at degree 4.
  • σ2\sigma^2 is a floor. Only better features move it; no model does.
  • Bagging attacks variance, boosting attacks bias, and both come directly from this decomposition.

Exercise 6 – Decompose the error, empirically

Next

Continue to K-Fold Cross-Validation — the practical machinery for estimating held-out error without the thousand training sets this page assumed.

If this helped you, consider buying me a coffee ☕

Buy me a coffee

Was this page helpful?

Let us know how we did