Skip to main content

Welcome to a Grasp lesson

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

Lesson 5

Gaussian Naive Bayes Training From Scratch

Recommended resources

Welcome to the next step in our journey through probabilistic machine learning. In previous lessons, we explored different ways to estimate model parameters, from the frequentist approach of Maximum Likelihood Estimation (MLE) to the Bayesian methods of MAP and using conjugate priors. Today, we will use these foundational ideas to build our first complete probabilistic classification algorithm: Gaussian Naive Bayes.

Your goal for this lesson is to implement the training logic for a Gaussian Naive Bayes classifier from scratch. This will involve understanding the model's assumptions and then translating the mathematical steps for learning its parameters directly into Python code. This process of moving from theory to implementation is central to your goal of gaining a deeper, more practical understanding of ML models.

From Bayes' Theorem to a "Naive" Classifier

At its core, the Naive Bayes classifier uses Bayes' theorem to determine the most probable class for a given data point. For a data point with features and a set of possible classes , we want to find the class that maximizes the posterior probability .

According to Bayes' theorem:

Since is the same for all classes, we can ignore it for comparison and focus on the numerator:

The "naive" part of the algorithm is a crucial simplifying assumption: it assumes that all features are conditionally independent given the class . This allows us to break down the complex likelihood term into a simple product:

This assumption is rarely true in reality (for example, in a medical dataset, height and weight are not independent), but it makes the model computationally efficient and surprisingly effective.

The following video provides an excellent mathematical walkthrough of this entire framework, from Bayes' theorem to the naive assumption and the introduction of the Gaussian model.

Gaussian Naive Bayes From Scratch in Python (Mathematical)

This video from the NeuralNine channel, "Gaussian Naive Bayes From Scratch in Python," breaks down the theory behind the algorithm.

Watch the theoretical explanation from the beginning. Pay close attention to how Bayes' theorem is adapted for classification, the meaning of the "naive" independence assumption, and how the Gaussian distribution is introduced to model the likelihood P(x_i|C_k).


The "Gaussian" Assumption and the "Training" Process

The classifier we are building is specifically a Gaussian Naive Bayes. This means we assume that for each class , the values of any continuous feature are distributed according to a Gaussian (Normal) distribution.

This image visualizes the core idea. For a new data point 'x', we calculate its probability of occurring under the Gaussian distribution for Class A, \(p(x|A)\), and under the Gaussian for Class B, \(p(x|B)\). These are our likelihoods.

Therefore, to model the likelihood , we just need the parameters of the corresponding Gaussian distribution: its mean and its variance .

This brings us to the "training" phase. For a Naive Bayes classifier, training is not an iterative optimization process like gradient descent. Instead, it is a straightforward process of calculating and storing the parameters that define our model directly from the training data. These parameters are:

  1. Class Priors : The overall probability of each class.
  2. Class-conditional Means : The mean of each feature for each class .
  3. Class-conditional Variances : The variance of each feature for each class .

How do we estimate these? We use the same principle we saw in our second lesson: Maximum Likelihood Estimation (MLE).

[PDF] Chapter 5 - Naive Bayes

This document provides the formal derivation for the parameter estimates in Gaussian Naive Bayes.

Please read the section "Gaussian Naive Bayes" on page 46. Focus on the formula for the mean, \hat{\mu}_{j,k}, and the subsequent formula for the sample variance, \hat{\sigma}_{j,k}.

As you can see from the reading, the MLE estimates are exactly what you would intuitively expect:

  • The prior is the frequency of class in the dataset:
  • The mean is simply the average of feature for all samples that belong to class .
  • The variance is the variance of feature for all samples that belong to class .

This is the entire training logic. We will now implement this in Python.


Implementing the Training Logic from Scratch

We will structure our implementation as a Python class with a fit method, similar to the convention used in scikit-learn. The fit method will take the training data X and labels y and perform the three calculations we just discussed, storing the results in the object's attributes.

The following reading provides a clear, step-by-step implementation. We will focus only on the training logic today.

Hands-On Naive Bayes -part 1: Implement Gaussian Classifier Without Scikit-Learn | by Vighneshwarraobandaru | Python in Plain English

This article provides a complete from-scratch implementation of Gaussian Naive Bayes. We will analyze the code for the training phase.

First, read through the high-level plan in the section "Gaussian Naive Bayes Implementation from Scratch". This gives a great overview. Then, carefully study the Python code provided in Steps 1, 2, and 3.

Let's break down the logic from the article.

  1. Initialization: The fit method starts by identifying the unique classes and getting the number of samples and features. It then prepares empty NumPy arrays (self.means, self.variances, self.priors) to store the parameters we will calculate.

  2. Iterating Over Classes: The core of the method is a loop that iterates through each unique class c.

  3. Calculating Parameters for each Class: Inside the loop, for each class c:

    • It first isolates all the data points X_c that belong to that class.
    • It calculates the prior probability for class c by dividing the number of samples in X_c by the total number of samples.
    • It calculates the mean of each feature for the data X_c (using .mean(axis=0)). This gives us the vector of means .
    • It calculates the variance of each feature for the data X_c (using .var(axis=0)). This gives us the vector of variances .

After the loop finishes, the self.priors, self.means, and self.variances attributes are fully populated. The "training" is complete!

Here is a Python class stub that encapsulates this logic, closely following the structure from the resources.

import numpy as np

class NaiveBayes:
    def fit(self, X, y):
        n_samples, n_features = X.shape
        self._classes = np.unique(y)
        n_classes = len(self._classes)




        # 1. Initialize arrays for parameters
        self._means = np.zeros((n_classes, n_features), dtype=np.float64)
        self._variances = np.zeros((n_classes, n_features), dtype=np.float64)
        self._priors = np.zeros(n_classes, dtype=np.float64)




        # 2. Loop through each class
        for idx, c in enumerate(self._classes):



            # Get all samples for the current class
            X_c = X[y == c]




            # 3. Calculate and store parameters
            self._means[idx, :] = X_c.mean(axis=0)
            self._variances[idx, :] = X_c.var(axis=0)
            self._priors[idx] = X_c.shape[0] / float(n_samples)

This fit method perfectly executes the training logic required by our learning outcome. It computes all the necessary statistical properties from the training data and saves them. These stored parameters now represent our "trained model."


Conclusion

In this lesson, you have learned how to construct the training logic for a Gaussian Naive Bayes classifier. We've seen how this algorithm, despite its "naive" assumption of feature independence, provides a powerful and efficient way to perform classification by modeling feature likelihoods with Gaussian distributions.

Key Takeaways:

  • Naive Bayes uses Bayes' theorem to find the most probable class for a new data point.
  • The "naive" assumption is that all features are conditionally independent given the class, which simplifies the likelihood calculation to a product of individual probabilities.
  • The "Gaussian" part means we model the probability of each continuous feature within a class, , using a Gaussian distribution.
  • "Training" a GNB classifier means calculating and storing three sets of parameters from the data: the prior probability of each class, and the mean and variance of each feature for each class.
  • These parameters are estimated using Maximum Likelihood Estimation, connecting directly back to our earlier lessons on parameter estimation.

In our next lesson, we will complete our classifier by implementing the prediction logic. We will use the priors, means, and variances we've just learned to calculate the posterior probability for new, unseen data points and make our final classification.