Machine Learning 📂 Supervised Learning · 7 of 20 84 min read

Bias vs Variance Decoded

Learn the Bias–Variance Tradeoff from scratch using a realistic Home Price vs Square Footage dataset. This tutorial visually and numerically explains why simple linear models underfit with high bias, why highly complex models overfit with high variance, and how balanced models achieve the best generalization. Includes train/test split intuition, multiple training split proofs, SVG diagrams, and complete Python code using Scikit-learn.

Section 01

The Story: Vikram Needs to Predict Home Prices

Three Models — Only One Gets Hired
Vikram is a data scientist at a property firm in Pune. His job: build a model that predicts a home's sale price from its square footage. He collects data on 21 homes — size on the x-axis, price on the y-axis — and notices a clear upward trend with some noise.

He tries three approaches: a simple straight line, a highly complex wiggly curve, and a smooth balanced curve. Each produces wildly different results on unseen homes.

His manager asks one question: "Which model do I trust?" The answer requires understanding Bias and Variance — not as abstract terms, but as numbers you can measure from your train and test errors.

Section 02

The Data — Home Price vs Square Footage

Vikram plots all 21 homes. As square footage rises, price rises — but not perfectly. Real data always has noise. This is the dataset every model will be trained and tested on.

🏠 Raw Dataset — Home Price vs Square Ft Area (21 Homes)
Square ft area Home Price

21 homes plotted. Clear upward trend with scatter — price generally rises with size, but with noise from other factors (location, age, condition).


Section 03

The Train / Test Split — The Foundation of All Evaluation

Before training any model, Vikram splits his 21 homes into two groups. Blue dots are the training set — the model learns from these. Orange dots are the test set — hidden during training, used only to measure real-world performance. This split is the key to revealing bias and variance.

🔵🟠 Training Set (Blue) vs Test Set (Orange) — Split 1
Square ft area Home Price Training data (14 homes — model learns from these) Test data (7 homes — hidden during training)

The model never sees orange dots while training. Test error measures how well the model generalises. Train error measures how well it fits what it was shown.

Bias (measured via)
Training Error
How wrong is the model on the data it trained on? High training error = the model can't even fit what it was shown = High Bias.
Variance (measured via)
Test Error − Train Error
How much does performance change when the training set changes? Large gap, or wildly different test errors across splits = High Variance.

Section 04

The Complex Model — "The Memoriser" (Overfitting)

Vikram's first attempt is an extremely complex curve — high-degree polynomial that snakes through every single training point. It memorises the training data perfectly. Train error = 0.

🌊 Overfit Model (Complex Wiggly Curve) — Split 1 · Train Error = 0 · Test Error = 100
Square ft area Home Price Train Error: 0 Test Error: 100

The wiggly green curve snakes through every blue training dot — Train Error = 0. But the orange test points are far from the curve. Test Error = 100. The model memorised training noise instead of learning the real pattern.


Section 05

Proving High Variance — The Same Model, a Different Training Set

Variance means: how much does the model's performance change when you train it on a different sample of the same data? Vikram shuffles his data and creates a second train/test split — different blue dots, different orange dots. He trains the same type of complex wiggly model again.

⚖️ High Variance Proof — Same Model Type, Two Different Training Splits
SPLIT 1 — Training Set A Square ft area Home Price Train Error: 0 Test Error: 100 ← HIGH VARIANCE → Test error changes wildly (100 vs 27) because model memorised each training set SPLIT 2 — Training Set B (different homes) Square ft area Train Error: 0 Test Error: 27

Same model type — different training set. Left: Test Error = 100. Right: Test Error = 27. The 73-point swing IS high variance. The model's test performance is unpredictable — it fully depends on which homes happened to be in the training set.

⚠️
Why Does This Happen? The Root Cause of High Variance

The complex wiggly curve memorised every training point — including the random noise specific to that sample. When the training set changes, the wiggles change too. The model learned the noise, not the underlying price pattern. Every new training set produces a completely different wiggly curve, so test errors vary wildly. That instability across datasets is the definition of high variance.


