munotes®

The Naive Bayes Classifier

Get access to whole semester resourcesSemester Pass

Chapter Fifty-Eight

Syllabus topic Module 2, "Naive Bayes"

Pages 321 to 327 of 591

In one line

Naive Bayes computes the probability of each class given the evidence by multiplying the evidence together as if the pieces were independent, which they are not, and it works anyway.

In the wording a student can write in an examination: the naive Bayes classifier assigns to an instance with features x1 ... xn the class c maximising

P(c | x1..xn) proportional to P(c) * product over i of P(xi | c)

This follows from Bayes theorem together with the naive assumption that the features are conditionally independent given the class. The denominator P(x1..xn) is the same for every class and so is dropped. Laplace smoothing adds a constant to every count to prevent an unobserved feature value from forcing the whole product to zero.

It is Module 1, twice

The derivation is three lines and uses nothing not already proved.

Start from Bayes theorem, Bayes Theorem:

P(c | x1..xn) = P(x1..xn | c) * P(c) / P(x1..xn)

Drop the denominator. It does not depend on c, so it cannot change which class is largest; it is the normalising constant of that chapter.

Apply conditional independence, Conditional Independence. If the features are conditionally independent given the class, the joint likelihood factorises:

P(x1..xn | c) = product over i of P(xi | c)

so P(c | x1..xn) proportional to P(c) * product over i of P(xi | c)

There is nothing else in the method. No optimisation, no iteration, no hyperparameter except the smoothing constant. Training is counting, which is why it is the fastest classifier in MU's list.

And the saving is the one Conditional Independence counted: with 30 binary features the full joint needs 2,147,483,647 numbers and this needs 61.

It worked, with every fraction printed

# The naive Bayes classifier: worked BY HAND on the 14 rows, with every
# probability printed, and the zero-frequency problem shown and then fixed.
ROWS = [
    ("rain",  "far",   "no",  "yes", "no"),
    ("rain",  "far",   "no",  "no",  "no"),
    ("clear", "far",   "no",  "yes", "yes"),
    ("humid", "near",  "no",  "yes", "yes"),
    ("humid", "near",  "yes", "yes", "yes"),
    ("humid", "near",  "yes", "no",  "no"),
    ("clear", "near",  "yes", "no",  "yes"),
    ("rain",  "near",  "no",  "yes", "no"),
    ("rain",  "near",  "yes", "yes", "yes"),
    ("humid", "far",   "yes", "yes", "yes"),
    ("rain",  "far",   "yes", "no",  "yes"),
    ("clear", "far",   "yes", "no",  "yes"),
    ("clear", "near",  "no",  "no",  "yes"),
    ("humid", "far",   "no",  "no",  "no"),
]
COLS = ["weather", "distance", "friend", "early"]
TARGET = 4
VALUES = [sorted({r[i] for r in ROWS}) for i in range(len(COLS))]

def counts(cls, col, val):
    n = sum(1 for r in ROWS if r[TARGET] == cls)
    k = sum(1 for r in ROWS if r[TARGET] == cls and r[col] == val)
    return k, n

def cond(cls, col, val, alpha):
    """P(feature = val | class), with Laplace smoothing by alpha."""
    k, n = counts(cls, col, val)
    return (k + alpha) / (n + alpha * len(VALUES[col]))

def predict(case, alpha, show=False):
    scores = {}
    for cls in ("yes", "no"):
        prior = sum(1 for r in ROWS if r[TARGET] == cls) / len(ROWS)
        p = prior
        if show:
            print("   class %s" % cls)
            print("      P(%s) = %d/%d = %.4f"
                  % (cls, sum(1 for r in ROWS if r[TARGET] == cls), len(ROWS), prior))
        for i, v in enumerate(case):
            c = cond(cls, i, v, alpha)
            k, n = counts(cls, i, v)
            p *= c
            if show:
                print("      P(%s = %s | %s) = (%d + %g)/(%d + %g*%d) = %.4f"
                      % (COLS[i], v, cls, k, alpha, n, alpha, len(VALUES[i]), c))
        scores[cls] = p
        if show:
            print("      product = %.8f" % p)
    total = scores["yes"] + scores["no"]
    return scores, (scores["yes"] / total if total else 0.0)

