Boosted Trees › Implementation in Scikit-learn
Machine Learning from ScratchAll chapters Boosted Trees › Implementation in Scikit-learnOne section · Sections in this chapter5 / 8 ↓
Reading tools Definitions & inline links
Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.
Article links
Make inline references clickable
Boosted trees are implemented in scikit-learn through the GradientBoostingClassifier and GradientBoostingRegressor classes. Let's implement a complete example with proper preprocessing and evaluation:
import numpy as np
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import cross_val_score, train_test_split
np.random.seed(42)
n_samples = 1000
# Generate features for classification
age = np.random.normal(40, 15, n_samples)
age = np.clip(age, 18, 80)
income = np.random.normal(60, 20, n_samples)
income = np.clip(income, 20, 150)
experience = np.random.normal(10, 8, n_samples)
experience = np.clip(experience, 0, 30)
# Create target based on realistic relationship
log_odds = -5 + 0.02 * age + 0.01 * income + 0.05 * experience
prob_purchase = 1 / (1 + np.exp(-log_odds))
y_class = np.random.binomial(1, prob_purchase, n_samples)
X_class = np.column_stack([age, income, experience]) # Combine features
X_train_class, X_test_class, y_train_class, y_test_class = train_test_split(
X_class, y_class, test_size=0.2, random_state=42, stratify=y_class
)
gb_classifier = GradientBoostingClassifier(
n_estimators=100,
learning_rate=0.1,
max_depth=3,
min_samples_split=5,
min_samples_leaf=2,
random_state=42,
)
gb_classifier.fit(X_train_class, y_train_class)
y_pred_class = gb_classifier.predict(X_test_class)
y_pred_proba_class = gb_classifier.predict_proba(X_test_class)[:, 1]
# Use a more robust cross-validation approach
import warnings
from sklearn.model_selection import StratifiedKFold
# Suppress the specific warning about failed fits
warnings.filterwarnings("ignore", category=UserWarning, module="sklearn")
# Check class distribution to ensure we have both classes
unique_classes, class_counts = np.unique(y_train_class, return_counts=True)
print(
f"Class distribution in training set: {dict(zip(unique_classes, class_counts))}"
)
# Use StratifiedKFold with error handling
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
cv_scores = cross_val_score(
gb_classifier, X_train_class, y_train_class, cv=skf, scoring="roc_auc"
)Classification Performance:
Accuracy: 0.945
ROC AUC: 0.668
Feature Importance:
Age: 0.415
Income: 0.329
Experience: 0.256
Sample Predictions:
Age: 21.8, Income: 57.0, Exp: 2.7 -> Prob: 0.007, Actual: 0
Age: 39.8, Income: 90.6, Exp: 7.6 -> Prob: 0.061, Actual: 0
Age: 39.6, Income: 64.3, Exp: 8.7 -> Prob: 0.017, Actual: 1
Age: 35.4, Income: 28.3, Exp: 0.0 -> Prob: 0.003, Actual: 0
Age: 52.4, Income: 87.8, Exp: 11.8 -> Prob: 0.027, Actual: 0
Classification Report:
precision recall f1-score support
0 0.95 0.99 0.97 190
1 0.00 0.00 0.00 10
accuracy 0.94 200
macro avg 0.47 0.50 0.49 200
weighted avg 0.90 0.94 0.92 200
Confusion Matrix:
[[189 1]
[ 10 0]]
Cross-validation ROC AUC scores:
[0.51439145 0.58100329 0.55180921 0.52672697 0.48026316]
Mean CV ROC AUC: 0.531 (+/- 0.068)Feature Importance in Boosted Tree Classifier: ================================================== Age : 0.415 Income : 0.329 Experience : 0.256 ================================================== Higher values indicate more influential features.

