AI Hints
Home›Machine Learning Tutorial›Gradient Boosting
Machine Learning · Lesson 37 of 85

Gradient Boosting

Learning from mistakes.

⏱ 2 min read▶ Video at 1:20:33🎓 Free
Watch this lesson in the Machine Learning courseWatch on YouTube ↗Full Machine Learning course

A random forest is a crowd working separately. Boosting is a team working in sequence. The first model makes a rough guess. The second studies only the mistakes of the first. The third fixes what is left. Each one is weak by itself, but together they become the most successful algorithm ever made for tables of data.

Gradient Boosting
From the video: Gradient Boosting
  • Forest: a crowd working apart
  • Boosting: a team in sequence
  • The champion for tabular data

Fixing the mistakes

Watch this. We start with one flat guess, the average. It fits poorly, and the gaps between the line and the dots are the errors. Now, here is the key move. We train a small tree, not on the prices, but on those errors. We add a little of it to our prediction, and the line bends closer. Then we measure the new errors, and repeat. Each tree shrinks what is left. See the remaining error falling on the right. The word gradient here means the same thing it did in gradient descent. We are walking downhill, but with trees as our steps.

Boosting by hand

This idea is so simple that we can code it in a few lines. Start by predicting the mean. Then loop. Find the residual, which is whatever we have got wrong so far. Fit a tiny tree to that residual. Add a small fraction of it to our prediction. That fraction is the learning rate, and it stops any one tree from having too much influence. Run it. By round fifty, the error has dropped dramatically. You have just written the core of an algorithm that wins competitions.

boost_by_hand.pypython
import numpy as np
from sklearn.tree import DecisionTreeRegressor

rng = np.random.default_rng(0)
x = np.sort(rng.uniform(0, 6, 200)).reshape(-1, 1)
y = np.sin(x).ravel() + rng.normal(0, 0.15, 200)

prediction = np.full(200, y.mean())
learning_rate = 0.3

for round_ in range(1, 51):
    residual = y - prediction
    tree = DecisionTreeRegressor(max_depth=2).fit(x, residual)
    prediction += learning_rate * tree.predict(x)
    if round_ in (1, 5, 10, 50):
        print(f"round {round_:>2}  error {((y - prediction) ** 2).mean():.4f}")
Output
round  1  error 0.2787
round  5  error 0.0539
round 10  error 0.0227
round 50  error 0.0115

The real thing

Scikit learn's fast version is called hist gradient boosting. It groups values into bins, so it runs quickly, even on millions of rows. It handles missing values with no extra work, and it needs no scaling. We train five hundred trees. Run it. We now have the lowest error of the course so far, and an R squared around point eight four. Your linear model, in the same units, was stuck at about point six. This is the moment you walk into your boss's office with a big smile.

boosting.pypython
from sklearn.datasets import fetch_california_housing
from sklearn.ensemble import HistGradientBoostingRegressor
from sklearn.metrics import mean_absolute_error
from sklearn.model_selection import train_test_split

X, y = fetch_california_housing(return_X_y=True)
X_tr, X_te, y_tr, y_te = train_test_split(X, y, random_state=0)

model = HistGradientBoostingRegressor(max_iter=500, learning_rate=0.08,
                                      random_state=0).fit(X_tr, y_tr)

print(f"MAE ${mean_absolute_error(y_te, model.predict(X_te)) * 1e5:,.0f}")
print(f"R2  {model.score(X_te, y_te):.3f}")
Output
MAE $29,947
R2  0.845

Summary

Boosting builds a strong model from weak ones, each correcting the last. That's why it dominates business data to this day. But boosting has a dark side. Give it too many trees, and it will overfit. So how many should you use? Luckily, the model can tell you.

Key takeaways
  • Each tree fits the last errors
  • Learning rate scales each step
  • Excellent for tables of data
Next up: Tuning Boosting — early stopping and the key settings