Worked examples — Out-of-bag error estimation
A drill-book for Out-of-bag error estimation. We march through every case the OOB idea can throw at you: normal forests, tiny forests, degenerate points that are OOB for nobody, ties, regression vs classification, the large- limit, and a real-world twist. Guess before you read the steps.
Before anything, one plain-word refresher so no symbol arrives unearned:
The scenario matrix
Every OOB question is really one of these cells. The examples below are tagged with the cell they hit.
| Cell | Case class | What makes it tricky | Example |
|---|---|---|---|
| A | Identify OOB set from one bootstrap | Repeats hide unique picks | Ex 1 |
| B | Classification vote, clear majority | which trees count | Ex 2 |
| C | Classification vote, tie | even , no majority | Ex 3 |
| D | Regression average | different aggregation rule | Ex 4 |
| E | Full OOB error over all points | mixing per-point | Ex 5 |
| F | Degenerate: point OOB for zero trees | prediction undefined | Ex 6 |
| G | Limiting: vs small | the number | Ex 7 |
| H | Real-world word problem | translate story → OOB | Ex 8 |
| I | Exam twist: OOB vs train error gap | why they differ | Ex 9 |
The blueprint below is the whole world our examples live in: rows are points, columns are trees, a cell is dark (in-bag) or amber (OOB). Everything else is bookkeeping on this grid.