CASE = ("rain", "near", "yes", "no")
print("a new student: weather %s, distance %s, friend going %s, early lecture %s"
      % CASE)
print()
print("WITHOUT smoothing (alpha = 0):")
scores, p_yes = predict(CASE, 0.0, show=True)
print("   unnormalised: yes %.8f   no %.8f" % (scores["yes"], scores["no"]))
print("   P(attend = yes) = %.8f / (%.8f + %.8f) = %.4f"
      % (scores["yes"], scores["yes"], scores["no"], p_yes))
print("   ANSWER: %s" % ("yes" if p_yes > 0.5 else "no"))
print()
print("THE ZERO-FREQUENCY PROBLEM. no student who ATTENDED had weather 'x', an")
print("unseen value, so P(weather = x | yes) would be 0/9 = 0, and the WHOLE")
print("product becomes 0 no matter how strong the other evidence is.")
print("the same happens for any value never seen with a class. check 'clear':")
for cls in ("yes", "no"):
    k, n = counts(cls, 0, "clear")
    print("   P(weather = clear | %s) = %d/%d = %.4f  %s"
          % (cls, k, n, k / n, "<- ZERO, and it wipes out the product" if k == 0 else ""))
print()
print("WITH Laplace smoothing (alpha = 1): add 1 to every count, and add")
print("alpha times the number of possible values to every denominator.")
for cls in ("yes", "no"):
    k, n = counts(cls, 0, "clear")
    print("   P(weather = clear | %s) = (%d+1)/(%d+1*3) = %.4f"
          % (cls, k, n, cond(cls, 0, "clear", 1.0)))
print()
print("the smoothed prediction for a student in CLEAR weather, near, no friend,")
print("early lecture:")
C2 = ("clear", "near", "no", "yes")
for alpha in (0.0, 1.0):
    s, p = predict(C2, alpha)
    print("   alpha = %.0f:  P(yes) = %.4f   -> %s" % (alpha, p, "yes" if p > 0.5 else "no"))
munotes.in321

The Naive Bayes Classifier

a new student: weather rain, distance near, friend going yes, early lecture no

WITHOUT smoothing (alpha = 0):
   class yes
      P(yes) = 9/14 = 0.6429
      P(weather = rain | yes) = (2 + 0)/(9 + 0*3) = 0.2222
      P(distance = near | yes) = (5 + 0)/(9 + 0*2) = 0.5556
      P(friend = yes | yes) = (6 + 0)/(9 + 0*2) = 0.6667
      P(early = no | yes) = (4 + 0)/(9 + 0*2) = 0.4444
      product = 0.02351558
   class no
      P(no) = 5/14 = 0.3571
      P(weather = rain | no) = (3 + 0)/(5 + 0*3) = 0.6000
      P(distance = near | no) = (2 + 0)/(5 + 0*2) = 0.4000
      P(friend = yes | no) = (1 + 0)/(5 + 0*2) = 0.2000
      P(early = no | no) = (3 + 0)/(5 + 0*2) = 0.6000
      product = 0.01028571
   unnormalised: yes 0.02351558   no 0.01028571
   P(attend = yes) = 0.02351558 / (0.02351558 + 0.01028571) = 0.6957
   ANSWER: yes

THE ZERO-FREQUENCY PROBLEM. no student who ATTENDED had weather 'x', an
unseen value, so P(weather = x | yes) would be 0/9 = 0, and the WHOLE
product becomes 0 no matter how strong the other evidence is.
the same happens for any value never seen with a class. check 'clear':
   P(weather = clear | yes) = 4/9 = 0.4444
   P(weather = clear | no) = 0/5 = 0.0000  <- ZERO, and it wipes out the product

WITH Laplace smoothing (alpha = 1): add 1 to every count, and add
alpha times the number of possible values to every denominator.
   P(weather = clear | yes) = (4+1)/(9+1*3) = 0.4167
   P(weather = clear | no) = (0+1)/(5+1*3) = 0.1250

the smoothed prediction for a student in CLEAR weather, near, no friend,
early lecture:
   alpha = 0:  P(yes) = 1.0000   -> yes
   alpha = 1:  P(yes) = 0.8319   -> yes
munotes.in322

The Naive Bayes Classifier

