Skip to content
learn
  1. Learn
  2. Machine Learning
  3. Trees and Ensembles

Machine Learning ML-06.05

Stacking and blending

Combine different models with a meta-model trained on out-of-fold predictions, why in-sample predictions leak, and when the extra complexity pays.

Advanced 8 min Last reviewed

The big idea

A hospital gets a second opinion from a radiologist, a lab test and a family doctor. Simply averaging them is crude: the radiologist may be excellent on tumours and weak on fractures. A senior physician who has watched all three for years learns how much to trust each one, and when. StackingAn ensemble in which a meta-model is trained to combine the predictions of several different base models, using their predictions as its input features. trains that senior physician: a meta-modelThe second-level model in stacking. Its inputs are the base models' predictions and its output is the final prediction. whose inputs are the predictions of several different base modelsThe first-level models in a stack, usually of different types (linear, trees, neighbours) so their errors differ..

The catch is subtle. If the meta-model learns from predictions the base models made on their own training data, it learns to trust whoever memorised best. Its training data must be predictions on data each base model never saw.

How it works

Step 1: Pick diverse base models

Stacking helps when base models make different mistakes, exactly like bagging. Five gradient boosting models with different seeds add little. A linear model, a k-nearest-neighbours model, a random forest and a boosted model see the data in different ways, so a combiner has something to choose between.

Step 2: Produce out-of-fold predictions

Out-of-fold predictions feed the meta-model Training data is split into five folds. For fold 3, a base model trained on folds 1, 2, 4 and 5 predicts fold 3, writing into the out-of-fold column. Repeating for every fold fills the column with predictions made on unseen rows. Columns from four base models form the meta-features, which train a logistic regression meta-model. The path from held-out fold to meta-model glows. train predict fold 3 training set 5 folds base model fit on folds 1,2,4,5 fold 3 held out out-of-fold column one per base model meta-model logistic regression Figure 1. Every value in the out-of-fold column was predicted by a model that did not train on that row. The meta-model learns from these honest predictions, not from memorised ones.

For each base model, run k-fold cross-validation ( Cross-validation ) and keep every held-out prediction. After k rounds every training row has exactly one out-of-fold predictionA prediction for a training row made by a model that was trained without that row, as in k-fold cross-validation.. Put the columns side by side: that table, plus the true labels, trains the meta-model.

Step 3: Fit the meta-model, then refit the bases

Use a simple meta-model, usually logistic or linear regression, sometimes constrained to non-negative weights. A flexible meta-model on a handful of correlated columns overfits easily. Finally, refit each base model on all the training data; at prediction time, the base models predict and the meta-model combines their predictions.

Step 4: Or blend with a holdout

BlendingA simpler form of stacking: base models train on one part of the data and the meta-model trains on their predictions for a separate holdout part. skips the folds: train bases on, say, 80 percent of the data and fit the meta-model on their predictions for the other 20 percent. It is simpler and leak-proof by construction, but the meta-model learns from fewer rows and the bases see less data.

Going deeper

Code: four models, an average, a leaky stack and an honest one

stacking.pyruns with python3 + numpy + scikit-learn
import numpy as np
from sklearn.datasets import make_classification
from sklearn.ensemble import RandomForestClassifier, HistGradientBoostingClassifier, StackingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import cross_val_predict, train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler

X, y = make_classification(n_samples=2000, n_features=20, n_informative=10, flip_y=0.08, random_state=3)
Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.4, random_state=0)
base = {
    "logistic": make_pipeline(StandardScaler(), LogisticRegression()),
    "kNN (k=15)": make_pipeline(StandardScaler(), KNeighborsClassifier(15)),
    "random forest": RandomForestClassifier(100, random_state=0),
    "boosting": HistGradientBoostingClassifier(random_state=0),
}
oof, insample, test = {}, {}, {}
for name, m in base.items():
    oof[name] = cross_val_predict(m, Xtr, ytr, cv=5, method="predict_proba")[:, 1]
    m.fit(Xtr, ytr)
    insample[name] = m.predict_proba(Xtr)[:, 1]
    test[name] = m.predict_proba(Xte)[:, 1]
    print(f"{name:<14} test AUC {roc_auc_score(yte, test[name]):.4f}")

T = np.column_stack(list(test.values()))
print(f"\nsimple average  test AUC {roc_auc_score(yte, T.mean(1)):.4f}")
for label, Z in [("leaky stack (in-sample preds)", insample), ("stack on out-of-fold preds  ", oof)]:
    meta = LogisticRegression().fit(np.column_stack(list(Z.values())), ytr)
    w = ", ".join(f"{c:+.2f}" for c in meta.coef_[0])
    print(f"{label}: test AUC {roc_auc_score(yte, meta.predict_proba(T)[:, 1]):.4f}, weights [{w}]")

