Tree-Based Algorithms

Lesson 4

Boosting

Build one strong model from many weak ones, each correcting the last

In the last lesson, random forests took a crowd of deep, low-bias, high-variance trees, grew each on a different bootstrap sample, and averaged them to cancel variance. Every tree was trained independently and in parallel. Boosting turns that idea inside out.

Boosting trains learners one at a time, and each new learner is trained to fix the errors the ensemble has made so far. The learners are deliberately weak: shallow trees, often a single split ("stumps"). No single one is good. But when you add them up, biased and slow at first, the committee sharpens into a model that is often the strongest thing you can run on tabular data.

This lesson builds the two boosting algorithms every engineer is expected to know. AdaBoost reweights the data toward the points it keeps getting wrong. Gradient boosting fits each new learner to the leftover error directly, which turns out to be gradient descent, run not on the weights of one model but in the space of functions itself.


The one idea: sequential, focused on mistakes

Here is the whole of boosting in one loop:

1

Start with a weak model. It is wrong about many points.

2

Look at what it got wrong. Focus the next weak model on exactly those mistakes.

3

Add the new model to the ensemble with a weight that reflects how good it is.

4

Repeat. The ensemble prediction is the (weighted) sum of all the weak models.

The two algorithms differ only in how they define "the mistakes" and how they focus the next learner on them. AdaBoost puts more weight on misclassified points. Gradient boosting fits the next learner to the residual error as a regression target. Everything else, the sequential loop and the additive final model, is shared.


Bagging vs boosting: variance vs bias

Both bagging and boosting are ensembles of trees, but they attack opposite halves of the error. Recall the decomposition from the bias-variance lesson:

E[(yf^)2]=Bias2[f^]systematic error+Var[f^]sensitivity to data+σ2noise\mathbb{E}\bigl[(y - \hat{f})^2\bigr] = \underbrace{\text{Bias}^2[\hat{f}]}_{\text{systematic error}} + \underbrace{\text{Var}[\hat{f}]}_{\text{sensitivity to data}} + \underbrace{\sigma^2}_{\text{noise}}
Bagging (Random Forest)Boosting (AdaBoost / GBM)
How trees are builtIn parallel, independentlySequentially, each depends on the last
Base learnerDeep tree (low bias, high variance)Weak / shallow tree (high bias, low variance)
Combining ruleAverage / plain majority voteWeighted sum by learner quality
Mainly reducesVarianceBias
Main failure modeStays biased if base trees are too shallowOverfits if run too long (chases noise)

The logic is symmetric. Bagging starts from learners that are already accurate but jittery (a deep tree changes a lot when the data shifts), and averaging many of them cancels that jitter, so it drives variance down. Boosting starts from learners that are stable but too simple to capture the pattern (a stump is nearly the same on any sample, but very wrong), and stacking many of them, each aimed at the current error, drives bias down.


AdaBoost: reweight the mistakes, then vote by confidence

AdaBoost (Adaptive Boosting) is the original boosting algorithm that made the idea practical. It works on classification, with labels written as yi{1,+1}y_i \in \{-1, +1\} so that "correct" means the prediction and the label have the same sign.

Every training point carries a weight wiw_i, its say in the loss. All points start equal:

wi=1nfor i=1,,nw_i = \frac{1}{n} \quad \text{for } i = 1, \dots, n

Each round t does three things.

1. Train a weak learner on the weighted data

Fit a stump hth_t that minimises the weighted error, so points with big weights matter most. Its weighted error rate is the total weight it gets wrong:

εt=i=1nwi1[ht(xi)yi]\varepsilon_t = \sum_{i=1}^{n} w_i \cdot \mathbf{1}\bigl[\,h_t(x_i) \neq y_i\,\bigr]

Since the weights sum to 1, εt\varepsilon_t is between 0 and 1. A useless coin-flip learner sits at εt=0.5\varepsilon_t = 0.5.

2. Score the learner: how much should it count?

Give the learner a weight αt\alpha_t in the final vote based on how much better than chance it is:

