---
title: Ensemble Models
date: 2025-09-12T07:35:42Z
modified: 2026-07-11T16:47:44Z
permalink: "https://www.micheledpierri.com/machine-learning/ensemble-models/"
type: page
status: publish
excerpt: ""
wpid: 1519
featured_image: "https://www.micheledpierri.com/wp-content/uploads/2026/07/ml_ensemble_.png"
featured_image_alt: A young boy in rustic clothing stands in an autumn forest, gazing upward in wonder as warm golden light filters through the trees.
timestamp: 2026-07-11T16:47:44Z
tags: []
---

## Introduction

Ensemble models are machine learning models that combine predictions from simpler, less powerful models to achieve better results. This approach works because combining multiple models helps reduce both bias and variance, leading to better generalization performance.

## Types of Ensemble Models

Ensemble models come in several types:

### Bagging (bootstrap aggregating)

Creates random subsets of the dataset, processes them through an algorithm (typically a Decision Tree), and then combines the results.

### Boosting

Trains models sequentially, with each new model correcting errors from the previous one.

### Stacking

Combines outputs from different models into a “meta-classifier” model, such as logistic regression.

### Voting

Uses predictions from multiple models, either by selecting the most-voted class (hard voting) or averaging probability scores (soft voting).

Ensemble models work best with noisy or complex datasets where overfitting and bias are likely, and when robust predictions are essential.

However, these models require significant computational resources and can be difficult to interpret.

## Bagging in Ensemble Models

Bagging consists of three main steps:

- Bootstrapping: Creating random subsets of the original dataset, each approximately the same size as the original through data duplication and removal.
- Model Training: Training a separate model (typically a Decision Tree) on each subset.
- Result Aggregation: Combining the predictions from all models—using majority voting for classification tasks or averaging the results for regression tasks.

Bagging effectively reduces variance and prevents overfitting, though it has minimal impact on bias.

Random Forest is the most widely recognized implementation of bagging.

## Boosting in Ensemble Models

Unlike bagging, boosting applies models in sequence. Each subsequent model works to correct errors made by previous models, with the final prediction being an average across all models.

Boosting models offer a key advantage: they can reduce variance and bias.

However, they require more complex implementation than bagging models.

The most prominent boosting algorithms include AdaBoost, Gradient Boosting, XGBoost, LightGBM, and CatBoost.



| BAGGING | BOOSTING |  |
| --- | --- | --- |
| **Training** | **Models trained independently** | **Models trained sequentially** |
| **Error focus** | **No special attention to errors** | **Focuses on previous errors** |
| **Complexity** | **Less complex** | **More complex** |
| **Overfitting risk** | **Low** | **Moderate/high** |

