Quiz 2

Ensemble Methods: Bagging & Random Forest

1788 words
9 min read
Python Week 1: the first filter for runtime behavior
Visual companion
Python
Type and operator map

Python Week 1: the first filter for runtime behavior

View
Revision summary

What this note is really saying

Short form

# Ensemble Methods: Bagging & Random Forest ## 🎯 Learning Objectives - Explain why ensembles outperform individual models - Describe bagging (Bootstrap Aggregating) and how it reduces variance - Build and tune a Random Forest classifier - Understand the difference between bagging and boosting - Implement gradient b...

Ensemble Methods: Bagging & Random Forest

🎯 Learning Objectives

  • Explain why ensembles outperform individual models
  • Describe bagging (Bootstrap Aggregating) and how it reduces variance
  • Build and tune a Random Forest classifier
  • Understand the difference between bagging and boosting
  • Implement gradient boosting with sklearn

📋 Prerequisites

  • Decision Trees — the base learner for most ensembles
  • Bootstrap sampling — sampling with replacement
  • Bias-variance tradeoff — ensembles reduce variance (bagging) or bias (boosting)

📖 Core Content

7.1 Intuition: The Wisdom of Crowds

Imagine you need to guess the number of jelly beans in a jar. One person's guess is likely off. But if you ask 100 people and average their guesses, the average is surprisingly accurate — often closer than any individual. This is the wisdom of crowds. Ensemble methods apply the same idea to ML. Instead of training one model, we train many diverse models and combine their predictions. The ensemble is typically more accurate, more stable, and less prone to overfitting than any single model. (Diagram)

7.2 Bagging: Bootstrap Aggregating

Bagging works in two steps:
  1. Bootstrap: Create B new training sets by sampling with replacement from the original dataset (each about 63% unique, 37% duplicated or missing).
  2. Aggregate: Train a model on each bootstrap sample, then average (regression) or majority vote (classification).
python
# runnable
from sklearn.ensemble import BaggingClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
import numpy as np
X, y = make_classification(n_samples=500, n_features=20, random_state=42)
# Single tree
tree = DecisionTreeClassifier(random_state=42)
tree_scores = cross_val_score(tree, X, y, cv=5)
print(f"Single tree: {tree_scores.mean():.3f} ± {tree_scores.std():.3f}")
# Bagged ensemble
bag = BaggingClassifier(
    estimator=DecisionTreeClassifier(),  # Note: use 'estimator' not 'base_estimator' in newer sklearn
    n_estimators=100,
    max_samples=0.8,
    bootstrap=True,
    random_state=42
)
bag_scores = cross_val_score(bag, X, y, cv=5)
print(f"Bagging (100 trees): {bag_scores.mean():.3f} ± {bag_scores.std():.3f}")
Why bagging works: Decision trees have high variance — a small change in training data produces a very different tree. By averaging many trees trained on different bootstrap samples, the variance drops while bias stays roughly the same.

7.3 Random Forest

Random Forest is bagging plus one extra trick: at each split, only a random subset of features is considered. This decorrelates the trees — without it, the trees would all choose the strongest feature for their root split and look very similar. (Diagram) Key parameters:
  • n_estimators: number of trees (higher is better, diminishing returns after ~100-500)
  • max_features: number of features considered at each split (default: sqrt(n) for classification, n/3 for regression)
  • max_depth: max tree depth (default: unlimited — trees grow fully)
  • min_samples_leaf: minimum samples per leaf (default: 1 for classification)
  • oob_score: use Out-Of-Bag samples as internal validation
python
# runnable
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
wine = load_wine()
X, y = wine.data, wine.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
rf = RandomForestClassifier(
    n_estimators=200,
    max_depth=10,
    min_samples_leaf=2,
    max_features='sqrt',
    oob_score=True,
    random_state=42
)
rf.fit(X_train, y_train)
y_pred = rf.predict(X_test)
print(f"Test accuracy: {accuracy_score(y_test, y_pred):.3f}")
print(f"OOB score: {rf.oob_score_:.3f}")
# Feature importance
for name, imp in sorted(zip(wine.feature_names, rf.feature_importances_),
                         key=lambda x: x[1], reverse=True)[:5]:
    print(f"  {name}: {imp:.3f}")

