liveBook · Manning

Naive bayes classifier

As explained in LLMs in Production

A naive Bayes classifier is a probabilistic classification model that applies Bayes' theorem while assuming conditional independence among features given the class.

A naive Bayes classifier turns text into class probabilities rather than generated language. It applies Bayes' theorem to choose among hypotheses, making it useful for classification and as an augmentation component around generative language systems. section 2.2.2

The naive version is deliberately simple: it treats observed word sequences as disconnected, much like bag-of-words models. That simplicity can make the implementation clear, but it discards sequence relationships and can limit effectiveness; multinomial extensions and other improvements may perform better for particular problems. section 2.2.2

Classifying text with word-label counts

A categorical implementation processes utterances, pairs each word with its class label, and counts those pairs. The listing uses sentences from Hamlet and binary sentiment labels, illustrating how class-associated word frequencies provide the evidence for classification. section 2.2.2

Listing 2.2 Categorical naive Bayes language model implementation
from utils import process_utt, lookup
from nltk.corpus.reader import PlaintextCorpusReader
import numpy as np

my_corpus = PlaintextCorpusReader("./", ".*\.txt")

sents = my_corpus.sents(fileids="hamlet.txt")


def count_utts(result, utts, ys):
    """
    Input:
        result: a dictionary that is used to map each pair to its frequency
        utts: a list of utts
        ys: a list of the sentiment of each utt (either 0 or 1)
    Output:
        result: a dictionary mapping each pair to its frequency
    """

    for y, utt in zip(ys, utts):
        for word in process_utt(utt):
            pair = (word, y)          #1

            if pair in result:
            result[pair] += 1     #2

            else:
            result[pair] = 1      #3

    return result


result = {}
utts = [" ".join(sent) for sent in sents]
ys = [sent.count("be") > 0 for sent in sents]
count_utts(result, utts, ys)

freqs = count_utts({}, utts, ys)
lookup(freqs, "be", True)
for k, v in freqs.items():
    if "be" in k:
        print(f"{k}:{v}")


def train_naive_bayes(freqs, train_x, train_y):
    """
    Input:
        freqs: dictionary from (word, label) to how often the word appears
        train_x: a list of utts
        train_y: a list of labels correponding to the utts (0,1)
    Output:
        logprior: the log prior.
        loglikelihood: the log likelihood of you Naive bayes equation.
    """
    loglikelihood = {}
    logprior = 0

    vocab = set([pair[0] for pair in freqs.keys()])      #4
    V = len(vocab)

    N_pos = N_neg = 0                  #5
    for pair in freqs.keys():
        if pair[1] > 0:                   #6
            N_pos += lookup(freqs, pair[0], True)     #7

        else:                                         #8
            N_neg += lookup(freqs, pair[0], False)     #9

    D = len(train_y)     #10

    D_pos = sum(train_y)      #11

    D_neg = D - D_pos     #12

    logprior = np.log(D_pos) - np.log(D_neg)      #13

    for word in vocab:                        #14
        freq_pos = lookup(freqs, word, 1)
        freq_neg = lookup(freqs, word, 0)

        p_w_pos = (freq_pos + 1) / (N_pos + V)    #15
        p_w_neg = (freq_neg + 1) / (N_neg + V)

        loglikelihood[word] = np.log(p_w_pos / p_w_neg)     #16

    return logprior, loglikelihood


def naive_bayes_predict(utt, logprior, loglikelihood):
    """
    Input:
        utt: a string
        logprior: a number
        loglikelihood: a dictionary of words mapping to numbers
    Output:
        p: the sum of all the logliklihoods + logprior
    """
    word_l = process_utt(utt)     #17

    p = 0          #18

    p += logprior      #19

    for word in word_l:
        if word in loglikelihood:       #20
            p += loglikelihood[word]      #21

    return p


def test_naive_bayes(test_x, test_y, logprior, loglikelihood):
    """
    Input:
        test_x: A list of utts
        test_y: the corresponding labels for the list of utts
        logprior: the logprior
        loglikelihood: a dictionary with the loglikelihoods for each word
    Output:
        accuracy: (# of utts classified correctly)/(total # of utts)
    """
    accuracy = 0       #22

    y_hats = []
    for utt in test_x:
        if naive_bayes_predict(utt, logprior, loglikelihood) > 0:    #23
            y_hat_i = 1    #24
        else:
            y_hat_i = 0    #25

        y_hats.append(y_hat_i)      #26

    error = sum(
        [abs(y_hat - test) for y_hat, test in zip(y_hats, test_y)]
    ) / len(y_hats)                 #27

    accuracy = 1 - error    #28

    return accuracy


if __name__ == "__main__":
    logprior, loglikelihood = train_naive_bayes(freqs, utts, ys)
    print(logprior)
    print(len(loglikelihood))

    my_utt = "To be or not to be, that is the question."
    p = naive_bayes_predict(my_utt, logprior, loglikelihood)
    print("The expected output is", p)

    print(
        f"Naive Bayes accuracy = {test_naive_bayes(utts, ys, logprior, loglikelihood):0.4f}
    )

Inspect the hand-written categorical implementation to follow corpus loading, utterance processing, label pairing, and frequency counting without hiding the mechanics behind a machine-learning package. section 2.2.2

How LLMs in Production covers it

How deep it goes
Implements the least-complex form and counts word-label pairs, while deferring multinomial and other enhancements.
Examples
Uses Hamlet sentences, binary sentiment labels, and a hand-written categorical word-frequency implementation.
What it assumes
Places the classifier within NLP and language-modeling history while introducing its classification role and implementation pattern.
What you can do after
Apply it via a hand-written categorical implementation that counts word-label frequencies for text classification.
How it connects
Contrasts disconnected bag-of-words assumptions with N-grams and Markov chains, and supports generative language model augmentation.

Also explained in

Compare how 5 books explain naive bayes classifier →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of LLMs in Production. The section links point to the parts of the book it draws on.