![Illustration of bagging and boosting methods](https://www.micheledpierri.com/wp-content/uploads/2025/09/bagboscol-1024x502.png)

## Using Bagging and Boosting in Python

In this example, we’ll create a synthetic dataset containing two classes with non-linear distributions. We’ll implement bagging with a Random Forest model and boosting with an AdaBoost model, then visualize the decision boundaries for both approaches.

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_moons
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier, AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier
from mlxtend.plotting import plot_decision_regions

# Generate synthetic dataset
X, y = make_moons(n_samples=400, noise=0.25, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# Bagging model (Random Forest)
bagging_model = RandomForestClassifier(n_estimators=50, random_state=42)
bagging_model.fit(X_train, y_train)

# Boosting model (AdaBoost)
boosting_model = AdaBoostClassifier(estimator=DecisionTreeClassifier(max_depth=1), 
                                    n_estimators=50, random_state=42)
boosting_model.fit(X_train, y_train)

# Function to plot decision boundaries side by side
def plot_side_by_side_decision_boundaries(model1, model2, title1, title2):
    fig, axes = plt.subplots(1, 2, figsize=(16, 6))  # Create a figure with 2 subplots side by side

    # Plot first model (Bagging)
    plot_decision_regions(X, y, clf=model1, ax=axes[0], legend=2)
    axes[0].set_title(title1)
    axes[0].set_xlabel("Feature 1")
    axes[0].set_ylabel("Feature 2")

    # Plot second model (Boosting)
    plot_decision_regions(X, y, clf=model2, ax=axes[1], legend=2)
    axes[1].set_title(title2)
    axes[1].set_xlabel("Feature 1")
    axes[1].set_ylabel("Feature 2")

    plt.tight_layout()  # Optimize space between subplots
    plt.show()

# Plot decision boundaries side by side
plot_side_by_side_decision_boundaries(
    bagging_model, boosting_model,
    "Decision Boundary - Bagging (Random Forest)",
    "Decision Boundary - Boosting (AdaBoost)"
)```
<span class="line"><span style="color: #FF79C6">import</span><span style="color: #F8F8F2"> numpy </span><span style="color: #FF79C6">as</span><span style="color: #F8F8F2"> np</span></span>
<span class="line"><span style="color: #FF79C6">import</span><span style="color: #F8F8F2"> matplotlib.pyplot </span><span style="color: #FF79C6">as</span><span style="color: #F8F8F2"> plt</span></span>
<span class="line"><span style="color: #FF79C6">from</span><span style="color: #F8F8F2"> sklearn.datasets </span><span style="color: #FF79C6">import</span><span style="color: #F8F8F2"> make_moons</span></span>
<span class="line"><span style="color: #FF79C6">from</span><span style="color: #F8F8F2"> sklearn.model_selection </span><span style="color: #FF79C6">import</span><span style="color: #F8F8F2"> train_test_split</span></span>
<span class="line"><span style="color: #FF79C6">from</span><span style="color: #F8F8F2"> sklearn.ensemble </span><span style="color: #FF79C6">import</span><span style="color: #F8F8F2"> RandomForestClassifier, AdaBoostClassifier</span></span>
<span class="line"><span style="color: #FF79C6">from</span><span style="color: #F8F8F2"> sklearn.tree </span><span style="color: #FF79C6">import</span><span style="color: #F8F8F2"> DecisionTreeClassifier</span></span>
<span class="line"><span style="color: #FF79C6">from</span><span style="color: #F8F8F2"> mlxtend.plotting </span><span style="color: #FF79C6">import</span><span style="color: #F8F8F2"> plot_decision_regions</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6272A4"># Generate synthetic dataset</span></span>
<span class="line"><span style="color: #F8F8F2">X, y </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> make_moons(</span><span style="color: #FFB86C; font-style: italic">n_samples</span><span style="color: #FF79C6">=</span><span style="color: #BD93F9">400</span><span style="color: #F8F8F2">, </span><span style="color: #FFB86C; font-style: italic">noise</span><span style="color: #FF79C6">=</span><span style="color: #BD93F9">0.25</span><span style="color: #F8F8F2">, </span><span style="color: #FFB86C; font-style: italic">random_state</span><span style="color: #FF79C6">=</span><span style="color: #BD93F9">42</span><span style="color: #F8F8F2">)</span></span>
<span class="line"><span style="color: #F8F8F2">X_train, X_test, y_train, y_test </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> train_test_split(X, y, </span><span style="color: #FFB86C; font-style: italic">test_size</span><span style="color: #FF79C6">=</span><span style="color: #BD93F9">0.3</span><span style="color: #F8F8F2">, </span><span style="color: #FFB86C; font-style: italic">random_state</span><span style="color: #FF79C6">=</span><span style="color: #BD93F9">42</span><span style="color: #F8F8F2">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6272A4"># Bagging model (Random Forest)</span></span>
<span class="line"><span style="color: #F8F8F2">bagging_model </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> RandomForestClassifier(</span><span style="color: #FFB86C; font-style: italic">n_estimators</span><span style="color: #FF79C6">=</span><span style="color: #BD93F9">50</span><span style="color: #F8F8F2">, </span><span style="color: #FFB86C; font-style: italic">random_state</span><span style="color: #FF79C6">=</span><span style="color: #BD93F9">42</span><span style="color: #F8F8F2">)</span></span>
<span class="line"><span style="color: #F8F8F2">bagging_model.fit(X_train, y_train)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6272A4"># Boosting model (AdaBoost)</span></span>
<span class="line"><span style="color: #F8F8F2">boosting_model </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> AdaBoostClassifier(</span><span style="color: #FFB86C; font-style: italic">estimator</span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2">DecisionTreeClassifier(</span><span style="color: #FFB86C; font-style: italic">max_depth</span><span style="color: #FF79C6">=</span><span style="color: #BD93F9">1</span><span style="color: #F8F8F2">), </span></span>
<span class="line"><span style="color: #F8F8F2">                                    </span><span style="color: #FFB86C; font-style: italic">n_estimators</span><span style="color: #FF79C6">=</span><span style="color: #BD93F9">50</span><span style="color: #F8F8F2">, </span><span style="color: #FFB86C; font-style: italic">random_state</span><span style="color: #FF79C6">=</span><span style="color: #BD93F9">42</span><span style="color: #F8F8F2">)</span></span>
<span class="line"><span style="color: #F8F8F2">boosting_model.fit(X_train, y_train)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6272A4"># Function to plot decision boundaries side by side</span></span>
<span class="line"><span style="color: #FF79C6">def</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B">plot_side_by_side_decision_boundaries</span><span style="color: #F8F8F2">(</span><span style="color: #FFB86C; font-style: italic">model1</span><span style="color: #F8F8F2">, </span><span style="color: #FFB86C; font-style: italic">model2</span><span style="color: #F8F8F2">, </span><span style="color: #FFB86C; font-style: italic">title1</span><span style="color: #F8F8F2">, </span><span style="color: #FFB86C; font-style: italic">title2</span><span style="color: #F8F8F2">):</span></span>
<span class="line"><span style="color: #F8F8F2">    fig, axes </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> plt.subplots(</span><span style="color: #BD93F9">1</span><span style="color: #F8F8F2">, </span><span style="color: #BD93F9">2</span><span style="color: #F8F8F2">, </span><span style="color: #FFB86C; font-style: italic">figsize</span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2">(</span><span style="color: #BD93F9">16</span><span style="color: #F8F8F2">, </span><span style="color: #BD93F9">6</span><span style="color: #F8F8F2">))  </span><span style="color: #6272A4"># Create a figure with 2 subplots side by side</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #6272A4"># Plot first model (Bagging)</span></span>
<span class="line"><span style="color: #F8F8F2">    plot_decision_regions(X, y, </span><span style="color: #FFB86C; font-style: italic">clf</span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2">model1, </span><span style="color: #FFB86C; font-style: italic">ax</span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2">axes[</span><span style="color: #BD93F9">0</span><span style="color: #F8F8F2">], </span><span style="color: #FFB86C; font-style: italic">legend</span><span style="color: #FF79C6">=</span><span style="color: #BD93F9">2</span><span style="color: #F8F8F2">)</span></span>
<span class="line"><span style="color: #F8F8F2">    axes[</span><span style="color: #BD93F9">0</span><span style="color: #F8F8F2">].set_title(title1)</span></span>
<span class="line"><span style="color: #F8F8F2">    axes[</span><span style="color: #BD93F9">0</span><span style="color: #F8F8F2">].set_xlabel(</span><span style="color: #E9F284">"</span><span style="color: #F1FA8C">Feature 1</span><span style="color: #E9F284">"</span><span style="color: #F8F8F2">)</span></span>
<span class="line"><span style="color: #F8F8F2">    axes[</span><span style="color: #BD93F9">0</span><span style="color: #F8F8F2">].set_ylabel(</span><span style="color: #E9F284">"</span><span style="color: #F1FA8C">Feature 2</span><span style="color: #E9F284">"</span><span style="color: #F8F8F2">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #6272A4"># Plot second model (Boosting)</span></span>
<span class="line"><span style="color: #F8F8F2">    plot_decision_regions(X, y, </span><span style="color: #FFB86C; font-style: italic">clf</span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2">model2, </span><span style="color: #FFB86C; font-style: italic">ax</span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2">axes[</span><span style="color: #BD93F9">1</span><span style="color: #F8F8F2">], </span><span style="color: #FFB86C; font-style: italic">legend</span><span style="color: #FF79C6">=</span><span style="color: #BD93F9">2</span><span style="color: #F8F8F2">)</span></span>
<span class="line"><span style="color: #F8F8F2">    axes[</span><span style="color: #BD93F9">1</span><span style="color: #F8F8F2">].set_title(title2)</span></span>
<span class="line"><span style="color: #F8F8F2">    axes[</span><span style="color: #BD93F9">1</span><span style="color: #F8F8F2">].set_xlabel(</span><span style="color: #E9F284">"</span><span style="color: #F1FA8C">Feature 1</span><span style="color: #E9F284">"</span><span style="color: #F8F8F2">)</span></span>
<span class="line"><span style="color: #F8F8F2">    axes[</span><span style="color: #BD93F9">1</span><span style="color: #F8F8F2">].set_ylabel(</span><span style="color: #E9F284">"</span><span style="color: #F1FA8C">Feature 2</span><span style="color: #E9F284">"</span><span style="color: #F8F8F2">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F8F8F2">    plt.tight_layout()  </span><span style="color: #6272A4"># Optimize space between subplots</span></span>
<span class="line"><span style="color: #F8F8F2">    plt.show()</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6272A4"># Plot decision boundaries side by side</span></span>
<span class="line"><span style="color: #F8F8F2">plot_side_by_side_decision_boundaries(</span></span>
<span class="line"><span style="color: #F8F8F2">    bagging_model, boosting_model,</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #E9F284">"</span><span style="color: #F1FA8C">Decision Boundary - Bagging (Random Forest)</span><span style="color: #E9F284">"</span><span style="color: #F8F8F2">,</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #E9F284">"</span><span style="color: #F1FA8C">Decision Boundary - Boosting (AdaBoost)</span><span style="color: #E9F284">"</span></span>
<span class="line"><span style="color: #F8F8F2">)</span></span>
```

![Decision boundaries applying bagging and bosting models](https://www.micheledpierri.com/wp-content/uploads/2025/09/bagging_boosting_comparison-1024x384.png)

The decision boundary of the bagging model appears smoother and less detailed than the boosting model’s boundary. While bagging may miss some complex patterns, boosting runs the risk of overfitting to noise in the data.

## Conclusions

Ensemble models combine multiple “weak” machine learning algorithms to create stronger predictions. Among the various combination techniques, bagging and boosting are the most widely used. Choosing between bagging and boosting depends on your problem’s specific goals and dataset characteristics. Choose bagging when robustness and generalization are priorities. Opt for boosting when you need high performance on complex data—just be mindful of potential overfitting.