Naive Bayes for Text
Imagine sorting ten thousand emails into "spam" and "not spam." There are no labeled examples of tomorrow's spam. A classifier must generalize from word patterns alone. It decides on the fly whether "viagra" and "free money now" carry more evidence than "meeting" and "attached invoice." Naive Bayes for Text solves this by turning classification into a probability calculation. It multiplies how surprising each word is under each candidate label. Then it picks the label that makes the observed words least surprising overall. This idea matters because it is the simplest instance of a pattern that recurs throughout NLP. Build a generative story for how data is produced. Then use Bayes' rule to invert that story and infer the hidden label. Naive Bayes classifiers still power real spam filters, sentiment baselines, and language-identification tools. They are fast to train and need almost no tuning. They also remain surprisingly competitive on short, high-dimensional text, where more complex models overfit. The big picture is that Naive Bayes trades a false assumption for enormous computational simplicity. That assumption is that words are conditionally independent given the class. Estimating a full joint distribution over vocabulary-sized feature vectors is intractable. Assuming independence collapses that joint into a product of easy one-dimensional estimates. The assumption is almost always wrong, since words are correlated. Yet the classifier's decisions are often right. Classification only needs the correct label to win the probability race. It does not need an accurate probability estimate. This article builds the model from Bayes' rule up. It gives the exact training and inference algorithms with worked pseudocode. It derives the smoothing correction that prevents zero-probability catastrophes. It traces a complete numeric example. Finally, it connects the generative-model perspective forward to Hidden Markov Models. These models extend this same "independent emissions given a hidden state" idea across a sequence.
- Naive Bayes classifies text by picking the class that maximizes .
- The "naive" conditional independence assumption lets a full joint distribution collapse into simple word-count statistics.
- Training is just counting: class priors and per-word likelihoods from labeled documents, using the Bag-of-Words Model representation.
- Laplace (add-one) smoothing prevents any unseen word from zeroing out an entire class's probability.
- Inference works in log-space to avoid numerical underflow from multiplying thousands of small probabilities.
- Despite its wrong independence assumption, Naive Bayes is fast, robust on small data, and a standard baseline in Text Classification Fundamentals.
Naive Bayes turns text classification into counting: it picks the class whose word-by-word "generation story" makes the observed document least surprising, assuming words appear independently given the class.
The idea
A Naive Bayes classifier is a probabilistic model that assigns a document to the class maximizing the posterior probability , where is the document. By Bayes' rule,
Since is the same for every candidate class, classification only requires comparing across classes — the denominator can be dropped entirely. is the prior, the overall frequency of class in the training data. is the likelihood, the probability the model assigns to generating exactly this document under class . The likelihood term is where the "naive" assumption enters. Representing as a bag-of-words sequence of tokens , the model assumes each word's occurrence is conditionally independent of every other word, given the class:
This is false in general — "not" and "good" are strongly correlated in sentiment text — but it converts an intractable joint distribution over exponentially many word combinations into (vocabulary size) independent one-dimensional distributions, each estimable from simple word counts. The full decision rule, called the Maximum A Posteriori (MAP) class, is:
Two design choices complete the model. First, the multinomial event model treats a document as a sequence of word draws from a per-class die with faces, so word frequency matters — a word appearing three times contributes three factors. This is the standard choice for text and the one developed below. An alternative, the Bernoulli event model, only asks whether each vocabulary word is present or absent, ignoring repeat counts; it tends to work better on very short documents. Second, because every is a fraction less than one, the product over a long document underflows floating-point precision, which is why real implementations always work in log-space, turning the product into a sum of log-probabilities.
How it works
Training estimates two sets of parameters from labeled data: class priors and word likelihoods. For each class , the prior is the fraction of training documents labeled :
For each word and class , the likelihood is estimated by counting how often occurs across all documents labeled , relative to the total word count in class :
This raw maximum-likelihood estimate has a fatal flaw: if a word never appears in class 's training documents, , and because the model multiplies probabilities, a single zero factor forces the entire class likelihood to zero — no matter how strongly every other word favors . Laplace (add-one) smoothing fixes this by pretending every vocabulary word was seen one extra time in every class:
The in the denominator is required so the smoothed probabilities still sum to one over the vocabulary — adding 1 to every one of the numerators must be balanced by adding to the shared denominator. At test time, an unseen document is tokenized, out-of-vocabulary words are dropped (the model has no parameters for them), and the remaining words are scored against every class using log-probabilities, and the arg-max class is returned. ``` // ---------- TRAINING ---------- function TRAIN_NAIVE_BAYES(documents, labels, classes): V := set of all distinct words seen in documents // vocabulary N_total := number of documents for each class c in classes: N_c := number of documents with label c logprior[c] := log(N_c / N_total) // concatenate all class-c documents into one "mega-document" text_c := concatenation of documents where label == c for each word w in V: count[w][c] := number of occurrences of w in text_c total_c := sum over w in V of count[w][c] for each word w in V: // Laplace smoothing: +1 numerator, +|V| denominator loglikelihood[w][c] := log( (count[w][c] + 1) / (total_c + |V|) ) return logprior, loglikelihood, V // ---------- INFERENCE ---------- function PREDICT(doc, classes, logprior, loglikelihood, V): best_class := null best_score := -infinity for each class c in classes: score := logprior[c] for each word w in TOKENIZE(doc): if w in V: // ignore out-of-vocabulary words score := score + loglikelihood[w][c] // else: skip — no evidence for or against any class if score > best_score: best_score := score best_class := c return best_class ``` Note the invariant maintained by training: after smoothing, for every class , since
This guarantees each class's likelihood model is a genuine probability distribution over the vocabulary, not merely a scoring heuristic.
Complexity & correctness
Training time is , where is the number of training documents and is the average document length, since each word token requires a single increment to a count table; the smoothing pass afterward touches every (word, class) pair once, adding . Total training time is , linear in the size of the corpus — no iterative optimization, no gradient descent, no convergence loop. This is a major practical advantage over discriminative alternatives like logistic regression, which require multiple passes over the data to converge.
Training space is to store the likelihood table, plus for priors — the model size depends only on vocabulary and class count, not on the number of training documents, so it does not grow as more data arrives (only the counts inside the table become more accurate).
Inference time per document is , where is the length of the test document, since the algorithm performs one table lookup and addition per word per class. This is a single linear pass with no search, making Naive Bayes attractive for high-throughput filtering systems.
Correctness argument. The MAP decision rule is provably Bayes-optimal — it minimizes expected classification error — if the model's assumed joint distribution equals the true data-generating distribution . The independence assumption is the model's only approximation; everything else (Bayes' rule, arg-max decision) is exact probability theory. The practical claim is weaker but still meaningful: even when features are correlated, the arg-max decision can remain correct as long as the ranking of classes by score is preserved, because classification only needs the correct class to have the highest score, not an accurate probability value. This explains empirically why Naive Bayes performs far better as a classifier than its probability estimates would suggest — the miscalibration from ignoring correlation often biases all classes' scores in a similar direction, leaving the relative ranking intact.
Honest tradeoffs. Correlated features that consistently co-occur get double-counted — if "not" and "good" always appear together in negative reviews, the model effectively counts that evidence twice, overconfidently favoring whichever class that pair supports. Naive Bayes also produces poorly calibrated probability estimates (often extremely close to 0 or 1) even when its class decisions are accurate, so its raw probability outputs should not be trusted as confidence scores without recalibration. On large datasets with abundant training examples, discriminative classifiers that model directly (e.g., logistic regression, or later, neural classifiers) typically overtake Naive Bayes in accuracy, because they can adjust for feature correlations that Naive Bayes cannot represent. Naive Bayes's advantage is sharpest precisely when training data is scarce, since it needs only simple counts and never overfits the way a high-parameter discriminative model can.
Worked example
Consider a two-class sentiment task with a tiny training set (following the standard textbook-style illustration used to sanity-check implementations):
| Document | Words | Class |
|---|---|---|
| "just plain boring" | − | |
| "entirely predictable and lacks energy" | − | |
| "no surprises and very few laughs" | − | |
| "very powerful" | + | |
| "the most fun film of the summer" | + |
Vocabulary (unique words across all documents, 20 words); class counts: , , .
Priors:
Suppose the negative-class mega-document has 14 word tokens and the positive-class mega-document has 9 word tokens (small numbers chosen for hand-tracing). With :
Now classify the test sentence "predictable with no fun". Suppose "with" never appeared in training (out-of-vocabulary, so it is dropped), and the remaining words have these smoothed counts:
| Word | count(w, −) | count(w, +) | ||
|---|---|---|---|---|
| predictable | 1 | 0 | ||
| no | 1 | 0 | ||
| fun | 0 | 1 |
Score for negative class (log base 10, for readability):
Score for positive class:
Since , the model predicts negative. This is sensible: "predictable" and "no" are strong negative-class signals present in training, and even though "fun" leans positive, it alone cannot outweigh two negative-leaning words plus the negative class's higher prior. Notice also that "with," an out-of-vocabulary word, contributed nothing to either score — the model simply has no opinion about words it never saw during training, which is a deliberate and correct behavior, not a bug.
Common pitfalls & traps
| Pitfall | Why it happens | Fix |
|---|---|---|
| Zero-probability collapse | A test word never appeared in one class's training data, making that class's raw likelihood exactly zero | Apply Laplace (or more general additive) smoothing to every word/class pair before inference |
| Forgetting the smoothing denominator | Adding 1 to every numerator without adding to the denominator | Probabilities no longer sum to 1; always add , the vocabulary size, to each class's total |
| Underflow from multiplying raw probabilities | Long documents multiply hundreds of small fractions, driving the product to zero in floating point | Always accumulate log-probabilities and sum instead of multiplying |
| Treating unseen test words as evidence | Trying to look up a word that never appeared in any training document | Skip out-of-vocabulary words entirely; they carry no information under this model |
| Trusting raw output probabilities as confidence | Naive Bayes probabilities are known to be poorly calibrated even when the class decision is correct | Use the arg-max decision for classification; calibrate separately (e.g., Platt scaling) if confidence scores are needed |
| Vocabulary built only from training data at test time | New domain-specific words at test time silently vanish | Acceptable by design, but monitor out-of-vocabulary rate — high rates signal domain mismatch |
Pioneers & history
The probabilistic engine behind Naive Bayes is Bayes' theorem itself, but its application to automated text categorization crystallized during the growth of statistical NLP and information retrieval in the late twentieth century, when researchers needed fast, trainable classifiers for exploding volumes of digital text — email, newswire, and web documents.
Origins · 1 minThomas Bayes and how this was discovered
Bayes never saw his idea applied to language. His 1763 essay, "An Essay towards solving a Problem in the Doctrine of Chances," published after his death by Richard Price, established how to update a belief about an unobserved cause given observed evidence — the mathematical seed that, two centuries later, would let machines infer whether an email is spam from nothing but the words it contains.
Where this matters
Naive Bayes remains embedded in production systems where speed, interpretability, and low data requirements outweigh the accuracy gains of heavier models. Early and many current email spam filters use Naive Bayes variants because the classifier retrains instantly as users flag new spam, needing no gradient-based fine-tuning. Sentiment analysis baselines in industry and academic benchmarks routinely report Naive Bayes accuracy first, since any more complex model must justify its added cost by beating this cheap reference point — a core habit taught alongside Text Classification Fundamentals. Language identification systems (detecting whether a string of text is English, French, or Japanese) often use character-level or word-level Naive Bayes because the independence assumption is nearly harmless when the discriminating signal is simple character or n-gram frequency. Document-routing systems in customer-support platforms, and simple content-moderation triage layers, use Naive Bayes as a fast first-pass filter before escalating uncertain cases to slower, more accurate models. Pedagogically, Naive Bayes is the cleanest bridge from the Bag-of-Words Model representation to fully generative sequence models: the next conceptual step, Hidden Markov Models, keeps the same "independent emissions given a hidden variable" structure but adds a Markov chain over the hidden states themselves, turning a single hidden class into a sequence of hidden states that evolve over time.
Ask the tutor: How would the decision rule and training procedure change if we wanted to use a Bernoulli event model instead of the multinomial one?
Why does Naive Bayes still work well even though words are clearly not independent?
Classification only requires the correct class to receive the highest score, not an accurate probability estimate. When features are correlated, the independence assumption distorts every class's computed likelihood in a similar direction, so the ranking of classes by score often stays correct even though the absolute probability values are wrong. This is why Naive Bayes decisions frequently match human judgments while its predicted probabilities are badly overconfident (very close to 0 or 1). The mismatch between "correct decisions" and "wrong probabilities" is a hallmark of the model and should be expected rather than treated as a bug.
What is the difference between the multinomial and Bernoulli event models?
The multinomial model treats a document as a sequence of word draws, so a word occurring three times contributes three identical factors to the likelihood — frequency matters. The Bernoulli model instead asks, for every vocabulary word, whether it is present or absent in the document at all, ignoring how many times it occurred. Multinomial Naive Bayes generally performs better on longer documents where word frequency carries real signal (e.g., topic classification), while Bernoulli Naive Bayes can be competitive on very short texts where presence/absence is the dominant signal.
How does Naive Bayes handle out-of-vocabulary words at test time?
It simply ignores them. Since the model has no trained likelihood parameters for a word it never saw during training, that word contributes no term to any class's score — it is dropped from the summation entirely. This is a deliberate design choice, not an approximation error: the model genuinely has zero evidence about an unseen word, so contributing nothing is the correct behavior rather than guessing.
Can Naive Bayes handle more than two classes?
Yes, directly. The decision rule generalizes to any number of classes without modification — the training algorithm computes a prior and a full likelihood table for every class, and inference simply scores all classes and takes the maximum. This is one practical advantage over classifiers like standard logistic regression, which need explicit multinomial extension or one-vs-rest wrapping to handle more than two labels.
Why is the model called "generative" rather than "discriminative"?
Naive Bayes models the joint distribution , effectively describing a story for how a document could be generated given its class — pick a class, then draw words independently from that class's word distribution. Discriminative models like logistic regression instead model directly, without ever describing how the words themselves were produced. The generative framing is what lets Naive Bayes be trained with pure counting rather than iterative optimization, and it is the same framing later extended by Hidden Markov Models to model sequences.
What causes Naive Bayes to be poorly calibrated, and does that matter?
Repeated correlated features get "double-counted" because the independence assumption treats them as separate, independent pieces of evidence even when they always co-occur. This systematically pushes computed probabilities toward the extremes (near 0 or 1) rather than reflecting true uncertainty. It matters if downstream systems need trustworthy confidence scores (e.g., to set a rejection threshold), in which case a calibration step such as Platt scaling should be applied. It matters far less if only the top-1 predicted class is used, since miscalibration rarely flips the arg-max decision.
How does Naive Bayes relate to the Bag-of-Words representation?
Naive Bayes is essentially a probabilistic classifier layered directly on top of Bag-of-Words counts: the word-count vectors produced by the Bag-of-Words representation become exactly the sufficient statistics — count(w, c) and total_c — that training needs to estimate . Because Bag-of-Words discards word order, Naive Bayes inherits that same blindness to order, which is precisely why sequence-aware generative models like Hidden Markov Models were later developed for tasks where order carries essential information, such as part-of-speech tagging.