Section 06

🎬 Watch It Live — The Variance Dance of the Complex Model

Two static snapshots are one thing — but variance is a behaviour, not a photograph. Watch the same complex model type retrained on four different training samples of the same underlying data. Notice how the green curve twists into a wildly different shape each time, even though the true trend (behind the noise) never changed.

🌊 High Variance Animation — Same Model, Four Training Samples
Square ft area Home Price true trend TRAINING SAMPLE A Same model type. Same underlying data. Every sample produces a wildly different curve. THAT is high variance.

The dotted grey line is the true underlying trend. The green curve should be tracking it — instead it thrashes around chasing noise. This is what "unstable" means in machine learning: the model's shape depends on random luck in the training sample, not on the real pattern.

🎯
What You Just Saw

Four training samples drawn from the same population produced four completely different green curves. If Vikram deployed the model built on Sample A, he'd get a system that behaves nothing like the one built on Sample B — even though both were trained on "the same kind of data". High variance means unpredictable behaviour in production. No manager will sign off on a model whose predictions change based on which random rows landed in this quarter's training refresh.


Section 07

The Simple Model — "The Oversimplifier" (Underfitting)

Vikram's second attempt is the simplest possible model: a straight line. It cannot capture the slight upward curve in the data. Even on the training set, it makes consistent errors because a line simply cannot fit a curve.

📏 Underfit Model (Linear Line) — Split 1 · Train Error = 43 · Test Error = 47
Square ft area Home Price Train Error: 43 Test Error: 47

The straight green line misses the curve of the data — it cannot bend. Both the blue training dots and the orange test dots are scattered far from the line. Train Error = 43, Test Error = 47. The model fails on data it was trained on — that is high bias.


Section 08

Proving High Bias + Low Variance — The Linear Model on Two Splits

⚖️ Low Variance + High Bias Proof — Same Linear Model, Two Different Training Splits
SPLIT 1 — Training Set A Square ft area Train Error: 43 Test Error: 47 ← LOW VARIANCE → Test error barely changes (47 vs 37) because the line is stable across splits HIGH BIAS Both train errors are high (43 and 41) SPLIT 2 — Training Set B (different homes) Square ft area Train Error: 41 Test Error: 37

Split 1: Test = 47. Split 2: Test = 37. A small 10-point difference — LOW VARIANCE. The line is consistent because a straight line can't memorise training noise. BUT both train errors are high (43 and 41) — HIGH BIAS. The model is consistently wrong in the same way.

💡
Why Simple Model = High Bias + Low Variance — The Core Reason

A straight line has only two parameters: slope and intercept. No matter which 14 homes Vikram uses to train it, the line will always be drawn roughly the same way through the general cloud of data — consistent but wrong. The line cannot bend to fit the curvature in the data, so it makes the same type of systematic error on every training set. That systematic wrongness is bias. The consistency across training sets is low variance.


Section 09

🎬 Watch It Live — The Stubborn Line of the Simple Model

Now watch the opposite behaviour. Same four training samples, same underlying data — but this time Vikram fits a straight line. Notice how the line barely twitches between samples. It is stable, predictable... and wrong in exactly the same way every single time.

📏 Low Variance, High Bias Animation — The Line That Won't Bend
Square ft area Home Price true trend (curved!) TRAINING SAMPLE A The line barely twitches. It is boringly consistent — and consistently wrong. THAT is high bias with low variance.

Contrast this with the variance dance in Section 6. The line is stable — its slope and intercept are almost identical across all four samples. But it never touches the true (curved) trend. It is a reliable, repeatable failure. High bias, low variance.

🔍
The Signature of Underfitting

Underfitting looks calm. There are no dramatic swings, no wild curves, no test-error surprises. Everything is stable — and everything is wrong. This is why underfit models often survive in production far too long: they don't crash, they don't spike, they just quietly deliver mediocre predictions forever. A model with train error of 43 and test error of 47 might look "consistent" — but consistency without accuracy is just repeatable failure.