αt=12ln ⁣(1εtεt)\alpha_t = \frac{1}{2} \ln\!\left( \frac{1 - \varepsilon_t}{\varepsilon_t} \right)

Read this formula. It is the heart of AdaBoost:

  • A great learner (εt0\varepsilon_t \to 0) gets αt+\alpha_t \to +\infty: it dominates the vote.
  • A coin flip (εt=0.5\varepsilon_t = 0.5) gets αt=0\alpha_t = 0: it is ignored, because ln(1)=0\ln(1) = 0.
  • A learner worse than chance (εt>0.5\varepsilon_t > 0.5) gets αt<0\alpha_t < 0: AdaBoost flips it and uses it backwards.

3. Reweight the data toward what this learner missed

Multiply up the weight of every point the learner got wrong, so the next round is forced to attend to them, then renormalise so the weights are a distribution again:

wiwiexp ⁣(αt1[ht(xi)yi]),wiwijwjw_i \leftarrow w_i \cdot \exp\!\bigl(\alpha_t \cdot \mathbf{1}[\,h_t(x_i) \neq y_i\,]\bigr), \qquad w_i \leftarrow \frac{w_i}{\sum_j w_j}

Correctly classified points multiply by e0=1e^0 = 1 and are left alone (they shrink only relative to the others after renormalising). Misclassified points multiply by eαt>1e^{\alpha_t} > 1 and grow. The bigger αt\alpha_t is, the harder the next learner is pushed onto today's mistakes.

The final model: a weighted majority vote

After T rounds, classify a new point by the sign of the confidence-weighted sum of the weak learners:

H(x)=sign ⁣(t=1Tαtht(x))H(x) = \operatorname{sign}\!\left( \sum_{t=1}^{T} \alpha_t \, h_t(x) \right)

Each stump votes ±1\pm 1, and its vote is scaled by how trustworthy it earned the right to be. Watch the whole loop run. Each round, the misclassified points swell, the stump line shifts to chase them, and the ensemble training error falls.

🪜 AdaBoost — weak learners, one mistake at a time

Each round adds one decision stump (a single axis-aligned split). Misclassified points swell; the weighted vote sharpens the boundary.

class +1class −1current stumpbigger dot = higher weight
Round0 / 15
Ensemble training error
50.0%
stump error
weight α

A stump barely beats a coin flip (error near 50%). Boosting reweights the data toward the points it just missed, fits the next stump on those, and blends them by confidence α. Sum enough weak rules and the committee draws a sharp boundary — bias falls round by round.


Gradient boosting: fit the residuals

AdaBoost's reweighting trick is elegant but specific to classification with that exponential loss. Gradient boosting generalises it to any differentiable loss with one clean idea: instead of reweighting points, fit each new learner directly to the error left over.

Build the model additively. Start from a constant F0F_0 (for squared error, the mean of yy), then add one weak learner at a time:

Fm(x)=Fm1(x)+νhm(x)F_m(x) = F_{m-1}(x) + \nu \, h_m(x)

Here ν\nu (nu) is the learning rate, a small number like 0.1 that shrinks each step. The only question is what hmh_m should learn. The answer: the negative gradient of the loss with respect to the current predictions.

hmLFF=Fm1h_m \approx -\left.\frac{\partial L}{\partial F}\right|_{F = F_{m-1}}

That looks abstract until you plug in squared-error loss L=12(yF)2L = \tfrac{1}{2}(y - F)^2. Its derivative with respect to the prediction FF is:

LF=(yFm1),soLF=yFm1\frac{\partial L}{\partial F} = -(y - F_{m-1}), \qquad \text{so} \qquad -\frac{\partial L}{\partial F} = y - F_{m-1}

The negative gradient is exactly the residual, the part of yy the current model still misses. So for regression with squared loss, gradient boosting is beautifully concrete:

Compute the residuals

ri = yi − Fm−1(xi)

fit a stump to those residuals, add ν × it, repeat.

