Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 45

Building AdaBoost with Weighted Decision Stumps

Recommended resources

Hello! Welcome back to our module on boosting algorithms.

In the last lesson, we laid the groundwork by implementing a DecisionStump from scratch. You learned that this simple, one-level decision tree serves as a "weak learner"—a model that's only slightly better than random chance.

Today, we'll use that building block to construct one of the most famous and influential boosting algorithms. This lesson directly addresses the learning outcome: Implement the AdaBoost algorithm by sequentially training weighted decision stumps.

AdaBoost, short for Adaptive Boosting, is a powerful algorithm that works by training a sequence of weak learners. The "adaptive" part is key: each new stump is forced to pay more attention to the data points that the previous stumps misclassified. We'll implement this clever mechanism from scratch.

The AdaBoost Algorithm: An Overview

The core idea of AdaBoost is to combine many weak learners into a single, strong classifier. It does this iteratively. In each iteration, AdaBoost identifies the mistakes of the current ensemble and "boosts" the importance of the misclassified samples. The next weak learner in the sequence is then trained to focus on these difficult examples.

The process can be visualized as a series of steps:

Steps In Adaboost Algorithm
This image provides a high-level overview of the sequential steps in the AdaBoost algorithm, from initializing weights to combining the weak classifiers into a final strong model.

This process involves two kinds of weights:

  1. Sample Weights (): Each data point in the training set has a weight. Initially, all points are weighted equally. After a weak learner is trained, the weights of misclassified points are increased. This tells the next weak learner: "Pay more attention to these points!"
  2. Classifier Weights (): Each weak learner gets a "say" in the final prediction, determined by its performance. A weak learner with lower error gets a higher value, giving it more influence in the final vote.

The result is a sequence of stumps, each one an expert on the mistakes of its predecessors.

AdaBoost Example with Decision Stumps
This image illustrates the sequence of decision stumps. Imagine each stump being trained on a dataset where the samples misclassified by the previous stumps are given more importance.

The Mathematical Steps of AdaBoost

Let's formalize the algorithm. For a set of classifiers and data points, the process is as follows. You can follow along with a detailed explanation of the theory and formulas in the following video.

AdaBoost in Python - Machine Learning From Scratch 13 - Python Tutorial

The video 'AdaBoost in Python' by Patrick Loeber clearly explains the mathematical formulas that drive the algorithm.

Watch from 03:02 to 08:52. This covers the formulas for error, sample weights, and classifier performance (alpha), and then summarizes the complete training process. Focus on understanding the purpose of each formula, not memorizing it.

Here is a summary of the steps discussed in the video:

  1. Initialize Sample Weights: For each sample , set the initial weight .

  2. For : (Iterate through each weak learner)
    a. Train a Weak Learner (): Find the best decision stump by performing the greedy search we discussed in the last lesson. The "best" stump is the one that minimizes the weighted error.
    b. Calculate Weighted Error (): The error is the sum of the weights of the misclassified samples.

    Where is the indicator function (1 if true, 0 if false).
    c. Calculate Classifier Weight (): This value represents the "say" of the -th classifier.

    A lower error results in a higher .
    d. Update Sample Weights (): Increase the weights of misclassified samples and decrease the weights of correctly classified ones.

    After updating, the weights are normalized so they sum to 1. Notice that if a sample is misclassified, , making the exponent positive and increasing the weight.

  3. Final Prediction: The final prediction is the sign of the weighted sum of all weak learners' predictions.

Test your understanding!

Looking at the formula for , what happens to its value as the weighted error approaches 0? What about when approaches 0.5?

Show answer
  • As (a perfect classifier), the term goes to infinity. The natural log of infinity is also infinity, so . A perfect weak learner gets an infinitely large say.
  • As (a classifier that is no better than random guessing), the term approaches . Since , . A useless classifier gets no say in the final prediction.

Implementing the AdaBoost Class

Now, let's translate these steps into code. We will create an AdaBoost class that uses our DecisionStump from the previous lesson. The implementation will closely follow the structure presented in the resources from Patrick Loeber and Python Engineer.

Your DecisionStump class from the last lesson should look like this. We will use it directly.

# From previous lesson
class DecisionStump:
    def __init__(self):
        self.polarity = 1
        self.feature_idx = None
        self.threshold = None
        self.alpha = None # We will set this in the AdaBoost class

    def predict(self, X):
        n_samples = X.shape[0]
        X_column = X[:, self.feature_idx]
        predictions = np.ones(n_samples)
        if self.polarity == 1:
            predictions[X_column < self.threshold] = -1
        else:
            predictions[X_column > self.threshold] = -1
        return predictions

Now, let's build the main AdaBoost class.

1. The __init__ and fit Methods