Example 1 — Read the OOB set off a bootstrap (Cell A)
Forecast: guess how many of the 6 points ended up OOB before reading on.
- List the distinct indices that appear. They are . Why this step? A point is in-bag if it appears at least once; repeats ( thrice, twice) don't add new points, so we collapse to the unique set.
- OOB = everything not in that set: . Why this step? By definition OOB means "never drawn". Points are absent, so the tree never saw them.
- Fraction OOB: . Why this step? Just count OOB over .
Verify: in-bag OOB , and they're disjoint — every point is classified exactly once. ✓ Fraction here; for tiny the OOB fraction is noisy and only settles onto its long-run value for large — we derive that long-run value () carefully in Example 7, so don't worry where it comes from yet.
Example 2 — Classification, clear majority (Cell B)
Forecast: which label wins, and does it match ?
- Count votes only inside . Zeros: → three. Ones: → two. Why this step? Only trees that never trained on may vote — that keeps the estimate honest (no bagging label leakage).
- Majority vote: . Why this step? Classification aggregation is the plurality of the sub-ensemble .
- Loss: (recall is if the inside is true, else ; here is false). Why this step? 0/1 loss is when prediction matches truth.
Verify: — all OOB votes accounted for. Prediction equals , so this point adds nothing to the error. ✓
Example 3 — Classification with a TIE (Cell C)
Forecast: two ones, two zeros — what does a forest actually do?
- Count: ones , zeros . A genuine tie. Why this step? An even can split evenly — the case the naive "majority" rule doesn't cover.
- Turn the 0/1 votes into a class-1 probability. Each tree votes a hard or ; the ensemble's estimated probability of class 1 is simply the fraction of trees voting 1 among : . Why this step? "Probability of class 1" is not mystical here — it is just how many of the qualifying trees said 1, divided by how many voted. Averaging the votes gives that fraction directly.
- Apply the deterministic tie rule. The default rule predicts the class with the largest ; at an exact tie it returns the lower class index, so . Why this step? We must state a reproducible rule; scikit-learn's default is "argmax of averaged probabilities", and on an exact it returns the first class (index ).
- Loss: . Why this step? 0/1 loss penalizes the mismatch fully.
Verify: exactly ( of votes are ), confirming a true tie; the deterministic rule gives a reproducible answer instead of a coin flip. ✓ (If your library breaks ties toward class 1, and loss — always know your library's rule.)
Example 4 — Regression average (Cell D)
Forecast: guess the averaged prediction to the nearest integer.
- Average the OOB predictions. . Why this step? Regression aggregation is the mean over , not a vote — trees output numbers, so we average.
- Squared error: . Why this step? Squared-error loss is the standard regression loss .
Verify: , and . The scatter around () cancels, giving a perfect hit — a nice reminder that averaging reduces variance (Bias-Variance Tradeoff). ✓
Example 5 — Full OOB error with per-point sub-ensembles (Cell E)
Forecast: how many of the 4 points get misclassified?
- Point 1: ones vs zeros → → loss . Why this step? Point 1 is judged only by its own (3 trees); majority is , matching .
- Point 2: zeros vs ones → → loss . Why this step? has 4 trees, a different set from ; the majority matches .
- Point 3: tie → lower-index rule → → loss . Why this step? has only 2 trees and splits evenly, so we fall back to the Example-3 tie rule (predict class ), which misses the truth.
- Point 4: ones vs zeros → → loss . Why this step? (3 trees) votes majority , but the truth is — an honest mistake this sub-ensemble makes.
- Average: Why divide by ? We average the per-point losses over all training points, each scored by its own — no shared hold-out.
Verify: two of four points wrong → . ✓ Note each point used a different number of votes () — legitimate and typical.
Example 6 — Degenerate: a point OOB for NOBODY (Cell F)
Forecast: can we even predict this point with OOB rules?
- Look at . It is empty: no tree qualifies to vote. Why this step? OOB prediction is defined only over . With there is nothing to average or vote.
- The prediction is undefined. Implementations either skip from the OOB error or emit a warning. Why this step? You cannot leak a label into the estimate, so you must exclude the point — it contributes terms to both numerator and denominator of the average.
- Estimate how likely this is. The chance one tree leaves out is the exact finite- miss-probability (derived in Example 7). So the chance it is in-bag for one tree is , and for all trees at once: For a large dataset the inner term approaches its limit , giving . For (and large ): — a whopping 25% chance! For : — vanishing. Why this step? We separate the exact finite- formula from its large- shortcut , so you know the is an approximation valid when is big.
Verify: ✓ This is exactly the "OOB needs many trees" mistake from the parent: small leaves points undefined and estimates high-variance.
Example 7 — The limiting number, small vs large (Cell G)
Forecast: is the fraction increasing or decreasing toward ?
- : . Why this step? Direct plug-in of the exact miss-probability formula from the parent.
- : . Why this step? Larger pushes toward the limit; still slightly above it.
- : Why this step? This is the definition at — the exponential is the tool that answers "what does repeated tiny multiplication converge to?"

How to read this figure: the horizontal axis is the dataset size ; the vertical axis is the OOB fraction . The cyan curve plots that fraction as grows — it climbs steadily. The dashed amber line is the limit . The two white dots mark our computed values at () and (). Read off the key message: the curve rises from below and flattens onto the amber line, so real datasets always have a little more than OOB when is small, converging down onto as grows.
Verify: the sequence climbs monotonically toward from below. ✓ So every real dataset has slightly more than 37% OOB for small , converging down onto as grows.
Example 8 — Real-world word problem (Cell H)
Forecast: guess how many of the 500 trees vote per customer.
- OOB fraction per tree . Why this step? is huge, so we use the limiting value.
- Expected trees with the customer OOB: trees. Why this step? Each tree independently leaves the customer out with probability ; expected count .
- Trust argument: those trees never saw that customer, so their averaged vote is an honest test prediction. Doing this for all customers yields a test-error estimate for free during training — no extra model fits, unlike -fold CV which refits times. Why this step? This is the core value proposition of OOB from the parent note.
Verify: . ✓ And , so no undefined predictions — large cures Cell F.
Example 9 — Exam twist: OOB vs training error (Cell I)
Forecast: which number is closer to real-world performance?
- Training error uses ALL trees, including those that memorized each point. So a point is scored partly by trees that trained on it → optimistic → artificially low (). Why this step? Decision trees can perfectly fit their bootstrap sample, so in-bag scoring leaks labels.
- OOB error uses only (unseen trees). No leakage → honest → higher and realistic (). Why this step? This is exactly why we restrict to .
- Conclusion: the model did not get worse; is the trustworthy test-error estimate. The gap is the optimism of training error. Why this step? OOB CV true test error; training error is a lower bound you should never quote.
Verify: gap (OOB train for a well-fit forest). ✓ Reporting would over-promise; report .
Recall One-line summary of the matrix
Guess the cell first ::: Identify OOB set (A) → aggregate by vote or mean over only (B/C/D) → average per-point losses (E) → watch empty (F) and the limit (G) → translate stories (H) and never confuse OOB with train error (I).
Connections
- Bootstrap Sampling — creates the in-bag/OOB split every example reads off.
- Bootstrap Aggregating (Bagging) — the sub-ensemble is honest bagging on unseen data.
- Random Forests — the real consumer of OOB error (Ex 8).
- Cross-Validation — the paid alternative OOB replaces for free.
- Bias-Variance Tradeoff — averaging (Ex 4) cancels variance.
- Decision Trees — memorizing base learners cause the Ex 9 gap.