Part V — Non-Linear Models, Trees, Ensembles & Kernel Methods · Chapter 2

Overfitting & cost-complexity pruning

Hook

A tree that gets 100% of its training data right sounds perfect. Is it?

Intuition
Depth 1 — train accuracy = 80%

The top row is training data — five of those points are quietly mislabeled, noise a real dataset would have. Drag depth up: watch the tree stop finding the boundary and start carving out tiny one-point regions instead, each one built to rescue a single mislabeled point.

Formalize

Nothing stops a tree from growing until every training point is classified perfectly — split enough times and you can isolate any single point into its own leaf. The question isn't whether it can memorize noise, it's whether doing so helps on data it hasn't seen:

gap=accuracytrainaccuracyvalidation\text{gap} = \text{accuracy}_{\text{train}} - \text{accuracy}_{\text{validation}}
  • gap — the difference between training and validation accuracy; a growing gap signals overfitting.
  • accuracytrain\text{accuracy}_{\text{train}} — the fraction of training points the tree classifies correctly.
  • accuracyvalidation\text{accuracy}_{\text{validation}} — the fraction of held-out (never-trained-on) points the tree classifies correctly.

The gap tells you that a tree is overfitting, but it needs a validation set to compute. Cost-complexity pruning finds the right size using only training data, by charging a fixed toll for every leaf a tree keeps:

Rα(T)=R(T)+αTR_\alpha(T) = R(T) + \alpha|T|
  • Rα(T)R_\alpha(T) — tree TT's cost-complexity score at penalty strength α\alpha; smaller is better.
  • R(T)R(T)TT's training misclassification rate, 1accuracytrain1 - \text{accuracy}_{\text{train}}.
  • α\alpha — the price charged per leaf; α=0\alpha = 0 charges nothing, larger α\alpha charges more.
  • T|T|TT's leaf count, i.e. how many regions it carved feature space into.
  1. alpha=0 reduces to pure training error

    With no penalty, Rα(T)R_\alpha(T) is just R(T)R(T) — whichever tree fits training data best wins, no matter how many leaves it took to get there. This is exactly the overfitting problem, restated as an objective.

  2. Growing alpha makes extra leaves cost more than they're worth

    Each split only pays for itself if the training-error improvement it buys is bigger than α\alpha. As α\alpha rises, splits that were only rescuing one or two noisy points stop being worth their toll first.

  3. This finds the right complexity blind — no validation set needed

    Real pruning algorithms (e.g. scikit-learn's ccp_alpha) minimize exactly this objective. It's not magic: it works because α\alpha acts as a stand-in for "how much do I trust that this split reflects real structure, not noise" — the same judgment a validation set makes empirically.

Play
Depth 1 (2 leaves) — train = 80%, validation = 100%
At α = 0, cost-complexity pruning picks depth 5 (10 leaves, R_α = 0.04) — using only training data.

The bottom row is validation data the tree never trained on — clean, no mislabeled points. Depth 1 or 2 already gets every single one right. Push the depth slider past that and watch validation accuracy start dropping while training accuracy keeps climbing. The α buttons show a different way to catch this: cost-complexity pruning picks a depth using only the training-side numbers above, no validation peek required — watch its pick shrink as α grows.

Worked example
  1. Depth 1, the shallow tree

    One split at x=9.5x = 9.5:

    • Training accuracy: 20/25=80%20/25 = 80\% (the 5 mislabeled points are the only misses)
    • Validation accuracy: 24/24=100%24/24 = 100\%
    • Leaves: T=2|T|=2, so R(T)=10.80=0.20R(T) = 1-0.80 = 0.20
  2. Depth 5, the overgrown tree

    Splitting all the way to depth 5, rescuing 4 of the 5 noisy points:

    • Training accuracy: 24/25=96%24/25 = 96\%
    • Validation accuracy: 20/2483%20/24 \approx 83\% — it falls even as training accuracy climbed
    • Leaves: T=10|T|=10, so R(T)=10.96=0.04R(T) = 1-0.96 = 0.04

    (Depth 6 adds one more leaf for zero extra training accuracy, so it never wins at any α0\alpha \geq 0 — pruning drops that redundant split for free.)

  3. alpha=0: raw training error wins, and the overgrown tree looks unbeatable

    R0(depth 1)=0.20+0×2=0.20R_0(\text{depth }1) = 0.20 + 0 \times 2 = 0.20, while R0(depth 5)=0.04+0×10=0.04R_0(\text{depth }5) = 0.04 + 0 \times 10 = 0.04. Depth 5 wins by this metric alone — exactly the overfitting trap, since it's also the worse tree on validation data.

  4. alpha=0.02: an exact tie, and ties favor the smaller tree

    R0.02(depth 1)=0.20+0.02×2=0.24R_{0.02}(\text{depth }1) = 0.20 + 0.02 \times 2 = 0.24 and R0.02(depth 5)=0.04+0.02×10=0.24R_{0.02}(\text{depth }5) = 0.04 + 0.02 \times 10 = 0.24 — dead even. Real weakest-link pruning (and the code here) breaks such ties in favor of the smaller tree, so α=0.02\alpha = 0.02 is already enough to recover depth 1 — and depth 1 is also the validation-optimal tree.

  5. alpha=0.03: no longer even close

    R0.03(depth 1)=0.20+0.03×2=0.26R_{0.03}(\text{depth }1) = 0.20 + 0.03 \times 2 = 0.26, while R0.03(depth 5)=0.04+0.03×10=0.34R_{0.03}(\text{depth }5) = 0.04 + 0.03 \times 10 = 0.34. Depth 1 wins outright now — cost-complexity pruning found the right size using only training-side arithmetic, no validation set required.

Checkpoint

Pick an α large enough that cost-complexity pruning — reasoning from training data alone — lands on the same depth that reaches the best possible validation accuracy, 100%. A small α still lets the overgrown tree win; you need one where the leaf penalty actually bites.

α = 0 → depth 5 (10 leaves) — train = 96%, validation = 83%
Pick an α to try it
Summary
Rα(T)=R(T)+αTR_\alpha(T) = R(T) + \alpha|T|

Training accuracy alone can't tell memorization apart from generalization — a tree can always reach 100% on data it's already seen, and α=0\alpha = 0 inherits that blind spot exactly. But charge a per-leaf toll and raise it: at some α\alpha, the leaves that only existed to rescue noise stop paying for themselves, and the objective's own minimum shifts from the overgrown tree to the right-sized one — the same tree a validation set would have picked, found without ever looking at one.