Now let's implement a regression example:
np.random.seed(42)
# Generate features for regression
house_size = np.random.normal(2000, 500, n_samples)
house_size = np.clip(house_size, 800, 4000)
bedrooms = np.random.poisson(3, n_samples)
bedrooms = np.clip(bedrooms, 1, 6)
bathrooms = np.random.poisson(2, n_samples)
bathrooms = np.clip(bathrooms, 1, 4)
# Create target based on realistic relationship
house_price = (
50000
+ 100 * house_size
+ 20000 * bedrooms
+ 15000 * bathrooms
+ np.random.normal(0, 10000, n_samples)
)
house_price = np.clip(house_price, 100000, 800000)
X_reg = np.column_stack([house_size, bedrooms, bathrooms])
X_train_reg, X_test_reg, y_train_reg, y_test_reg = train_test_split(
X_reg, house_price, test_size=0.2, random_state=42
)
gb_regressor = GradientBoostingRegressor(
n_estimators=100,
learning_rate=0.1,
max_depth=3,
min_samples_split=5,
min_samples_leaf=2,
random_state=42,
)
gb_regressor.fit(X_train_reg, y_train_reg)
y_pred_reg = gb_regressor.predict(X_test_reg)Regression Performance: R² Score: 0.958 RMSE: 12387.57 Feature Importance: House Size: 0.688 Bedrooms: 0.249 Bathrooms: 0.063 Sample Predictions: Size: 2272, Beds: 3, Baths: 1 -> Pred: $356879, Actual: $339322 Size: 2491, Beds: 3, Baths: 3 -> Pred: $405659, Actual: $393120 Size: 1080, Beds: 4, Baths: 2 -> Pred: $274314, Actual: $260181 Size: 1713, Beds: 1, Baths: 4 -> Pred: $297229, Actual: $314224 Size: 1438, Beds: 2, Baths: 1 -> Pred: $248029, Actual: $247561
Feature Importance in Boosted Tree Regressor: ================================================== House Size : 0.688 Bedrooms : 0.249 Bathrooms : 0.063 ================================================== Higher values indicate more influential features.

Hyperparameter Tuning
Boosted trees have several important hyperparameters that can significantly affect performance:
param_grid = {
"n_estimators": [50, 100, 200],
"learning_rate": [0.01, 0.1, 0.2],
"max_depth": [3, 5, 7],
"min_samples_split": [2, 5, 10],
"min_samples_leaf": [1, 2, 4],
}
# Use a smaller subset for faster tuning
X_train_small = X_train_class[:500]
y_train_small = y_train_class[:500]
grid_search = GridSearchCV(
GradientBoostingClassifier(random_state=42),
param_grid,
cv=3, # 3-fold CV for faster tuning
scoring="roc_auc",
n_jobs=-1,
)
grid_search.fit(X_train_small, y_train_small)Best parameters:
{'learning_rate': 0.1, 'max_depth': 5, 'min_samples_leaf': 2, 'min_samples_split': 10, 'n_estimators': 50}
Best cross-validation score: 0.654
Test set ROC AUC: 0.621
Key Parameters
Below are some of the main parameters that affect how Gradient Boosting works and performs.
n_estimators: Number of boosting stages (trees) to perform (default: 100). More trees generally improve performance but increase computation time and risk of overfitting. Start with 100 and increase if validation scores improve.learning_rate: Shrinkage parameter that controls the contribution of each tree (default: 0.1). Lower values (0.01-0.1) require more trees but often lead to better generalization. Values between 0.01 and 0.2 work well for most datasets.max_depth: Maximum depth of each tree (default: 3). Controls the complexity of individual trees. Shallow trees (3-5) work well for boosting as they focus on learning simple patterns iteratively.min_samples_split: Minimum samples required to split an internal node (default: 2). Higher values prevent overfitting by requiring more data for splits. Values of 5-10 are commonly used.min_samples_leaf: Minimum samples required in a leaf node (default: 1). Higher values smooth the model and prevent overfitting. Values of 2-4 work well for most problems.subsample: Fraction of samples to use for fitting each tree (default: 1.0). Values less than 1.0 introduce stochastic gradient boosting, which can help prevent overfitting. Try values between 0.5 and 0.8.loss: Loss function to optimize (default: 'log_loss' for classification, 'squared_error' for regression). Different loss functions are appropriate for different problem types.random_state: Seed for reproducibility (default: None). Set to an integer to ensure consistent results across runs.
Key Methods
The following are the most commonly used methods for interacting with Gradient Boosting models.
fit(X, y): Trains the gradient boosting model on the training data X and target values y. Each tree is trained sequentially to correct the errors of previous trees.predict(X): Returns predicted class labels (classification) or values (regression) for input data X by summing predictions from all trees in the ensemble.predict_proba(X): Returns probability estimates for each class (classification only). Useful for setting custom decision thresholds or understanding prediction confidence.score(X, y): Returns the mean accuracy (classification) or R² score (regression) on the given test data.staged_predict(X): Returns predictions at each stage of boosting. Useful for determining the optimal number of trees and implementing early stopping.