The fit method is where the main algorithm lives. It will contain the loop that sequentially creates, trains, and weights our decision stumps.

import numpy as np

class AdaBoost:
    def __init__(self, n_clf=5):
        self.n_clf = n_clf  # The number of weak learners (M)
        self.clfs = []      # List to store the trained stumps

    def fit(self, X, y):
        n_samples, n_features = X.shape

        # Step 1: Initialize weights
        w = np.full(n_samples, (1 / n_samples))
        self.clfs = []

        # Step 2: Iterate through classifiers
        for _ in range(self.n_clf):
            clf = DecisionStump()
            min_error = float('inf')

            # --- Greedy search for the best stump (Step 2a) ---
            # This is the "training" part from our previous lesson
            for feature_i in range(n_features):
                X_column = X[:, feature_i]
                thresholds = np.unique(X_column)
                for threshold in thresholds:
                    p = 1
                    predictions = np.ones(n_samples)
                    predictions[X_column < threshold] = -1
                    
                    # Step 2b: Calculate weighted error
                    misclassified = w[y != predictions]
                    error = sum(misclassified)

                    # A stump better than random guessing has error < 0.5
                    # If error > 0.5, we flip the polarity
                    if error > 0.5:
                        error = 1 - error
                        p = -1

                    if error < min_error:
                        min_error = error
                        clf.polarity = p
                        clf.threshold = threshold
                        clf.feature_idx = feature_i
            # --- End of greedy search ---
            
            # Step 2c: Calculate classifier weight (alpha)
            EPS = 1e-10  # Avoid division by zero
            clf.alpha = 0.5 * np.log((1.0 - min_error + EPS) / (min_error + EPS))

            # Step 2d: Update sample weights
            predictions = clf.predict(X)
            w *= np.exp(-clf.alpha * y * predictions)
            w /= np.sum(w)  # Normalize weights

            # Save the trained classifier
            self.clfs.append(clf)

The video below walks through this exact implementation logic. Watching it will help connect the formulas to the code you see above.

AdaBoost in Python - Machine Learning From Scratch 13 - Python Tutorial

Patrick Loeber now implements the fit method for the AdaBoost class. This is the core of our lesson.

Watch from 13:16 to 24:14. This long segment covers the entire fit method. Pay attention to how the loops find the best stump, how alpha is calculated from min_error, and how the sample weights w are updated and normalized.

2. The predict Method

Once the model is fitted, making a prediction involves getting a weighted vote from every stump in our ensemble and taking the sign of the sum.

    def predict(self, X):
        # Get predictions from all classifiers, weighted by their alpha
        clf_preds = [clf.alpha * clf.predict(X) for clf in self.clfs]
        
        # Sum the weighted predictions
        y_pred = np.sum(clf_preds, axis=0)
        
        # Return the sign of the sum
        y_pred = np.sign(y_pred)
        
        return y_pred

This implementation is a direct translation of the final prediction formula. The following short segment shows its implementation.

AdaBoost in Python - Machine Learning From Scratch 13 - Python Tutorial

The final piece is the predict method, which combines the weak learners' outputs.

Watch from 24:14 to 26:02. See how a list comprehension is used to efficiently calculate the weighted sum of predictions before the final np.sign is applied.

You can also review the complete, clean code in the accompanying article to consolidate your understanding.

AdaBoost in Python - ML From Scratch 13

The article 'AdaBoost in Python' from Python Engineer provides the full source code for the AdaBoost class we have just constructed.

Review the code for the Adaboost class. Compare it with the code we've discussed to ensure you understand how the fit and predict methods work together.


Conclusion

Congratulations! You have now implemented the AdaBoost algorithm from scratch. By combining your DecisionStump weak learner with a clever weighting scheme, you've built a powerful classifier.

Key Takeaways:

  • AdaBoost is an adaptive boosting algorithm that trains weak learners sequentially.
  • Sample weights are used to make the algorithm focus on data points that were previously misclassified.
  • The classifier weight () is calculated based on the weak learner's weighted error and determines its influence on the final prediction.
  • The fit method involves an outer loop for the number of classifiers and an inner set of loops to find the best stump for the current sample weights.
  • The predict method computes a weighted sum of the predictions from all stored weak learners and returns the sign.

Preview of the Next Lesson:
AdaBoost is a brilliant algorithm, but its derivation is tied to a specific loss function (the exponential loss). What if we wanted to use this "boosting" idea for other problems, like regression with Mean Squared Error?

In the next lesson, we will take the first step towards a more general boosting framework called Gradient Boosting. You will learn to calculate pseudo-residuals for a regression loss function. These residuals represent the "errors" that the next weak learner should try to fit, and you'll see that they are directly related to the gradient of the loss function—connecting back to the central theme of our course.