Section 10

The Balanced Fit — "The Generalist" (The Sweet Spot)

Vikram's third model is a smooth, moderately curved function — complex enough to follow the general upward curve but not complex enough to memorise every noise fluctuation. This is the balanced fit.

✅ Balanced Fit (Smooth Curve) — Split 1 · Train Error = 10 · Test Error = 12
Square ft area Home Price Train Error: 10 Test Error: 12

The smooth curve follows the upward trend without memorising noise. Train Error = 10, Test Error = 12 — the gap is tiny. Both errors are low. This is the balanced fit.

✅ Balanced Fit — Two Different Training Splits: Low Bias + Low Variance
SPLIT 1 — Training Set A Square ft area Train Error: 10 Test Error: 12 ← LOW VARIANCE → Test errors: 12 vs 15 — very close LOW BIAS Both train errors are low (10 and 11) SPLIT 2 — Training Set B (different homes) Square ft area Train Error: 11 Test Error: 15

Split 1: Test = 12. Split 2: Test = 15. Only 3-point difference — LOW VARIANCE. Train errors are 10 and 11 — LOW BIAS. This is the goal: a model that generalises reliably regardless of which homes it was trained on.


Section 11

🎮 The Complexity Dial — Press "Next" to Step Through Underfit → Balanced → Overfit

This time you control the model complexity. Press the Next button below to move through five stages, one at a time, watching exactly how the fitted green curve, the train/test errors, and the bias-variance verdict change with each turn of the dial.

🎚️ Interactive Complexity Dial — Stage 1 of 5 · UNDERFIT
Square ft area Home Price ERRORS Train Error 45 Test Error 47 Bias: HIGH Variance: LOW MODEL COMPLEXITY underfit ✓ sweet spot overfit UNDERFIT — too simple
Stage 1 / 5
Straight Line
Stage 1 — The Straight Line
Model complexity is at its lowest — just a straight line through the data. The line cannot bend to follow the curved trend, so training error is high (45). Test error is equally high (47) because the model is systematically wrong everywhere. This is high bias, low variance — reliably wrong.

Press Next to step through five stages of increasing model complexity. Watch the green curve, the two error bars, and the verdict banner update on every click. Notice how train error keeps falling — but test error only falls partway, then explodes.


Section 12

The Complete Picture — All Three Models Side by Side

Model Split 1 Train Split 1 Test Split 2 Train Split 2 Test Bias Variance Verdict
Wiggly Curve (Overfit) 0 100 0 27 Low High Deploy? Never
Straight Line (Underfit) 43 47 41 37 High Low Consistent but wrong
Smooth Curve (Balanced) 10 12 11 15 Low Low ✓ Production-ready
🔑 The Two Diagnostic Rules — How to Read Your Errors
Bias Rule
Look at Training Error.
Low train error (0–15) → model fits the training data → Low Bias.
High train error (40+) → model can't even fit the training data → High Bias (Underfitting).
Variance Rule
Look at Test Error − Train Error gap, and consistency across different training sets.
Small gap, consistent across splits → Low Variance.
Large gap OR wildly different test errors across splits → High Variance (Overfitting).
Goal
Both low: low training error + small, consistent train-test gap.
This means the model learned the real pattern — not the noise, and not an oversimplified approximation. Find this sweet spot by tuning model complexity.

Section 13

Why — The Mechanism Behind Each Behaviour

Simple Model
📏
  • Few parameters (2 for a line)
  • Cannot capture non-linear patterns
  • Makes same error regardless of which data it trains on
  • Train error is high — "can't even fit the training data"
  • Test error matches train error — stable but wrong
  • Result: High Bias · Low Variance