Watch it happen. The top panel shows the staircase prediction creeping toward the target curve. The bottom panel shows the residuals shrinking, with the next stump (dashed) fitting whatever error is left. Slide the learning rate and see how smaller steps need more rounds but move more carefully.

📉 Gradient Boosting — fit the residuals

Each round fits one stump to what's left over (target − prediction). The staircase creeps toward the curve, stage by stage.

Round 0/12RMSE 0.000
Learning rate ν0.5smaller ν = smaller, safer steps
prediction vs targetresiduals (target − prediction) & next stump
targetensemble predictionnext stump (fit to residuals)residual

The residual is the negative gradient of squared-error loss. Fitting the next stump to it, then adding only ν × its output, nudges the prediction toward the target without overshooting. Repeat and the staircase hugs the curve — small ν needs more rounds but generalises better.

Why this is "gradient descent in function space"

Ordinary gradient descent nudges a parameter vector downhill: wwηL/ww \leftarrow w - \eta \, \partial L / \partial w. Gradient boosting does the same thing, but the object being optimised is the whole function FF, and each step moves FF in the direction of the negative gradient by adding a new learner that points that way. The learning rate ν\nu plays the exact role η\eta plays below: the size of each downhill step.

Loss curve over a single weight w
learning rate η0.060
too slowconvergesovershoots

Same picture, one level up. Below, a ball rolls down a loss surface by repeatedly stepping against the gradient. In gradient boosting, the "ball" is the ensemble's prediction, and each weak learner is one step down that same slope, fitting the residual because the residual is where the slope points.

Learning rate and shrinkage

Why not add each learner at full strength (ν=1\nu = 1)? Because a smaller ν\nu (shrinkage) makes the model take many small, cautious steps instead of a few greedy ones. Each step corrects less, so no single stump can overreact to noise, and the ensemble generalises better. The trade-off is fixed:

small ν    more rounds M needed, but better generalisation\text{small } \nu \;\Longrightarrow\; \text{more rounds } M \text{ needed, but better generalisation}

In practice you set a small ν\nu (0.05 to 0.1), then use as many rounds as a validation set will let you before it starts overfitting. Learning rate and number of rounds are tuned together.


Code: run both, watch the error fall

Time to make it real. First, fit both boosters on a real dataset and compare their accuracy to a single stump. AdaBoostClassifier and GradientBoostingClassifier both live in scikit-learn, which auto-loads in the Pyodide worker.

Python
First run loads the Python runtime (~10 MB) — takes ~5–10 seconds. Subsequent runs are instant.

Now the payoff plot. Every booster can replay its prediction after each round with staged_predict (and gradient boosting also exposes staged_decision_function). Plot the test error round by round and you can literally watch bias fall as learners accumulate, and, if you push it, watch overfitting begin.

Python
First run loads the Python runtime (~10 MB) — takes ~5–10 seconds. Subsequent runs are instant.

Finally, gradient boosting stripped to its skeleton: no scikit-learn, just NumPy fitting stumps to residuals. This is the entire algorithm for squared-error regression in about fifteen lines. Run it and watch the training error drop each round as the residuals shrink.

Python
First run loads the Python runtime (~10 MB) — takes ~5–10 seconds. Subsequent runs are instant.

Push these. In the first playground, raise noise on the moons and watch every model's accuracy sag toward the noise floor. In the last one, set nu = 1.0 and see it lurch, or nu = 0.05 and watch it crawl but converge more smoothly. Break it, then fix it.


Recap

Check your understanding

1 / 5

In AdaBoost, a weak learner has weighted error εₜ = 0.5. What vote weight αₜ does it receive, and what does that mean?


Interview readiness

Q1ConceptualGoogleAmazonMeta

Explain the difference between bagging and boosting. When would you reach for each?

Q2MathAmazonMicrosoft

Why is gradient boosting called 'gradient descent in function space', and what does the learning rate do?

Test your understanding

Prof is ready

Prof will ask you questions about Boosting: AdaBoost and gradient boosting — not explain it. You'll be surprised what you don't know until you have to say it.

Finished this lesson?

Read through the lesson first (0/20s).