7.4 Out-of-Bag (OOB) Evaluation

Each bootstrap sample contains about 63% of the original data. The remaining 37% (out-of-bag) serve as a built-in validation set — no need for a separate validation split or cross-validation. For each tree, predict on its OOB samples. Aggregate OOB predictions across all trees to get an unbiased performance estimate. This is essentially free internal cross-validation.

7.5 Boosting: Sequential Ensemble

Unlike bagging (parallel, independent trees), boosting trains trees sequentially, each one correcting the mistakes of the previous ones. (Diagram) AdaBoost: Increases weights on misclassified examples. Each new tree focuses on hard cases. Gradient Boosting: Each tree predicts the residual errors (gradient of the loss) of the previous ensemble.
python
# runnable
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import numpy as np
X, y = make_classification(n_samples=500, n_features=20, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
gb = GradientBoostingClassifier(
    n_estimators=100,
    learning_rate=0.1,
    max_depth=3,
    min_samples_leaf=5,
    subsample=0.8,  # Stochastic: use 80% of data per tree
    random_state=42
)
gb.fit(X_train, y_train)
y_pred = gb.predict(X_test)
print(f"GB test accuracy: {accuracy_score(y_test, y_pred):.3f}")

7.6 Comparison: Bagging vs Boosting

AspectBagging / Random ForestBoosting (AdaBoost, GBM)
TrainingParallel (independent)Sequential (dependent)
GoalReduce varianceReduce bias
OverfittingLow (averaging helps)High (can overfit if too many rounds)
Base learnersDeep trees (high variance)Shallow trees (weak learners)
SpeedFast (parallelizable)Slow (sequential)
Data scalingNot neededNot needed
Key hyperparamsn_estimators, max_featuresn_estimators, learning_rate, subsample

7.7 When to Use / Not Use

When to UseWhen NOT to Use
Need high accuracy (RF is often top-3)Interpretability is critical (use single tree)
Mixed data typesVery sparse data (linear models better)
Many features (RF handles well)Production latency is tight (RF is large)
Imbalanced data (RF handles OK)Need calibrated probabilities (use logistic reg)

📐 Key Formulas / Concepts

ConceptFormula/DefinitionNotes
BootstrapSample with replacement~63% unique per sample
Bagging predictiony^=1By^b\hat{y} = \frac{1}{B}\sum \hat{y}_b (regression)or majority vote (classification)
OOB ErrorError on out-of-bag samplesFree validation
Random ForestBagging + random feature subset at each splitmax_features = sqrt(n) for classif
Boostingy^=αbhb(x)\hat{y} = \sum \alpha_b h_b(x)Weighted sum of weak learners
Learning Rateη < 1 shrinks each tree's contributionLower η = more trees needed

⚠️ Common Pitfalls

Pitfall 1: Too Few Trees

The mistake: Using n_estimators=10 and wondering why RF doesn't beat a single tree. Why: Random Forest needs enough trees to stabilize the variance reduction. With too few, the ensemble still has high variance. Fix: Start with n_estimators=100. Check if increasing to 500 helps. Plot OOB error vs n_estimators — stop when it plateaus.

Pitfall 2: Overfitting with Boosting

The mistake: Using n_estimators=1000 with learning_rate=1.0 and deep trees. Why: Boosting is prone to overfitting — each tree greedily fixes the last errors, eventually memorizing noise. Fix: Use shallow trees (max_depth=2-4), higher learning_rate with fewer trees, or early stopping.

Pitfall 3: Ignoring max_features in RF

The mistake: Setting max_features = n_features (all features considered at every split). Why: Trees become highly correlated — losing the key benefit of Random Forest. All trees look similar. Fix: Use sqrt(n) for classification, n/3 for regression. This forces diversity.

📝 Practice Questions

Q1: What fraction of original data appears in a bootstrap sample?
About 63.2% (approximately 1 - 1/e). The probability a specific example is NOT selected in a sample of size m (with replacement) is (1 - 1/m)^m → 1/e ≈ 36.8%. So 63.2% appear at least once. Q2: Why does random forest outperform a single decision tree?
  1. Variance reduction: Averaging B independent trees reduces variance by factor ≈ B (but trees aren't fully independent)
  2. Feature randomization: Decorrelates trees further
  3. Robustness: Less sensitive to noise and outliers
A single decision tree can change completely with minor data changes. RF averages over this instability. Q3: What is the difference between bagging and pasting?
  • Bagging: Bootstrap sampling (with replacement) — some examples appear multiple times, some appear 0 times.
  • Pasting: Sampling without replacement — each example appears at most once per sample. Pasted samples are smaller subsets.
Bagging is more common because it creates more diverse training sets. Q4: Your RF has training accuracy 0.99 and test accuracy 0.85. What do you do?
The gap (0.14) suggests overfitting. Solutions:
  1. Reduce max_depth (limit tree growth)
  2. Increase min_samples_leaf
  3. Increase n_estimators (more averaging reduces variance)
  4. Reduce max_features (more randomness)
  5. Increase data if possible
The OOB score should be close to test score — if OOB is also 0.99, overfitting is confirmed. Q5: Explain how gradient boosting works in one sentence.
Gradient boosting trains trees sequentially where each new tree predicts the negative gradient (residual errors) of the loss function with respect to the current ensemble's predictions. Q6: When would you choose Gradient Boosting over Random Forest?
Choose Gradient Boosting when:
  1. You need the highest possible accuracy (GB tends to win competitions)
  2. Data is not too large (< 100k rows)
  3. You have time for hyperparameter tuning
  4. You're using shallow trees (weak learners)
Choose Random Forest when:
  1. Simplicity and robustness matter
  2. Data is very large (RF parallelizes easily)
  3. You worry about overfitting (RF is more robust)
  4. Quick baseline needed Q7: What is subsample in gradient boosting?
subsample (default 1.0) specifies the fraction of training data used per tree. Value 0.8 means each tree uses 80% of data (randomly selected). This adds randomness (like bagging) and helps prevent overfitting. Called Stochastic Gradient Boosting. Q8: Implement a Random Forest regressor for the Boston housing dataset.
python
from sklearn.ensemble import RandomForestRegressor
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
import numpy as np

housing = fetch_california_housing()
X, y = housing.data, housing.target
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=42)

rf = RandomForestRegressor(n_estimators=200, max_depth=15, random_state=42)
rf.fit(X_train, y_train)

y_pred = rf.predict(X_test)
rmse = np.sqrt(mean_squared_error(y_test, y_pred))
print(f"RMSE: ${rmse:.3f}k")
Q9: What is a "weak learner" in boosting context?
A weak learner is a model that performs slightly better than random (e.g., accuracy > 50% for binary classification). In boosting, weak learners are typically decision stumps (depth 1 trees) or shallow trees (depth 2-3). The magic of boosting is combining many weak learners into one strong ensemble. Q10: How does early stopping work in gradient boosting?
Monitor validation error after each tree is added. If validation error hasn't improved for n_iter_no_change rounds, stop training. This prevents overfitting and saves computation. sklearn's GradientBoostingClassifier supports this with n_iter_no_change and validation_fraction parameters. Q11: Why does RF not require feature scaling?
Because decision trees (the base learners) are threshold-based, not distance-based. A tree tests "is feature > t?" regardless of the feature's scale. Doubling a feature's scale just doubles the threshold — the split point adapts. So RF works with raw data without any scaling. Q12: Compare bagging with pasting.
AspectBaggingPasting
SamplingWith replacementWithout replacement
Unique examples per sample~63%100% (if sample size = original)
DiversityHigher (some examples appear multiple times)Lower
Duplicates in sampleYesNo
Typical useDefault for most ensemblesWhen you want all examples used
Bagging is generally preferred because the extra diversity helps ensembles more.

🔗 Cross-References

Document outline

Keep your place and jump directly to a heading.

Table of Contents
System Normal // Awaiting Context

Intelligence Hub

Navigate the knowledge graph to generate context. The Hub adapts dynamically to surface backlinks, related notes, and metadata insights.