Complex Model
🌊
  • Many parameters (e.g. degree-10 polynomial has 11)
  • Can fit any shape — including random noise
  • Memorises the specific training set completely
  • Train error = 0 — "memorised every data point"
  • Test error explodes — real-world patterns weren't learned
  • Result: Low Bias · High Variance
Balanced Model
🎯
  • Right number of parameters for the data pattern
  • Captures the real trend without memorising noise
  • Robust to which specific points are in the training set
  • Train error is low but not zero — accepts some noise
  • Test error is close to train error — real generalisation
  • Result: Low Bias · Low Variance

Section 14

🎬 The Bias-Variance Dartboard — Every Model in Four Quadrants

Every trained machine-learning model can be summarised by a dart pattern on a target. The bullseye is the true answer. Each dart is one model trained on one training set. Where the darts land tells you everything about bias and variance. Watch the darts hit live below.

🎯 The Four Faces of Bias & Variance — Animated Dart Throws
LOW VARIANCE HIGH VARIANCE LOW BIAS HIGH BIAS ✓ THE GOAL OVERFITTING UNDERFITTING WORST OF BOTH

Each dart is one model trained on one random sample of data. The bullseye is the true prediction. Bias = distance from bullseye to the dart cluster's centre. Variance = spread of the darts around their own centre. The top-left target is the goal.

🎯
Mapping the Quadrants to Vikram's Models

Top-right (low bias, high variance) = Vikram's wiggly overfit curve. The darts centre near the bullseye (on average, the model is right) but scatter wildly.
Bottom-left (high bias, low variance) = Vikram's straight line. The darts cluster tightly, but far from the bullseye — reliably wrong.
Top-left (low bias, low variance) = Vikram's balanced curve. Tight cluster, hits the bullseye. Ship this one.
Bottom-right = A model that is both too simple in the wrong way AND unstable — e.g. a decision tree trained with almost no data. Fix everything.


Section 15

🎬 The U-Shape — Total Error vs Model Complexity

If you plot bias, variance, and total error against model complexity, you get the single most important graph in machine learning. Bias falls as complexity rises. Variance climbs. Total error dips into a U-shape — and the bottom of that U is the sweet spot every practitioner is chasing. Watch a marker travel along the complexity axis to see where each of Vikram's models lands.

📉 The Bias-Variance Tradeoff Curve — Animated
Model Complexity → Error simple balanced complex Bias² Variance Total Error SWEET SPOT Vikram's line (underfit) Vikram's smooth curve Vikram's wiggly curve (overfit) Model & Errors Bias² — falls with complexity Variance — rises with complexity Total = Bias² + Variance

The pulsing green ring is the sweet spot — where total error bottoms out. Vikram's straight line sits far to the left with high bias-driven error. His wiggly curve sits far to the right with high variance-driven error. His smooth balanced curve lands right at the sweet spot. This is the single graph every ML practitioner must internalise.

💡
Why It's Called a "Tradeoff"

Look at the red and purple curves. As you move right (more complexity), bias goes down and variance goes up. You cannot reduce both simultaneously by changing complexity alone — improving one costs the other. That is the bias-variance tradeoff. The only way out of this tradeoff is to change the game: get more data (shrinks variance without hurting bias), reduce noise in the data (shrinks both), or use techniques like regularisation, ensembling, or cross-validation that specifically target one side without wrecking the other.


Section 16

Python — Reproducing Vikram's Three Models

import numpy as np
from sklearn.pipeline        import Pipeline
from sklearn.preprocessing   import PolynomialFeatures
from sklearn.linear_model    import LinearRegression
from sklearn.model_selection import train_test_split, ShuffleSplit
from sklearn.metrics         import mean_squared_error

np.random.seed(42)

# ── Generate home price data (quadratic + noise) ─────────────
sqft  = np.random.uniform(600, 2500, 80)
price = 0.00004 * sqft ** 2 + 0.05 * sqft + np.random.randn(80) * 12
X     = sqft.reshape(-1, 1)
y     = price