The arithmetic a paper wants. For the class yes: the prior is 9/14, and the four conditional probabilities are read straight off the table by counting. Their product is 0.02351558. The same for no gives 0.01028571. Normalising, P(yes) is 0.6957, so the answer is yes.

Note that the two products do not sum to 1 before normalising. They are P(class) * P(evidence | class), which is the joint, and normalising by their sum divides by P(evidence). That is the normalising constant of Bayes Theorem computed without ever being named.

The zero-frequency problem

Read the middle block. Among the five students who did not attend, none had clear weather, so P(weather = clear | no) is 0/5 = 0.

One zero destroys everything. The product for no becomes exactly 0, whatever the other three features say, so the classifier reports P(yes) = 1.0000: absolute certainty from one missing count. That is not confidence, it is an artefact, and it would occur on any feature value that happens not to appear with a class in a finite sample.

munotes.in323

The Naive Bayes Classifier

Laplace smoothing is the fix and it is one line:

P(xi = v | c) = (count + alpha) / (n_c + alpha * number of possible values of xi)

With alpha = 1, P(weather = clear | no) becomes (0 + 1)/(5 + 3) = 0.1250 instead of 0, and the same student's prediction falls from the absurd 1.0000 to a sensible 0.8319. Same answer, honest confidence.

The denominator must add alpha times the number of possible values, not alpha once, or the smoothed probabilities for a feature no longer sum to 1. And this is Regularization again: smoothing is a prior pulling every estimate towards uniform, and alpha = 1 is exactly a uniform prior on each feature's distribution. It is the same device as The Learning Agent used to stop an early run of failures producing an estimate of zero.

The three standard variants

MU writes Naive Bayes without qualification, and a paper may ask which kind.

VariantFeatures areP(xi given c) is
Multinomialcounts, such as how often a word occursproportional to the count, smoothed
Bernoullipresent or absenta probability of presence, and absence is also evidence
Gaussiancontinuous numbersa normal density with the mean and variance of that feature within that class

Multinomial and Bernoulli differ in a way that matters for text: Bernoulli explicitly scores a word's absence, multinomial ignores it. For short documents Bernoulli usually wins; for long ones multinomial does.

Gaussian naive Bayes is how continuous features are handled without discretising them: estimate the mean and variance of each feature within each class from the training data, and use the normal density. That is two numbers per feature per class, so it remains linear in the number of features.

Why a false assumption gives a good classifier

The assumption is almost always false. In text, New and York are strongly dependent given any class. In the 14 rows, weather and distance may well be related. And the classifier works. A paper asking why expects this answer.

The probabilities are wrong; the ordering is often right. Classification needs only the largest class, not a correct probability. Dependent features count their shared evidence more than once, which pushes the winning class's product further ahead, and the winner usually does not change.

So the correct statement is precise: naive Bayes is a good classifier and a bad probability estimator. Its outputs are notoriously overconfident, clustering near 0 and 1. Anything that uses the probability as a number, such as ranking by risk or setting a threshold on expected cost, should not use naive Bayes without recalibrating it.

munotes.in324

The Naive Bayes Classifier

Two more practical reasons it survives: it needs very little data, since each estimate is a one-dimensional count rather than a joint; and it is immune to the curse of dimensionality that defeats k-NN in k-NN for Regression, and What Limits the Method, because it never computes a distance.

Two implementation points that cost marks

Underflow. Multiplying a hundred probabilities gives a number too small for a computer to represent, and it becomes 0. The fix is to work with logarithms: maximise log P(c) + sum of log P(xi | c), which turns the product into a sum and cannot underflow. Every real implementation does this.

A feature value never seen at all, in any class, contributes the same factor to every class and so cannot affect the comparison. It is usually simply skipped.

Distinctions

Naive BayesBayes theorem
Isa classifiera theorem
Extra assumptionconditional independence of the featuresnone
Exactnoyes
A good classifierA good probability estimator
Needsthe right class to be largestthe number to be right
Naive Bayes isyesno, it is overconfident
MultinomialBernoulliGaussian
Featurescountspresent or absentcontinuous
Scores absencenoyesnot applicable
Parameters per feature per classoneonetwo, mean and variance
No smoothingLaplace smoothing
An unseen value givesprobability 0, wiping out the producta small positive probability
Confidence here1.0000, from one missing count0.8319
It isa bug waiting for a finite samplea uniform prior, that is regularization

