Random Forests, annotated
How to read this page
- Any dotted word explains itself when you hover it, tab to it, or tap it, and so does every symbol in every equation.
- The diagrams are live: hover or tap a part to read what it does. Several charts respond to you: one lets you watch a vote settle as trees are added, another shows how the paper's error bound moves with strength and correlation.
Each idea climbs the same ladder: an everyday picture, a tiny example you can check by hand, a diagram, the math, and why it matters today. One small example runs through the page: a forest of ten trees voting on whether four emails are spam. The trees and boosting lesson builds a decision tree and a random forest from scratch in NumPy.
Abstract · original
“The generalization error of a forest of tree classifiers depends on the strength of the individual trees in the forest and the correlation between them.”Breiman (2001), Abstract
Everyday picture
Ask one doctor for a diagnosis and you get one opinion, with that doctor's blind spots. Ask a hundred doctors who each trained at a different hospital and each looked at a different handful of test results, and take the majority: the blind spots rarely line up, so the majority is right more often than almost any single doctor. Two things decide how good the majority is: how good each doctor is (the paper calls it strength) and how often they make the same mistake (correlation). This paper builds that committee out of decision trees.
What the paper claims
- A random forest is any collection of trees, each grown with its own independent dose of randomness, that vote. Adding trees never makes it overfit: its error settles to a limit (Theorem 1.2).
- The forest's error is bounded by the trees' average correlation divided by the square of their strength (Theorem 2.3), so good randomness lowers correlation without costing much strength.
- Choosing a random handful of inputs at every split (and growing each tree on a bootstrap sample) gives accuracy that compares favourably with Adaboost, is more robust to wrong labels, and is faster.
- The rows each tree never saw give free, built-in estimates of the error, the strength, the correlation and the importance of each input.
Why it matters today
Random forests are still the standard first model on a new table of data: they need almost no tuning, cannot be ruined by adding trees, and report their own validation score. The idea of shuffling one column and measuring the damage, introduced in §10, became permutation importance, one of the most used tools for asking what any model relies on.
1 Random forests · original
“After a large number of trees is generated, they vote for the most popular class. We call these procedures random forests.”Breiman (2001), §1.1
Everyday picture
Before this paper, several people had found ways to grow many different trees from one dataset and let them vote. Bagging gives each tree its own resample of the rows. Random split selection picks each split at random from the best few. The random subspace method gives each tree a random subset of the inputs. Breiman notices they share one skeleton: tree number k is grown from the training data plus a fresh random “recipe card” Θk, drawn independently of all the other cards and from the same deck. Any procedure of that shape is a random forest.
Tiny example
In bagging, the recipe card is a list of counts: throw N darts at N boxes, one box per training row, and count how many darts land in each box. With N = 5 emails, one card might read (2, 0, 1, 1, 1): email 1 is used twice, email 2 not at all. Tree 1 is grown on that resample. Tree 2 gets a new card, say (0, 2, 1, 0, 2), and so on. Each tree then votes, and the forest answers with the class that gets the most votes.
Hover or tap a part. Start with the training set at the top.
Reading it: read from the top down. The training set is resampled K times with replacement (the pink boxes), and each resample grows one full-depth, unpruned tree (the blue boxes). Inside every tree, each node (the highlighted circle in tree 1) may only choose its question from F inputs picked at random for that node. Nothing passes between trees, so they can be grown in any order or on different machines. The trees' answers meet at the vote. The dashed wire is the paper's second idea: for each training row, a vote taken only among the trees whose resample left that row out gives an honest score of the forest without a separate test set.
Why it matters
Naming the common skeleton is what made the theory possible. Because the recipe cards are independent and identically distributed, the law of large numbers applies to the vote, which is the next section's first result. The trees and boosting lesson implements the skeleton as RandomForest, which hands each tree its own bootstrap_sample and its own seed for choosing features.
2 Characterizing the accuracy of random forests · original
Everyday picture
For a single email, think of a referendum. What matters is not only whether the right side won, but by how much: winning 90 to 10 is safe, winning 51 to 49 is one bad day from losing. The paper measures every prediction by that winning lead, the margin, and builds all of its theory on it.
2.1 Random forests converge · original
“This result explains why random forests do not overfit as more trees are added, but produce a limiting value of the generalization error.”Breiman (2001), §2.1
Tiny example
Ten trees vote on email A, which really is spam. Seven vote spam and three vote not spam. The average vote for the right class is 0.7, the biggest average vote for any wrong class is 0.3, and the margin is 0.7 − 0.3 = 0.4: positive, so the forest gets email A right. Emails B, C and D get margins 0.8, −0.2 and 0.6. Only C has a negative margin, so this forest misclassifies one email in four.
In words: “the margin at an example is the share of trees that vote for its true class, minus the share that vote for the most popular wrong class.”
With the numbers: email A: avk I(hk = spam) = 7/10 = 0.7; the only wrong class, not spam, gets 3/10 = 0.3; mg = 0.7 − 0.3 = 0.4.
In Python:
# the ten trees' votes on email A, whose true class Y is spam
votes = ["spam"] * 7 + ["not"] * 3
Y = "spam"
# av_k I(h_k(X) = j): the share of trees voting for class j
def av(j):
return sum(1 for h_k in votes if h_k == j) / len(votes)
av(Y) # → 0.7
# max over the wrong classes j ≠ Y
wrong = max(av(j) for j in ["not"])
wrong # → 0.3
round(av(Y) - wrong, 2) # → 0.4
The forest's generalization error is the chance that a fresh example lands with a negative margin:
In words: “the error is the probability, over all the examples the world could send, that the right class loses the vote.”
With the numbers: margins 0.4, 0.8, −0.2 and 0.6: one of four is below zero, so the estimate of PE* is 1/4 = 0.25.
In Python:
# margins for emails A, B, C, D
mg = [0.4, 0.8, -0.2, 0.6]
# P(mg < 0), estimated by the share of negative margins
sum(1 for m in mg if m < 0) / len(mg) # → 0.25
Theorem 1.2: the vote settles
Each tree is a random draw, because its recipe card Θ is random. As trees are added, the share of trees voting for each class at a given email is an average of independent draws, so by the law of large numbers it settles on a fixed number: the probability PΘ that a randomly grown tree votes for that class. The error therefore settles too. More trees move the forest towards its limit; they cannot push it past it into overfitting.
Hover or tap the chart to read the margin after any number of trees.
Simulated for this page with a fixed random seed: each tree's vote is an independent coin flip with the chosen chance. No data from the paper.
Reading it: the horizontal axis is the number of trees that have voted on one email (log scale), and the solid line is the margin after that many votes. The dashed line is the limit the theorem promises, 2PΘ − 1 for two classes. The first few trees swing the margin wildly (one tree gives +1 or −1), but by a few hundred trees the line hugs its limit. Drag the slider below 0.5: the limit drops below zero and the forest settles on the wrong answer for this email, however many trees you add. More trees remove the luck of the draw; they cannot fix trees that are wrong more often than right.
Why it matters
This is why the number of trees is the one setting of a forest that needs no tuning: pick “enough”, and past that point only time is spent. The lesson measures the same plateau with forest_curve. Contrast gradient boosting, where adding rounds does overfit (see the trees and boosting lesson and the gradient boosting machine companion).
2.2 Strength and correlation · original
“Although the bound is likely to be loose, it fulfills the same suggestive function for random forests as VC-type bounds do for other types of classifiers.”Breiman (2001), §2.2
Everyday picture
A committee is good when its members are individually good (strong) and do not all share the same blind spot (uncorrelated). The paper turns that sentence into an inequality.
Tiny example
In the limit of many trees, the margin at an example uses probabilities instead of vote shares; call it mr. The forest's strength s is the average margin over all examples. For the four emails, the margins 0.4, 0.8, −0.2 and 0.6 average to s = 0.4. Their variance (how much they spread around 0.4) is (0 + 0.16 + 0.36 + 0.04) / 4 = 0.14.
In words: “the margin of the whole forest at an example is the probability that a random tree votes for the right class, minus the probability of the most popular wrong class; the strength is that margin averaged over every example.”
With the numbers: for two classes the wrong class gets whatever the right one does not, so mr = P − (1 − P) = 2P − 1. With P = 0.7 for email A, mr = 0.4. Averaging the four margins, s = (0.4 + 0.8 − 0.2 + 0.6) / 4 = 0.4.
In Python:
# two classes: mr = P_Θ(right) − P_Θ(wrong) = 2P − 1
P = 0.7
round(P - (1 - P), 2) # → 0.4
# s = E_{X,Y} mr: the average margin over the four emails
mr = [0.4, 0.8, -0.2, 0.6]
s = sum(mr) / len(mr)
round(s, 2) # → 0.4
If the average margin is comfortably positive and the margins do not spread much, few of them can fall below zero. Chebyshev's inequality makes that exact:
In words: “the error is at most the spread of the margins divided by the square of their average.”
With the numbers: 0.14 / 0.42 = 0.14 / 0.16 = 0.875. The true share of negative margins is 0.25, well under the bound, as it must be.
In Python:
mr = [0.4, 0.8, -0.2, 0.6]
s = sum(mr) / len(mr)
# var(mr): the average squared distance from s
var_mr = sum((m - s) ** 2 for m in mr) / len(mr)
round(var_mr, 2) # → 0.14
# the Chebyshev bound var(mr) / s²
round(var_mr / s ** 2, 3) # → 0.875
Theorem 2.3: the bound in strength and correlation
The paper then splits the spread of the margins into two pieces. Each single tree has a “raw margin” at every example: +1 if it votes for the right class, −1 if it votes for the forest's most popular wrong class, 0 otherwise. The spread of the forest's margin is the correlation between two trees' raw margins, times their spreads, averaged over pairs of trees (equations 5 to 7). A little more algebra (equation 8) bounds the spread of one tree's raw margin by 1 − s2. Put together:
In words: “the forest's error is at most the trees' average correlation, times one minus the strength squared, divided by the strength squared: lower correlation or higher strength both push the ceiling down.”
With the numbers: the paper measures real values in §9. With F = 25 random inputs per node it reports s = 0.28 and ρ̄ = 0.065, so the bound is 0.065 × (1 − 0.0784) / 0.0784 = 0.764. The measured test error is 2.8%: the bound is true but very loose. The ratio ρ̄ / s2 (the paper's c/s2) is 0.83, which is what the paper suggests watching instead.
In Python:
# §9, F = 25: strength and mean correlation
s, rho_bar = 0.28, 0.065
# PE* ≤ ρ̄ (1 − s²) / s²
round(rho_bar * (1 - s ** 2) / s ** 2, 3) # → 0.764
# the c/s² ratio: ρ̄ / s²
round(rho_bar / s ** 2, 2) # → 0.83
Hover or tap the curve to read the bound at any strength.
Reading it: the horizontal axis is the strength s, the average margin; the vertical axis is the bound on the error, cut off at 1 because an error cannot exceed 100%. Where the curve sits above 1 the bound says nothing at all. Read it from right to left: a strong forest has a low ceiling, and as strength falls the ceiling climbs steeply, because s appears squared in the denominator. Drag ρ̄ down and the whole curve drops in proportion. That is the design rule of the rest of the paper: inject whatever randomness lowers the correlation between trees, as long as it does not cost too much strength.
Why it matters
The bound itself is rarely tight enough to use, but the trade-off it names became the way everyone thinks about ensembles. The trees and boosting lesson shows the same trade-off in its simplest form, the variance of an average of B correlated predictions, ρσ2 + (1 − ρ)σ2/B, computed by averaged_variance: more trees shrink only the second term, and only lower correlation lowers the floor.
3 Using random features · original
“To improve accuracy, the randomness injected has to minimize the correlation ρ̄ while maintaining strength.”Breiman (2001), §3
Everyday picture
If every doctor on the committee may look at every test result, they all fixate on the same striking one, and they all make the same mistake when it misleads. Hide most results from each doctor at each step of their reasoning, a different random handful each time, and they are forced to reason along different paths. Each doctor gets slightly worse; the committee gets better.
What the paper proposes
Earlier forests (bagging, random split selection, random outputs) did not match Adaboost, the leading method of the time. The forests in this paper choose, at every node, a random small set of inputs (or random combinations of inputs) and split on the best of those only. The paper lists what it gains: accuracy as good as Adaboost and sometimes better, robustness to outliers and noise, speed, internal estimates of error, strength, correlation and importance, and easy parallel training.
Why it matters
Random feature selection at each node is the ingredient that turned bagged trees into random forests. In the lesson's code it is the max_features setting of DecisionTree, which RandomForest sets to the square root of the number of features by default.
3.1 Using out-of-bag estimates to monitor error, strength, and correlation · original
“Therefore, using the out-of-bag error estimate removes the need for a set aside test set.”Breiman (2001), §3.1
Everyday picture
A teacher sets each student a practice exam drawn at random, with repeats, from a bank of questions. Every student misses some questions entirely. To judge how the class would do on unseen questions, ask each question only of the students who never practised it. No questions have to be held back from practice at all.
Tiny example
Five emails, four trees. Each tree's resample is five draws with replacement:
Hover or tap a cell: row = an email, column = a tree. The number is how many times that tree drew that email.
Reading it: each column is one tree's resample, and each column's counts add up to 5 because every tree drew five times. A number is how often that tree saw that email; a dashed grey cell marked “out” is an email the tree never saw. Email 2 is out of bag for trees 1 and 3, so its out-of-bag vote is the vote of those two trees only. Email 5 was drawn by every tree, so it has no out-of-bag vote at all in this tiny forest: with only four trees that happens, and it is one reason the paper grows 100 trees before trusting the estimates.
The math
How many rows does a resample leave out? A given row is missed by one draw with chance 1 − 1/N, and by all N draws with chance (1 − 1/N)N. The paper just says “about one-third”; this is where the third comes from.
In words: “the chance a row never makes it into a resample is the chance of missing it once, multiplied by itself once per draw, which settles near 37% for large datasets.”
With the numbers: N = 5 gives 0.85 = 0.328; N = 1,000 gives 0.3677, already close to 1/e = 0.3679.
In Python:
import math
N = 5
# (1 − 1/N)^N: missed by every one of the N draws
round((1 - 1 / N) ** N, 3) # → 0.328
round((1 - 1 / 1000) ** 1000, 4) # → 0.3677
round(1 / math.e, 4) # → 0.3679
The paper points out a subtlety. Each row's out-of-bag vote uses only about a third of the trees, and fewer trees make a slightly worse forest, so the out-of-bag error tends to overestimate the current forest's error. Run past the point where the error has settled and the estimate becomes unbiased, which, the paper stresses, is more than cross-validation can promise. It cites earlier empirical work (Breiman, 1996) showing the out-of-bag estimate is as accurate as a test set the same size as the training set.
Why it matters
A free validation score is one reason forests are so easy to use: you can compare settings without holding back data. The same out-of-bag rows power the strength and correlation estimates (Appendix II, below) and the variable importance of §10. The lesson computes the out-of-bag fraction with out_of_bag_fraction.
4 Random forests using random input selection · original
“It was surprising that using a single randomly chosen input variable to split on at each node could produce good accuracy.”Breiman (2001), §4
Everyday picture
The simplest random forest, which the paper calls Forest-RI (random inputs): at each node, draw F of the M inputs at random, find the best split among just those (with the usual CART search), grow the tree to full size, and do not prune.
Tiny example
The paper tries two group sizes on every dataset: F = 1, a single random input per node, and F = int(log2 M + 1). The sonar data has M = 60 inputs, so the second choice is 6.
In words: “try about as many inputs per node as it takes binary digits to count the inputs.”
With the numbers: sonar, M = 60: log2 60 = 5.9, plus 1 is 6.9, so F = 6. Zip-code digits, M = 256: F = 9. The §9 data with M = 1,000 inputs: F = 10, as the paper states.
In Python:
import math
# F = int(log2 M + 1) for sonar, zip-code and the §9 data
[int(math.log2(M) + 1) for M in (60, 256, 1000)] # → [6, 9, 10]
For each of 13 smaller datasets, the paper sets aside a random 10%, grows 100 trees with each F, keeps the F with the lower out-of-bag error, and scores it on the held-out 10%; it repeats this 100 times and averages. Adaboost gets 50 trees on the same splits.
| Data set | Adaboost | Forest-RI | F = 1 only | One tree |
|---|---|---|---|---|
| breast cancer | 3.2 | 2.9 | 2.7 | 6.3 |
| diabetes | 26.6 | 24.2 | 24.3 | 33.1 |
| sonar | 15.6 | 15.9 | 18.0 | 31.7 |
| vowel | 4.1 | 3.4 | 3.3 | 30.4 |
| German credit | 23.5 | 24.4 | 26.2 | 33.3 |
| letters | 3.4 | 3.5 | 4.7 | 19.8 |
| zip-code | 6.2 | 6.3 | 7.8 | 20.6 |
| ringnorm | 6.9 | 4.9 | 4.9 | 25.7 |
Reading it: in the bars, grey is Adaboost, blue is Forest-RI and the striped bars are a single tree from the same forest; shorter is better. On most rows the forest and Adaboost are within a point of each other, the forest winning some (vowel, ringnorm) and losing some (German credit). The striking column is the last: each tree alone is far worse (30.4% on vowel against 3.4% for the forest). The forest is not a collection of good trees; it is a good committee of mediocre ones. The paper notes that the average gap between F = 1 and the larger F is under one point: the method is not sensitive to F.
It is also fast
Searching F inputs instead of all M makes each node cheaper. The paper gives the ratio of compute time against growing unpruned trees on all inputs:
In words: “a random-input tree costs roughly F times the log of the number of rows, compared with M for a tree that searches every input.”
With the numbers: zip-code with F = 1: N = 7,291 training rows and M = 256 inputs give log2 7291 / 256 = 12.8 / 256 = 0.050, a 20-fold saving. The paper prints the ratio as .025 and “40 times faster”, twice what its own formula gives for these numbers, so one of the two has slipped. Its measured run is in the same range: 4.0 minutes for 100 Forest-RI trees on a 250 MHz Macintosh, against almost three hours for Adaboost (which combined 100 trees on zip-code).
In Python:
import math
F, N, M = 1, 7291, 256
# F log2 N / M
ratio = F * math.log2(N) / M
round(ratio, 3) # → 0.05
# how many times faster
round(1 / ratio, 1) # → 20.0
Why it matters
“One random input per node already works” is the result that showed how much of a forest's power comes from decorrelation rather than from clever splits. Modern defaults sit between the paper's two choices; the lesson's RandomForest uses the square root of the number of features.
5 Random forests using linear combinations of inputs · original
Everyday picture
With only a handful of inputs, drawing F of them at random does not decorrelate much: the trees keep drawing the same few. Forest-RC (random combinations) invents new inputs instead. At each node it mixes L randomly chosen inputs with random weights, makes F such mixtures, and splits on the best one. There are so many possible mixtures that trees rarely repeat each other.
Tiny example
Take L = 3 inputs, already rescaled to comparable units: age 0.5, income −1.2 and number of links 2.0. Draw three weights uniformly between −1 and 1, say 0.3, −0.8 and 0.5. The new feature for this row is 0.3 × 0.5 + (−0.8) × (−1.2) + 0.5 × 2.0 = 0.15 + 0.96 + 1.0 = 2.11. The node then searches for the best threshold on that feature, exactly as it would on a real column.
In words: “a random feature is a weighted sum of L randomly chosen inputs, with each weight drawn evenly from −1 to 1.” (The paper describes this in prose; the formula is ours.)
With the numbers: 0.3 × 0.5 + (−0.8) × (−1.2) + 0.5 × 2.0 = 2.11.
In Python:
# a_l: the random weights; x_{m_l}: the chosen inputs (age, income, links)
a = [0.3, -0.8, 0.5]
x = [0.5, -1.2, 2.0]
# v = Σ a_l x_{m_l}
round(sum(a_l * x_ml for a_l, x_ml in zip(a, x)), 2) # → 2.11
The paper uses L = 3 and picks F = 2 or F = 8 by out-of-bag error, rescaling inputs to mean 0 and spread 1 first when their units differ. The results (its Table 3) compare with Adaboost even more favourably than Forest-RI: 13.6% against 15.6% on sonar, 23.0% against 26.6% on diabetes, 3.8% against 4.9% on twonorm. A later experiment with F = 100 combinations reached 8.5% on the satellite images and 3.0% on the letters, and Forest-RI with F = 25 reached 5.8% on zip-code, which the paper calls the lowest test set errors so far achieved on these three datasets by tree ensembles.
5.1 Categorical variables
A categorical input with I values (a region code with I = 6 regions, say) is handled by drawing a random subset of its categories each time it is chosen, and turning it into a yes/no feature: “is the region in this subset?”. Since such an input carries as much as I − 1 yes/no columns would, it is made I − 1 times as likely to be picked; the region code is 5 times as likely as a numeric input. With many categorical inputs, the paper finds F must rise to two or three times int(log2 M + 1) to keep enough strength. This also sidesteps the costly search for the best subset of categories, which for more than two classes grows like 2I−1.
Why it matters
Random combinations produce splits that are not parallel to the axes, so the forest can follow a diagonal boundary with fewer steps. The price is that each question mixes several inputs and is harder to read; the lesson's forest, like Forest-RI, asks about one real input per split.
6 Empirical results on strength and correlation · original
“Past about F=4 the strength remains constant; adding more inputs does not help. But the correlation continues to increase.”Breiman (2001), §6
Everyday picture
Let each doctor see more test results and two things happen: each becomes a little better, and they start agreeing more, mistakes included. Past some point the first effect stops and only the second continues.
The experiment
On the sonar data (60 inputs, 208 examples) the paper grows Forest-RI with every F from 1 to 50, 100 trees each, repeated 80 times on random 10% test splits: 400,000 trees in all. It records the out-of-bag strength and correlation for each F.
Hover or tap the chart to read strength and correlation at any F.
Hover or tap the chart to read the ratio c/s² at any F.
Strength and correlation are read off the top panel of the paper's Figure 1 by eye, so each is approximate to about ±0.01. The ratio c/s2 is computed on this page from those readings.
Reading it: the horizontal axis is F, the number of random inputs each node may choose from. The solid line (strength) climbs quickly up to F of about 4 and then stays almost flat near 0.4. The dashed line (correlation) starts lower and keeps climbing all the way to about 0.5. The second chart is their ratio ρ̄/s2, the quantity Theorem 2.3 says to keep small (note its axis starts at 2.5): it falls to its lowest around F = 5 or 6, then climbs steadily as extra correlation buys no extra strength. The paper's error curves (the bottom panel of its Figure 1) behave the same way: a small drop out to F of about 4 to 8, then a slow rise.
Other datasets
On the breast cancer data with random combinations (Figure 2), strength is flat from the start and correlation creeps up, so the best F is 1. On the larger satellite data (Figure 3), both keep rising slowly and the error falls slightly as F grows; the paper conjectures that on larger, more complex data the strength keeps improving for longer before it plateaus.
Why it matters
This is the evidence behind the rule “use few random inputs per node”. It also explains why forests are so forgiving to tune: the ratio is shallow over a wide range of F, so almost any sensible choice lands near the best.
7 Conjecture: Adaboost is a random forest · original
“… my belief is that in its later stages Adaboost is emulating a random forest.”Breiman (2001), §1.2
Everyday picture
A pseudo-random number generator is completely deterministic, yet its output looks random. Adaboost is also deterministic: it reweights the training examples after each tree, raising the weight of the ones just misclassified. Breiman's hunch is that, after a while, this sequence of weightings wanders like a random draw from some fixed distribution, which would make Adaboost a random forest in disguise.
Tiny example
Adaboost gives each tree a vote weight that grows with its accuracy on the weighted data. A tree with 10% weighted error gets log(0.9/0.1) = 2.197; one with 40% error gets log(0.6/0.4) = 0.405; one no better than a coin flip (50%) gets 0.
In words: “a tree's say in the vote is the logarithm of its odds of being right on the weighted training set.”
With the numbers: taking log as the natural logarithm, error 0.1: log 9 = 2.197; error 0.25: log 3 = 1.099; error 0.4: log 1.5 = 0.405; error 0.5: log 1 = 0.
In Python:
import math
# Q(w_k) = log[(1 − error(k)) / error(k)], natural log
[round(math.log((1 - err) / err), 3) for err in (0.1, 0.25, 0.4, 0.5)] # → [2.197, 1.099, 0.405, 0.0]
The experiment
The paper runs Adaboost 75 times, discards the first 25 weightings, and treats the remaining 50 as a deck of cards, each drawn with probability proportional to its Q. A random forest that grows each tree on a randomly drawn card from this deck matched Adaboost closely: on the Wisconsin breast cancer data, 2.91% error for Adaboost against 2.94% for the forest. If the conjecture holds (the paper states it precisely as an ergodicity condition on the reweighting map), it would also explain why Adaboost does not overfit as trees are added, which was a puzzle at the time.
Why it matters
The conjecture was never settled in this paper, and later work showed that boosting can overfit when run long enough on noisy data, which is why modern boosting uses early stopping. The lasting lesson is the contrast in how the two families work: boosting changes the training set as it goes, forests never do.
8 The effects of output noise · original
“Then, Adaboost will concentrate increasing weight on these noisy instances and become warped.”Breiman (2001), §8
Everyday picture
A tutor who spends each lesson on the questions you got wrong last time is excellent, until the answer key has typos. Then the tutor keeps drilling the questions whose “correct” answers are wrong, and the whole course bends around them. A committee that never reweights anything just outvotes the typos.
Tiny example
The paper flips 5% of the training labels (about one in twenty) to a different class at random, and measures how much the test error rises. On the breast cancer data, Adaboost's error rises by 43.2%; Forest-RI's by 1.8%.
Reading it: each pair of bars is one dataset from the paper's Table 4, selected rows reproduced with attribution (Breiman, 2001): the percent increase in test error when 5% of the training labels are wrong. Grey bars are Adaboost and the striped blue bars are Forest-RI; a negative value (sonar) means the noisy run happened to score slightly better. Adaboost's damage is large and uneven, from a few percent to almost 50%, while the forest's stays in single digits. The reason is in the quote above: mislabelled examples keep being misclassified, so boosting keeps raising their weight.
Why it matters
Real labels are noisy. Robustness to wrong labels is one of the practical reasons forests remain a safe default, and why boosting libraries added shrinkage, subsampling and early stopping (see the trees and boosting lesson).
9 Data with many weak inputs · original
“Forests seem to have the ability to work with very weak classifiers as long as their correlation is low.”Breiman (2001), §9
Everyday picture
Some problems have no single tell-tale clue: a diagnosis from hundreds of lab values, each only slightly informative. One tree, which asks about one input at a time, barely beats guessing. But a crowd of barely-better-than-guessing trees, if their mistakes are independent, can add up to an expert.
Tiny example: the paper's run
The paper simulates 10 classes and 1,000 yes/no inputs, 1,000 training and 4,000 test examples. The best possible error (the Bayes rate) is 1.0%, and a naive Bayes classifier gets 6.2%.
| F | One tree's error | Forest error | Strength s | Correlation ρ̄ | c/s² (paper) | ρ̄/s² (recomputed) |
|---|---|---|---|---|---|---|
| 1 | 80% | 10.7% | 0.069 | 0.012 | 2.5 | 2.52 |
| 10 | 65% | 3.0% | 0.22 | 0.045 | 0.91 | 0.93 |
| 25 | 60% | 2.8% | 0.28 | 0.065 | 0.83 | 0.83 |
Each tree is wrong 60% to 80% of the time, yet the forest with F = 25 gets 2.8%, not far above the 1.0% floor and well below naive Bayes. With F = 1 the correlation is almost zero but the strength is too low, and the forest had still not converged after 2,500 trees. Raising F bought strength at a small price in correlation, and the ratio fell from 2.5 to 0.83, tracking the error. (The paper's 0.91 for F = 10 differs from the 0.93 recomputed here only because its strength is printed rounded to 0.22.) The paper could not get Adaboost to run on this data at all, because the individual trees are too weak.
In Python:
# (s, ρ̄) for F = 1, 10, 25, as printed in §9
runs = [(0.069, 0.012), (0.22, 0.045), (0.28, 0.065)]
# c/s² = ρ̄ / s²
[round(rho_bar / s ** 2, 2) for s, rho_bar in runs] # → [2.52, 0.93, 0.83]
Why it matters
The same principle, many weak but independent voters, is behind every ensemble method, including the averaging of many randomly thinned networks that dropout approximates inside one neural network.
10 Exploring the random forest mechanism · original
“A forest of trees is impenetrable as far as simple interpretations of its mechanism go.”Breiman (2001), §10
Everyday picture
To learn which player a football team depends on, bench each one for a real match and see how much the score suffers. The paper does this to the inputs of a forest: scramble one input's values in the out-of-bag rows, so it no longer lines up with anything, and measure how much worse the out-of-bag vote gets.
Tiny example
A forest has an out-of-bag error of 20%. Shuffle input m among the out-of-bag rows, run them down the trees again, and the out-of-bag error becomes 26%. The paper reports the percent increase: (26 − 20) / 20 = 30%.
In words: “an input's importance is how much, in percent, the out-of-bag error grows when that input is scrambled.” (The paper describes this in prose; the formula is ours.)
With the numbers: 100 × (0.26 − 0.20) / 0.20 = 30.
In Python:
# out-of-bag error intact, and with input m scrambled
e, e_m = 0.20, 0.26
round(100 * (e_m - e) / e, 1) # → 30.0
Values read off the paper's Figure 4 by eye, approximate to about ±1.
Reading it: each bar is one of the eight inputs of the diabetes data, and its length is the percent rise in out-of-bag error when that input is scrambled (a forest of 1,000 trees, F = 1). Input 2 dominates at about 34%, followed by input 8 (about 14%) and input 6 (about 10%). The paper then checks by refitting on subsets: input 2 alone gives 29.7% test error against 23.1% with everything; adding input 6 brings it to 26.4%, but adding input 8 only to 29.4%. Input 8 looked important because it carries much of the same information as input 2: scrambling either one hurts, but once one is in, the other adds little.
On the congressional voting data (435 members, 16 yes/no votes), one vote stands out: scrambling it triples the error, and a forest using that single vote scores 4.3%, about the same as one using all sixteen.
Why it matters
This procedure grew into permutation importance, now standard for any model. The trees and boosting lesson implements it on held-out validation data as permutation_importance, and shows the cheaper impurity-based importance (RandomForest.feature_importances) crediting a pure-noise column. The paper's diabetes finding is the caveat the lesson repeats: correlated inputs share the credit, and importance is not cause.
11 Random forests for regression · original
“The randomization employed needs to aim at low correlation.”Breiman (2001), §11
Everyday picture
For numbers instead of labels, the trees no longer vote; they average. Ask a hundred people to guess the weight of an ox and average the guesses: individual errors cancel, but only to the extent that people do not all err in the same direction.
Tiny example
The paper's Table 7 reports, for the Boston housing data, that a single tree's mean squared error averages 26.3, and that two trees' residuals (true value minus prediction) have a weighted correlation of 0.45. Theorem 11.2 promises the forest's error is at most 0.45 × 26.3 = 11.8. The forest's out-of-bag error is 11.6 and its test error 10.2.
In words: “averaging the trees divides their typical squared error by at least the mean correlation of their residuals.”
With the numbers: Boston: 0.45 × 26.3 = 11.8 (out-of-bag 11.6); ozone: 0.55 × 32.5 = 17.9 (out-of-bag 17.6); abalone: 0.56 × 8.3 = 4.6 (out-of-bag 4.6).
In Python:
# (ρ̄, PE*(tree)) from Table 7 for Boston, ozone and abalone
rows = [(0.45, 26.3), (0.55, 32.5), (0.56, 8.3)]
# the bound ρ̄ · PE*(tree)
[round(rho_bar * pe_tree, 1) for rho_bar, pe_tree in rows] # → [11.8, 17.9, 4.6]
The theorem assumes each tree is unbiased on average (its average prediction equals the average target). Its proof is the same move as §2.2: the forest's squared error is an average, over pairs of trees, of the covariance of their residuals, which is correlation times spreads. Theorem 11.1, the regression version of Theorem 1.2, says the average over trees converges as trees are added, so again more trees cannot overfit.
Why it matters
With B → ∞ this is exactly the lesson's formula ρσ2 + (1 − ρ)σ2/B with the second term gone: the floor is ρσ2. The lesson plots it with averaged_variance and forest_curve.
12 Empirical results in regression · original
What the paper finds
Regression forests here use bagging plus 25 random features per node, each a random combination of two inputs, 100 trees, and no split of a node with fewer than 5 examples. Against plain bagging and Breiman's earlier adaptive bagging:
| Data set | Bagging | Adaptive bagging | Forest | Forest OB error | PE*(tree) | Correlation |
|---|---|---|---|---|---|---|
| Boston housing | 11.4 | 9.7 | 10.2 | 11.6 | 26.3 | 0.45 |
| Ozone | 17.8 | 17.8 | 16.3 | 17.6 | 32.5 | 0.55 |
| Abalone | 4.9 | 4.9 | 4.6 | 4.6 | 8.3 | 0.56 |
| Friedman #1 | 6.3 | 4.1 | 5.7 | 6.3 | 15.3 | 0.41 |
The forest always beats bagging. Where adaptive bagging (which, like boosting, changes the training data as it goes) helps a lot, the forest helps less; where it helps nothing, the forest still helps. One difference from classification: correlation rises only slowly as more features are allowed per node, so regression forests need more features per node to drive down each tree's error.
The paper also swaps bagging for random output noise (Gaussian noise with the same spread as the targets added to every training target) and gets its lowest errors yet on the first two datasets. Its Table 8 lists Boston at 10.2 with bagging and 9.1 with noise. One entry there does not match the earlier tables: Table 8 gives ozone's with-bagging error as 17.8, which is bagging's entry in Table 6, while the forest's is 16.3 in Tables 6 and 7, the same value Table 8 gives for the noise version.
Why it matters
The out-of-bag estimates track the test errors, usually a little high, as §3.1 predicted. And the result that different kinds of injected randomness work better on different problems is the paper's standing invitation to experiment with the recipe.
13 Remarks and conclusions · original
“Because of the Law of Large Numbers they do not overfit.”Breiman (2001), §13
What the paper leaves open
- Why forests reduce bias. Boosting is known to reduce bias as well as variance by reweighting the data. Forests never change the data, yet match boosting's accuracy, so they must reduce bias too, and the paper admits the mechanism is not obvious.
- Other randomness. Bagging and random features are only two choices; a referee suggested random Boolean combinations of features.
- Random features plus boosting. Combining the two gave errors as low as 5.1% on zip-code, 2.2% on letters and 7.9% on the satellite data in some runs: better than either alone on the larger datasets.
Why it matters
The last open question was answered in practice: XGBoost, for one, samples a random subset of columns for every tree, borrowing the forest's decorrelation trick to make boosting less prone to overfitting (see the XGBoost companion, §2.3).
Appendix II: out-of-bag estimates for strength and correlation · original
Everyday picture
Strength and correlation are defined through the probabilities that an imaginary random tree votes each way. The appendix replaces each imaginary probability with a real count: the share of out-of-bag trees that voted that way.
Tiny example
In the out-of-bag table above, email 2 is spam and is out of bag for trees 1 and 3. If both vote spam, its out-of-bag vote share for spam is 2/2 = 1. Email 1 is out of bag only for tree 2; if tree 2 votes not spam, email 1's share for spam is 0/1 = 0.
In words: “among the trees that never saw this example, the share that voted for class j.”
With the numbers: email 2: trees 1 and 3 are out of bag and both vote spam, so Q(email 2, spam) = 2/2 = 1.0. Replace the probabilities in the margin by these shares, average over the training set, and you have the out-of-bag strength; the spread of those margins gives the correlation through equation (7).
In Python:
# for email 2: which trees saw it, and how each tree votes on it
in_bag = {1: False, 2: True, 3: False, 4: True}
vote = {1: "spam", 2: "not", 3: "spam", 4: "spam"}
oob_trees = [k for k in in_bag if not in_bag[k]]
oob_trees # → [1, 3]
# Q(x, spam): the out-of-bag share of votes for spam
sum(1 for k in oob_trees if vote[k] == "spam") / len(oob_trees) # → 1.0
Why it matters
This is what makes the theory usable: strength and correlation are not just symbols in a bound, they are numbers the forest reports about itself on every run, as §6 and §9 show.
What changed since 2001
The algorithm most people run today is the paper's Forest-RI with bagging, almost unchanged. What moved is around it:
| In the paper | Common today | Why | Where |
|---|---|---|---|
| F = 1 or int(log2 M + 1) inputs per node | About the square root of the number of inputs for classification | A middle ground between the paper's two settings that works on most tables | trees lesson |
| Importance by scrambling inputs in the out-of-bag rows | Permutation importance on a held-out set, for any model; impurity importance as a quick look | Impurity importance is biased towards inputs with many distinct values | trees lesson |
| Forests versus Adaboost | Forests versus gradient-boosted trees | Gradient-boosted trees are the more common winner on tables; forests remain the model that works best with no tuning at all | gradient boosting companion |
| Averaging many randomized models | The same idea inside neural networks | Dropout trains an implicit ensemble of thinned networks | dropout companion |
Glossary
Every term with hover guidance on this page, in one place.