CadetX
CX Learn | Complete Machine Learning Guide
Scikit-Learn · Python
CadetX logo CadetX CX Learn
ML-101 · Module 8 Intermediate about 40 minutes 11 Lessons Prereq: Modules 1 to 7

Random Forest & Gradient Boosting

One decision tree is easy to understand but often not very accurate. Hundreds of trees working together are a different story. In this module you'll learn the two most successful ways to combine trees, the methods behind a huge share of real-world machine learning on spreadsheet-style data.

  • Level: Intermediate
  • Time: about 40 minutes
  • Needs: Modules 1 to 7

By the end of this module you will be able to

  • Explain ensemble learning and the "wisdom of the crowd"
  • Describe bagging and bootstrap sampling
  • Explain how a random forest makes its trees different from each other
  • Explain how gradient boosting learns from its own mistakes
  • Compare bagging and boosting, and choose between them
  • Tune the key hyperparameters of each method
  • Train and compare ensembles against simpler models in scikit-learn

8.1Ensemble learning: the wisdom of the crowd

In 1906, the scientist Francis Galton visited a country fair where around 800 people paid to guess the weight of an ox. Individual guesses were all over the place. But when Galton averaged them, the crowd's answer was within about 1% of the true weight, closer than almost any single expert.

This is the idea behind ensemble learning: combine many models, and the group is usually more accurate than any one of them.

Ensembles in one sentence

An ensemble trains many models and combines their predictions, so that their individual mistakes cancel out.

There's one important condition: the models must make different mistakes. If every member of the crowd copied the same person's guess, averaging them would change nothing. The two methods in this module make models different in two different ways:

MethodHow the trees are builtHow they're combined
Random forest (bagging)Side by side, all at once, each on a different random sample of the dataThey vote (or average)
Gradient boostingOne after another, each one fixing the mistakes of the ones beforeThey're added together

8.2Why combine trees?

In Module 7, you saw two problems with a single decision tree:

  • It overfits easily. Deep trees memorise the training data.
  • It's unstable. Change a few rows of data and you can get a completely different tree.

In Module 5 terms, a deep tree has high variance: its predictions jump around depending on exactly which data it saw. The good news is that high variance is exactly what averaging fixes. One wobbly tree is unreliable; the average of 300 wobbly trees is remarkably steady.

Like asking for directions

Ask one stranger for directions and they might be wrong. Ask ten strangers and go with the most common answer, and you're far more likely to get there, as long as they didn't all hear it from the same person.

8.3Bagging and bootstrap samples

How do you train many different trees from one dataset? Bagging (short for bootstrap aggregating) gives each tree its own random version of the data.

Each version is a bootstrap sample: a random sample of the same size as the original, picked with replacement. That means after picking a row, you "put it back", so it can be picked again.

Bagging. Three random samples are drawn from the original six customers, with some customers repeated and some left out. Each sample trains its own tree, and the trees vote on the final answer.Original dataABCDEFRandom sample 1AACDFFTree 1: LeaveRandom sample 2BCCDEFTree 2: StayRandom sample 3ABBDEETree 3: LeaveNotice in sample 1:A and F appear twice.B and E are left out.Every sample is different.Majority vote: Leave (2 of 3)
Figure 1. Three bootstrap samples from six customers (amber left, blue stayed). Some customers appear twice, some not at all. Each sample trains its own tree, and the trees vote.

On average, each bootstrap sample contains about 63% of the original rows, with the rest being repeats. The rows a tree didn't see are called its out-of-bag (OOB) rows. They make a handy free test set: each row can be scored using only the trees that never saw it. This gives the OOB score, a built-in estimate of how well the forest will do on new data.

8.4Random forest

A random forest is bagging with decision trees, plus one extra twist. At every split, each tree is only allowed to look at a random handful of features, not all of them.

Why? Imagine one feature, like "months with us", is very strong. Without the twist, almost every tree would ask about it first, and the trees would end up looking similar and making similar mistakes. Forcing each split to choose from a random subset makes the trees more different from each other, so their mistakes cancel out better.