What it does not mean

Naive does not mean simple-minded. It names the independence assumption specifically.

The assumption is not usually true, and the classifier is not claiming it is. It is claiming that the ordering of the classes survives the approximation.

The output probability is not a probability you should act on numerically. It is overconfident. Use it to choose a class, not to price a risk.

Smoothing is not a fudge. It is a uniform prior, and it is the same device as the ridge penalty of Regularization.

A zero probability is not evidence of impossibility. It is evidence that the value did not occur in a finite sample.

Multiplying the probabilities directly is not how it is implemented. Logarithms are used, to avoid underflow.

Quick revision

  • P(c | x) proportional to P(c) * product of P(xi | c). Bayes theorem, drop the denominator, and assume the features are conditionally independent given the class.
  • Training is counting. No optimisation, no iteration. With 30 binary features it needs 61 numbers where the full joint needs 2,147,483,647.
  • Worked: prior 9/14, four conditionals counted off the table, product 0.02351558 against 0.01028571, giving P(yes) = 0.6957.
  • Zero frequency: P(weather = clear | no) = 0/5 = 0 makes the whole product 0, so the classifier reports 1.0000. One missing count produces absolute certainty.
  • Laplace smoothing: (count + alpha) / (n + alpha * number of values). With alpha = 1 the estimate becomes 0.1250 and the confidence falls from 1.0000 to 0.8319. It is a uniform prior, that is regularization.
  • Variants: multinomial (counts), Bernoulli (presence, and absence is evidence), Gaussian (continuous, mean and variance per feature per class).
  • A good classifier and a bad probability estimator. The assumption is false, the probabilities are overconfident, and the class ordering usually survives.
  • Implementation: use logarithms, or the product underflows to zero.
munotes.in325

The Naive Bayes Classifier

Test yourself

1. Derive the naive Bayes rule from Bayes theorem. Bayes theorem gives P(c | x) as P(x | c) times P(c) divided by P(x). The denominator is the same for every class and cannot change which is largest, so it is dropped. Assuming the features are conditionally independent given the class, P(x | c) factorises into the product of P(xi | c), giving P(c | x) proportional to P(c) times that product.

2. Compute the prediction for a student in rain, near, with a friend going, no early lecture. For yes: prior 9/14 times the four conditionals, giving 0.02351558. For no: prior 5/14 times its conditionals, giving 0.01028571. Normalising, P(yes) is 0.6957, so the prediction is that the student attends.

3. What is the zero-frequency problem, and what does it do to the output? If a feature value never occurs with a class in the training data, its conditional probability is exactly zero, and multiplying by it makes the entire product zero however strong the other evidence. In this chapter no non-attending student had clear weather, so the classifier reports a probability of 1.0000, absolute certainty produced by one missing count.

4. State Laplace smoothing and apply it to that case. Estimate each conditional as the count plus alpha, divided by the class count plus alpha times the number of possible values of that feature. With alpha of 1, P(weather = clear | no) becomes one over eight, that is 0.1250, instead of zero, and the classifier's confidence falls from 1.0000 to 0.8319.

5. Name the three variants of naive Bayes and say what each suits. Multinomial, for count features such as word frequencies. Bernoulli, for presence-or-absence features, which also scores a feature's absence as evidence and suits short documents. Gaussian, for continuous features, modelling each with a normal distribution whose mean and variance are estimated per class.

munotes.in326

The Naive Bayes Classifier

6. The independence assumption is usually false. Why does the classifier still work? Because classification needs only the correct class to have the largest score, not a correct probability. Dependent features double-count their shared evidence, which exaggerates the leading class's score but usually does not change which class leads. The correct summary is that it is a good classifier and a poor probability estimator, since its outputs are systematically overconfident.

7. Why are logarithms used in an implementation? Because multiplying many probabilities produces a number too small to represent, which becomes zero and destroys the comparison. Taking logarithms turns the product into a sum of logarithms, which cannot underflow, and the class with the largest sum is the same as the class with the largest product.

munotes.in327

The rest of this subject

These notes are cut from the University's printed syllabus. Open the syllabus itself, or the past papers, for the same subject.

Issue
Done!