# scikit-learn does the out-of-fold bookkeeping for you
s = StackingClassifier(list(base.items()), final_estimator=LogisticRegression(), cv=5).fit(Xtr, ytr)
print(f"\nStackingClassifier test AUC {roc_auc_score(yte, s.predict_proba(Xte)[:, 1]):.4f}")

Output

logistic       test AUC 0.9049
kNN (k=15)     test AUC 0.9386
random forest  test AUC 0.9430
boosting       test AUC 0.9421

simple average  test AUC 0.9443
leaky stack (in-sample preds): test AUC 0.9454, weights [+0.75, +1.21, +3.93, +5.64]
stack on out-of-fold preds  : test AUC 0.9472, weights [+0.40, +2.68, +2.36, +2.39]

StackingClassifier test AUC 0.9472
Stacking gives a small, real gain when done honestly Test AUC: best single model, the random forest, 0.9430. Simple average of four models 0.9443. Stack trained on in-sample predictions 0.9454. Stack trained on out-of-fold predictions 0.9472, glowing green. test AUC (bars start at zero; the differences are small) best single (forest) 0.9430 simple average 0.9443 leaky stack 0.9454 out-of-fold stack 0.9472 Figure 2. Numbers from the code below. Gains from stacking are typically fractions of a point. Worth it in a competition, often not worth a four-model production pipeline.

Look at the meta-model weights. Trained on in-sample predictions, it puts +5.64 on boosting and +3.93 on the forest, the models that fit their own training data almost perfectly, and only +0.75 on logistic regression. Trained on out-of-fold predictions, the weights are more balanced (+0.40, +2.68, +2.36, +2.39), because it sees how each model actually performs on unseen rows. Here the leak cost only a little; with more flexible base models and a more flexible meta-model it can cost a lot. StackingClassifier gives the same 0.9472 as the hand-written version, because it does the same out-of-fold bookkeeping.

Practical variations

  • Pass-through: give the meta-model the original features as well (passthrough=True), so it can learn that one base model is better for some segments. More power, more overfitting risk.
  • Multi-level stacks: stack the stacks. Common in competitions, rarely justified in production.
  • Time series: out-of-fold predictions must respect time order, using forward-chaining folds ( Backtesting and forecast evaluation ), or the meta-model learns from the future.

Trade-offs

OptionWins whenLoses when
Single best model Production simplicity, latency, debugging Leaves a small amount of accuracy on the table
Simple or weighted average Diverse models of similar quality; almost free Cannot learn which model to trust when
Stacking with out-of-fold predictions Competitions and offline batch scoring where every point counts k times more training, several models to serve and monitor
Blending with a holdout Quick, leak-proof combination Meta-model trains on fewer rows

Common mistakes

  • Training the meta-model on base predictions for rows the bases trained on.
  • Using a deep, flexible meta-model on four correlated columns.
  • Stacking near-identical models and expecting a gain.
  • Reporting the stack's score on the same folds used to build the out-of-fold predictions and to tune the meta-model.
  • Shipping a five-model stack for a 0.2 point gain without counting serving cost and maintenance.

In the wild

Stacking and blending are staples of data science competitions, where winning solutions often combine dozens of models and a fraction of a point decides the ranking. In production, teams more often ship a single strong model or a simple average, because every extra model must be retrained, served, monitored and debugged. Stacking shows up where scoring happens offline in batches and accuracy is worth the cost, such as risk scoring or demand forecasting pipelines.

Check yourself

  1. Why must the meta-model be trained on out-of-fold predictions?

    Show answer

    B. In-sample predictions are overconfident for models that memorise, so the meta-model learns to trust the wrong ones A deep forest predicts its own training rows almost perfectly. A meta-model trained on that would over-trust it; out-of-fold predictions show real performance.

  2. Which set of base models is most likely to benefit from stacking?

    Show answer

    B. Logistic regression, kNN, a random forest and gradient boosting Stacking needs diversity: models that make different mistakes. Different model families provide it.

  3. What is the main difference between blending and stacking?

    Show answer

    A. Blending uses a holdout set for the meta-model; stacking uses out-of-fold predictions over all training rows Blending is the simpler holdout version. Stacking uses every row for the meta-model via cross-validation.

  4. Your stack beats the best single model by 0.2 AUC points and needs four models in production. A reasonable conclusion?

    Show answer

    B. Weigh the gain against serving, retraining and monitoring four models; often ship the single model Stacking's gains are usually small. Whether they pay depends on the value of accuracy versus operational cost.

Recap

  • Stacking trains a meta-model on the predictions of diverse base models.
  • The meta-model's training data must be out-of-fold predictions, never in-sample ones.
  • Keep the meta-model simple: logistic or linear regression is the norm.
  • Blending uses a holdout split instead of folds: simpler, but with less data for each part.
  • Gains are usually small; worth it in competitions and batch scoring, often not in latency-sensitive production.

Get new lessons by email

Get new posts on backend and AI internals. No spam, unsubscribe anytime.

Your email is only used to send new posts. Privacy