StepWhat happens
1Draw a bootstrap sample of the training data
2Grow a tree on it. At each split, only consider a random subset of features
3Repeat steps 1 and 2 many times (often 100 to 500 trees)
4To predict: every tree votes, and the majority wins. The share of votes is the probability

Watch this happen with a real forest trained on 4,000 broadband customers.

Try it: grow the forest

Leave: Stay:

Notice two things. First, the score climbs quickly for the first 20 or so trees, then levels off. Adding more trees never makes a random forest overfit; it just stops helping and makes it slower. Second, with only a few trees, the vote on a single customer swings wildly. With hundreds, it settles on a stable answer. (This lab uses fully grown trees. In lesson 8.9, limiting each leaf to at least 10 customers pushes the score even higher, to 0.857.)

8.5Gradient boosting: learning from mistakes

Boosting takes the opposite approach. Instead of growing many big trees independently, it grows many small trees one after another. Each new tree focuses on what the model so far is still getting wrong.

Like revising for an exam

After a practice paper, a smart student doesn't revise everything again. They look at the questions they got wrong and focus on those. Then they take another practice paper, check the new mistakes, and repeat. Each round fixes a bit more. That's boosting.

How gradient boosting works

Let's use the ten Newcastle house prices from Module 3.

  1. Start simple: predict the average price for every house: £201.1k.
  2. Measure the mistakes: work out each house's residual (actual − predicted), just like in Module 3.
  3. Train a small tree to predict those mistakes, not the prices.
  4. Add a small part of that tree's answer to the current prediction.
  5. Repeat from step 2, with a new tree each time.
Gradient boosting after 1, 3 and 40 trees. The first prediction is a single rough step. Each new tree corrects the remaining errors, until the prediction closely follows the data.After 1 treeAverage error: £32.6kAfter 3 treesAverage error: £20.7kAfter 40 treesAverage error: £0.8k
Figure 2. Gradient boosting on the house prices, using tiny one-question trees. After 1 tree, the prediction is a rough step. After 3, it's getting the shape. After 40, it follows the data closely. The red dashed lines are the remaining errors, which shrink every round.
Round50 m² house (sold £130k)135 m² house (sold £290k)
Start (the average)£201.1k£201.1k
After 1 tree£190.2k£217.5k
After 3 trees£176.6k£242.3k
After 10 trees£145.2k£275.8k
After 40 trees£130.6k£289.5k

Each round moves every prediction a little closer to the truth. The word "gradient" comes from the same idea as gradient descent in Module 3: each step heads "downhill" towards a smaller error.

The learning rate

In step 4, we only add a small part of each new tree's answer. That fraction is the learning rate (0.3 in Figure 2). A small learning rate means small, careful steps: you need more trees, but the final model usually generalises better. It's like turning a steering wheel gently rather than yanking it.

Boosting can overfit

Unlike a random forest, adding too many boosting trees can overfit, because each new tree chases smaller and smaller errors, eventually including noise. After 40 trees, the model in Figure 2 is almost perfect on its 10 training houses, which is a warning sign. Use cross-validation, or early stopping (stop adding trees when the validation score stops improving).

8.6Bagging vs boosting

Random forest (bagging)Gradient boosting
How trees are builtIndependently, in parallelOne after another, in sequence
Size of each treeBig, deep treesSmall, shallow trees (often 2 to 6 levels)
Main thing it fixesVariance (instability, overfitting)Bias (underfitting), by steadily improving
More treesNever hurts, just slowerCan overfit; use early stopping
Tuning effortLow: works well with default settingsHigher: learning rate, depth and number of trees interact
AccuracyVery goodOften the best, once tuned
Training speedFast; trees can be built at the same timeSlower; each tree must wait for the last

A practical rule of thumb

Start with a random forest: it's hard to get badly wrong and gives a strong baseline in minutes. If you need the last few percent of accuracy and have time to tune, try gradient boosting.

8.7The key hyperparameters

Random forest

SettingWhat it doesGood starting point
n_estimatorsNumber of trees200 to 500
max_featuresHow many features each split can choose from. Smaller = more different trees"sqrt" (the default for classification)
max_depthMaximum depth of each treeNone (fully grown), or limit if the data is noisy
min_samples_leafMinimum examples in each leaf1 to 20
oob_scoreCalculate the free out-of-bag scoreTrue

