Problem
The overfitting page said that too simple a model underfits and too flexible a model overfits. That is a description. To reason about it, to say why an ensemble helps or why a penalty helps, we need the error written as parts that each respond differently to the choices we make.
The question: for a fixed query point, if we could redraw the training set many times and refit, what does the average squared error consist of?
Intuition
Picture a dart player throwing many rounds at one target. Bias is how far the centre of the cluster of darts is from the bullseye. Variance is how spread out the darts are around their own centre. A steady player who aims a little left has high bias and low variance; a shaky player who aims correctly on average has low bias and high variance. Noise is a target that itself jitters: even a perfect player misses by that much.
Each training set is one round of throws, and the fitted model's prediction at a point is the dart. A straight line fitted to a sine wave lands in nearly the same wrong place every time (high bias, low variance). A degree-9 polynomial tracks whichever noise it was shown (low bias, high variance). Ways to cut variance without raising bias much, such as averaging many models or penalizing large coefficients, are what make flexible models usable.
Bias² falls as the degree rises while variance climbs; the ridge penalty pulls the degree-9 variance back down.
Mechanics
The decomposition
Let the data be y = f(x) + ε with E[ε] = 0 and Var(ε) = σ². Let f̂ be the model fitted on a random training set D. At a fixed x, the expectation below is over D and over the noise in the test label y:
E[(y − f̂(x))²]
= E[(f(x) + ε − f̂)²]
= σ² + E[(f(x) − f̂)²] (ε is independent of f̂ and has mean 0)
= σ² + (f(x) − E[f̂])² + E[(f̂ − E[f̂])²] (add and subtract E[f̂]; the cross term is 0)
= noise + bias² + variance
Two steps do all the work. First, the noise in the new label is independent of anything the model learned, so its contribution separates. Second, adding and subtracting the average prediction E[f̂] makes the cross term vanish because E[f̂ − E[f̂]] = 0. Averaging over x as well gives a single number for each part. The result holds for squared error; other losses do not split this cleanly (see loss functions). The expectation and variance page has the rules used here.
Bias is the gap between a model family's average fit and the truth, not the error of any one fit.
Measuring it
On real data f is unknown and there is only one training set, so the three parts cannot be read off directly. They can be estimated when the data are simulated, as on this page: draw many training sets, fit each, and at each test x compute the mean prediction, the squared gap of that mean from f (bias²), and the spread of the predictions around it (variance). On real data the practical stand-ins are curves, covered next.
Reading the parts from curves
- High bias. Training and validation error are both high and close together. A learning curve is flat: more rows do not help, because the model family cannot represent the pattern.
- High variance. Training error is low, validation error is far above it. The learning curve's gap narrows as rows are added, since more data pins the fit down.
- The validation curve over complexity is U shaped: the left arm is bias, the right arm is variance, the floor is noise plus whatever the best model leaves.
The fixes are asymmetric. Variance falls with more data, simpler models, regularization and averaging many models. Bias falls with richer models and better features, and does not fall with more data.
Averaging cuts variance
If M predictions each have variance v and pairwise correlation ρ, their average has variance ρv + (1 − ρ)v/M. Averaging leaves the bias of each member unchanged (the mean of the average is the average of the means) and shrinks the second term towards zero as M grows. Bagging makes the members differ by fitting each on a bootstrap resample of the rows; the more decorrelated the members, the more variance disappears. Boosting works the other way, mostly reducing bias, as the gradient boosting page showed.
| Component | Shape/Params | Meaning | Source |
|---|---|---|---|
learning_curve |
train_sizes, cv |
Train and validation scores against training set size: flat and together means bias, a closing gap means variance. | _validation.py |
_translate_train_sizes |
fractions or counts | Turns the requested sizes into absolute row counts, rejecting sizes that do not fit. | _validation.py |
validation_curve |
param_name, param_range |
Scores one hyperparameter at each value with cross-validation: the U-shaped complexity curve. | _validation.py |
Worked example
Splitting the error of polynomial fits
Data: y = sin(2πx) + ε, ε ~ N(0, 0.3²), x uniform on 0 to 1, so σ² = 0.090. Each model is fitted on 100 different random training sets of 25 rows, and judged on 40 evenly spaced test points against the true sine (noise is added back as σ²). Averages over those points:
| Model | Bias² | Variance | Noise | Total |
|---|---|---|---|---|
| degree 1 | 0.1959 | 0.031 | 0.090 | 0.317 |
| degree 3 | 0.0045 | 0.021 | 0.090 | 0.115 |
| degree 5 | 0.0009 | 0.093 | 0.090 | 0.184 |
| degree 7 | 0.0366 | 2.065 | 0.090 | 2.191 |
| degree 9, ridge 0.01 | 0.0053 | 0.070 | 0.090 | 0.165 |
The straight line has bias² 0.196: no line fits a sine, however much data it sees. The cubic cuts bias² to 0.0045 at about the same variance, so it is the best row here, total 0.115, near the noise floor. Beyond that, bias² is already near zero and variance takes over: 0.093 at degree 5 and 2.065 at degree 7. The total is each row's bias² + variance + noise; the table adds exactly.
Two ways to cut the variance of degree 9
A degree-9 polynomial with almost no penalty (α = 0.001) has bias² 0.0034 and variance 0.226. Two remedies, same data and test points:
| Model | Bias² | Variance |
|---|---|---|
| degree 9, α = 0.001 | 0.0034 | 0.226 |
| same, bagged over 15 bootstrap fits | 0.0016 | 0.176 |
| degree 9, α = 0.01 | 0.0053 | 0.070 |
Bagging lowers the variance by 22% and leaves the bias nearly unchanged, as the averaging formula predicts. The members are strongly correlated (they see overlapping rows and fit the same family), so it does not approach 1/15. A ten-times larger penalty cuts the variance by 69% at the price of a little extra bias. Both are variance remedies; they differ in cost: bagging multiplies fitting time by 15, the penalty costs nothing extra.
Implementation
import numpy as np
from sklearn.linear_model import Ridge
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import PolynomialFeatures
rng = np.random.default_rng(0)
grid = np.linspace(0.0125, 0.9875, 40).reshape(-1, 1)
truth = np.sin(2 * np.pi * grid[:, 0])
preds = []
for _ in range(200): # 200 fresh training sets
x = rng.uniform(0, 1, (25, 1))
y = np.sin(2 * np.pi * x[:, 0]) + rng.normal(0, 0.3, 25)
model = make_pipeline(PolynomialFeatures(3), Ridge(alpha=1e-3)).fit(x, y)
preds.append(model.predict(grid))
preds = np.array(preds) # (200, 40)
bias2 = ((preds.mean(axis=0) - truth) ** 2).mean()
variance = preds.var(axis=0).mean()
print(bias2, variance, 0.3 ** 2) # error = sum of the three
This only works when the truth is known. For real data, fit with learning_curve and validation_curve from sklearn.model_selection and read the diagnosis from the shapes described above.
Tradeoffs
- Squared error only. The clean three-way split needs squared loss. Classification with 0–1 loss has several competing decompositions, and none is as tidy.
- Not a strict ladder. The "U" shape is typical for classical models but not universal. Very large networks and boosted ensembles can reach zero training error and still improve on new data as they grow (double descent; see generalization), so variance does not always rise with capacity.
- Hard to measure for real. With one dataset you cannot redraw training sets; bootstrap resampling approximates it, and learning curves give indirect evidence. The numbers on this page come from a known truth.
- Remedies trade against each other. A bigger penalty cuts variance and raises bias; the best setting is found by validation, not by theory.
- Even-degree polynomials look odd here. The sine is an odd function around the middle of the interval, so degree 2 adds variance and no bias reduction over degree 1; the table sticks to odd degrees.
Check yourself
A model has training error 0.30 and validation error 0.31, with a noise floor of 0.05. Which term dominates, and will 10× more data help?
Bias: both errors are high and together. More data will not help; the model family needs more capacity or better features.
Why does averaging 100 identical copies of one model not reduce its variance?
The members are perfectly correlated (ρ = 1), so ρv + (1 − ρ)v/M is just v. Averaging only helps to the extent that the members make different errors.
In E[(y − f̂)²] = σ² + bias² + variance, which term can a better model never remove?
The noise σ²: it is the variance of the label around f(x), which no function of x can predict.
Connections
Read first
- Generalization intro
- Expectation, variance and sampling intro
Read next
- Random forests core
References
- Hastie, Tibshirani and Friedman. The Elements of Statistical Learning, section 7.3: the bias–variance decomposition.
- Geman, Bienenstock and Doursat. Neural networks and the bias/variance dilemma. Neural Computation, 1992.
- Belkin, Hsu, Ma and Mandal. Reconciling modern machine-learning practice and the classical bias–variance trade-off. PNAS 2019. arXiv:1812.11118.
- Breiman. Bagging predictors. Machine Learning, 1996.
- scikit-learn 1.9.1:
learning_curve,validation_curve.