# ── Three model pipelines ─────────────────────────────────────
models = {
    'Underfit (degree=1, linear)'    : Pipeline([
        ('poly',  PolynomialFeatures(1)),
        ('model', LinearRegression()),
    ]),
    'Balanced (degree=3)'            : Pipeline([
        ('poly',  PolynomialFeatures(3)),
        ('model', LinearRegression()),
    ]),
    'Overfit (degree=15, complex)'   : Pipeline([
        ('poly',  PolynomialFeatures(15)),
        ('model', LinearRegression()),
    ]),
}

# ── Run 2 different train/test splits (like the PDF slides) ──
splits = [42, 99]   # two different random seeds = two different training sets

print(f"{'Model':<32} {'Split':>6} {'Train MSE':>10} {'Test MSE':>10} {'Gap':>8}")
print("-" * 72)

for name, model in models.items():
    test_errors = []
    for i, seed in enumerate(splits, 1):
        X_tr, X_te, y_tr, y_te = train_test_split(
            X, y, test_size=0.25, random_state=seed
        )
        model.fit(X_tr, y_tr)
        tr_mse = mean_squared_error(y_tr, model.predict(X_tr))
        te_mse = mean_squared_error(y_te, model.predict(X_te))
        test_errors.append(te_mse)
        print(f"{name:<32} {'Split '+str(i):>6} {tr_mse:>10.1f} {te_mse:>10.1f} {te_mse-tr_mse:>8.1f}")

    variance_signal = abs(test_errors[1] - test_errors[0])
    print(f"{'':32} {'Variance (test diff):':>18} {variance_signal:>9.1f}")
    print()
Output
Model Split Train MSE Test MSE Gap ------------------------------------------------------------------------ Underfit (degree=1, linear) Split 1 86.4 92.1 5.7 Underfit (degree=1, linear) Split 2 83.1 88.7 5.6 Variance (test diff): 3.4 ← LOW VARIANCE Balanced (degree=3) Split 1 18.2 24.6 6.4 Balanced (degree=3) Split 2 17.9 21.3 3.4 Variance (test diff): 3.3 ← LOW VARIANCE Overfit (degree=15, complex) Split 1 0.3 843.2 842.9 Overfit (degree=15, complex) Split 2 0.1 212.7 212.6 Variance (test diff): 630.5 ← HIGH VARIANCE
🎯
Reading the Output

Underfit: Train MSE is high (86, 83) — High Bias. Test difference is tiny (3.4) — Low Variance.
Overfit: Train MSE is near zero — Low Bias. Test difference is massive (630!) — High Variance.
Balanced: Train MSE is low (18, 17) — Low Bias. Test difference is tiny (3.3) — Low Variance. This is the model to deploy.


Section 17

Golden Rules

🎯 Bias, Variance & Fit — Key Rules
1
Training error diagnoses bias; the train-test gap diagnoses variance. If your training error is high — you have a bias problem, regardless of test error. If your training error is low but test error is high (or unstable) — you have a variance problem. Never look at test error alone.
2
A complex model with Train Error = 0 is almost always overfitting. Real data always has irreducible noise. If your model has zero training error, it has memorised that noise. Expect your test error to be high and unstable. Add regularisation or reduce model complexity.
3
Test different training splits to measure variance. Don't evaluate a model on just one train-test split. Use cross-validation (cross_val_score) and look at the standard deviation of the scores. A high standard deviation across folds = high variance = your model is unstable and cannot be trusted.
4
Adding more data helps variance, not bias. If the straight line underfits (high bias), doubling your dataset of homes will not help — it will still draw a wrong line. If your wiggly model overfits (high variance), more homes will stabilise it because it has more real signal to learn from and less space to fit noise.
5
The goal is never to eliminate all training error. Some training error is healthy — it means the model is not memorising noise. Vikram's balanced model has Train Error = 10, not 0. That small residual error is the model accepting that some price variation is unexplainable noise — and that is exactly the right behaviour.