Gradient boosting

SettingWhat it doesGood starting point
n_estimatorsNumber of trees (rounds)100 to 1,000, with early stopping
learning_rateHow big each step is. Smaller = more trees needed, but often better results0.05 to 0.1
max_depthDepth of each small tree2 to 5
subsampleTrain each tree on a random share of rows, adding some "bagging" randomness0.8

Remember: learning_rate and n_estimators work together. Halve the learning rate and you'll roughly need to double the number of trees.

8.8XGBoost, LightGBM and CatBoost

scikit-learn has its own boosting models, but in industry you'll often hear three names. They're all gradient boosting, with clever engineering that makes them faster and more accurate on big datasets.

LibraryKnown for
XGBoostThe library that made boosting famous by winning many data science competitions in the mid-2010s. Fast and reliable, with built-in regularisation
LightGBMBuilt by Microsoft. Very fast on large datasets with many rows
CatBoostBuilt by Yandex. Handles text categories (like "city") automatically, with less need for one-hot encoding
HistGradientBoostingscikit-learn's own fast version, inspired by LightGBM. A great choice when you don't want an extra library

They all follow the same .fit() and .predict() pattern you already know, so switching between them is easy. For data in rows and columns (like spreadsheets and database tables), a well-tuned gradient boosting model is very often the strongest option, frequently beating neural networks.

8.9Comparing models in Python

In Module 4, our churn data was made from logistic regression's own formula, which gave it an unfair advantage. Real customer behaviour is messier: it has thresholds ("more than 3 calls"), special cases ("new customers are risky") and combinations ("an expensive bill and no contract"). So here we use 5,000 customers with more realistic, tangled patterns, and let four models compete.

compare_models.py
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.metrics import accuracy_score, roc_auc_score

# 1. 5,000 customers with more realistic, tangled patterns
rng = np.random.default_rng(8)
n = 5000
df = pd.DataFrame({
    "support_calls":    rng.poisson(3, n),
    "months":           rng.integers(1, 72, n),
    "monthly_bill":     rng.integers(20, 90, n),
    "monthly_contract": rng.integers(0, 2, n),
    "age":              rng.integers(18, 80, n),
})
z = (-2.2
     + 1.4 * (df["support_calls"] >= 4) + 1.0 * (df["support_calls"] >= 7)
     + 1.8 * (df["months"] < 6) - 1.2 * (df["months"] > 36)
     + 2.0 * df["monthly_contract"] * (df["monthly_bill"] > 60)
     + 0.9 * ((df["age"] < 25) | (df["age"] > 70))
     - 0.6 * df["monthly_contract"] * (df["months"] > 24))
df["left"] = (rng.random(n) < 1 / (1 + np.exp(-z))).astype(int)
print(f"Customers who left: {df['left'].mean():.0%}\n")

X = df.drop(columns="left")
y = df["left"]
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y)

# 2. Four models to compare
models = {
    "Logistic regression": Pipeline([("scale", StandardScaler()),
                                     ("clf", LogisticRegression())]),
    "Single tree":         DecisionTreeClassifier(max_depth=4, random_state=42),
    "Random forest":       RandomForestClassifier(
                               n_estimators=300, min_samples_leaf=10,
                               oob_score=True, random_state=42),
    "Gradient boosting":   GradientBoostingClassifier(
                               n_estimators=150, learning_rate=0.05,
                               max_depth=2, random_state=42),
}

# 3. Train each one and score it on the test set
for name, model in models.items():
    model.fit(X_train, y_train)
    acc = accuracy_score(y_test, model.predict(X_test))
    auc = roc_auc_score(y_test, model.predict_proba(X_test)[:, 1])
    print(f"{name:20} accuracy={acc:.3f}  ROC AUC={auc:.3f}")

# 4. Random forest extras
rf = models["Random forest"]
print("\nOut-of-bag score:", round(rf.oob_score_, 3))
for col, imp in sorted(zip(X.columns, rf.feature_importances_), key=lambda t: -t[1]):
    print(f"{col:17} {imp:.2f}")
Output
Customers who left: 23%

Logistic regression  accuracy=0.816  ROC AUC=0.811
Single tree          accuracy=0.816  ROC AUC=0.817
Random forest        accuracy=0.829  ROC AUC=0.857
Gradient boosting    accuracy=0.836  ROC AUC=0.860

Out-of-bag score: 0.814
months            0.38
monthly_bill      0.20
support_calls     0.18
age               0.14
monthly_contract  0.09

What the output tells us

  • Accuracy barely separates them (81.6% to 83.6%). Remember the accuracy trap from Modules 4 and 5: 77% of customers stay, so "always stay" would already score 77%.
  • ROC AUC tells the real story. Logistic regression (0.811) and the single tree (0.817) are close. The random forest (0.857) and gradient boosting (0.860) are clearly better at ranking which customers are most likely to leave.
  • Why do the ensembles win? Logistic regression can only draw one straight boundary, so it can't capture "bill over £60 and no contract". A single tree can, but it's unstable. Hundreds of trees capture the tangled patterns and stay stable.
  • The OOB score (81.4%) is close to the real test accuracy (82.9%), which shows it's a useful free estimate when you don't want to hold back a separate test set.
  • Feature importance now ranks months with us first. That makes sense: the data has a sharp "new customer" effect and a "loyal customer" effect, which trees capture well.

No free lunch

There's a famous idea in machine learning called the "no free lunch" theorem: no single algorithm is best for every problem. On simple, straight-line data (Module 4), logistic regression matched the ensembles. On tangled real-world data, the ensembles pull ahead. That's why data scientists always compare several models, starting with a simple baseline.

8.10Strengths, weaknesses and real-world uses

StrengthsWeaknesses
Top accuracy on table-shaped dataHarder to explain: you can't draw 300 trees on one slide
No scaling needed (they're made of trees)Slower to train and predict than a single model
Capture curves, thresholds and combinations automaticallyLarger models take more memory
Random forests are hard to break: great with default settingsBoosting needs careful tuning to avoid overfitting
Give feature importanceCan't predict beyond the training range, like single trees
IndustryExample
Banking and insuranceCredit scoring, card fraud detection, pricing insurance policies
Retail and e-commerceDemand forecasting, predicting which customers will buy or leave
HealthcarePredicting hospital readmissions and patient risk scores
EnergyForecasting electricity demand from weather and time
Search and advertisingRanking search results and predicting ad clicks

Explaining a "black box"

When a manager asks "why did the model flag this customer?", a popular tool called SHAP can break down any single prediction into how much each feature pushed it up or down. It's widely used with random forests and boosting to make them explainable.

SummaryKey takeaways

  • Ensembles combine many models so their mistakes cancel out, like the wisdom of the crowd.
  • Bagging trains each model on a bootstrap sample (random rows, with replacement) and lets them vote.
  • A random forest is bagged decision trees, plus a random subset of features at each split to make the trees more different.
  • Adding trees to a random forest never causes overfitting; the OOB score is a free estimate of test performance.
  • Gradient boosting builds small trees one after another, each one predicting the remaining errors.
  • The learning rate controls step size; boosting can overfit, so use early stopping or cross-validation.
  • Random forest is a great first choice; tuned boosting (XGBoost, LightGBM, CatBoost) is often the most accurate on table data.
  • No free lunch: always compare against a simple baseline.

Check your understanding

Your machine learning roadmap

  1. 01
    Introduction to Machine LearningWhat ML is and how it works
  2. 02
    Preparing Data for Machine LearningFeatures, encoding, scaling, train/test split
  3. 03
    Linear RegressionPredicting numbers
  4. 04
    Logistic RegressionPredicting yes or no
  5. 05
    Evaluating ModelsAccuracy, precision, recall, overfitting, cross-validation
  6. 06
    K-Nearest NeighboursLearning from similar examples
  7. 07
    Decision TreesFlowcharts that learn
  8. 08
    Random Forest and Gradient BoostingYou are here
  9. 09
    Support Vector MachinesFinding the best boundary
  10. 10
    Naive BayesProbability-based classification
  11. 11
    Clustering with K-MeansFinding groups without labels
  12. 12
    Dimensionality Reduction with PCASimplifying big datasets
  13. 13
    Capstone ProjectBuild and present a full ML project