Build the lesson's Naive Bayes spam filter and use it on new messages.
For a message and a class (spam or ham), the score is
log P(class) + Σ over the message's words of log((count(word, class) + 1) / (total words in class + V))
where P(class) is the share of training messages in that class, count(word, class) is how often the word appears in that class's training messages, and V is the number of different words in all the training messages. Words are compared exactly (they are all lower case). Predict the class with the higher score; if the scores are equal, predict ham.
Input
The first line has t (2 ≤ t ≤ 100). Each of the next t lines is a training message: its label, spam or ham, then its words. Both labels appear. Then a line with q (1 ≤ q ≤ 50) and q lines, each a message to classify (one or more words).
Output
spam or ham for each message, one per line.
Examples
6 spam win money now spam free money offer spam win a free prize ham meeting at noon ham project meeting tomorrow ham lunch at noon tomorrow 2 free money meeting tomorrow at noon
spam ham
3 spam buy now ham see you now ham call me 3 buy now call now
spam ham ham
Prompts inside input() are ignored when checking, so input("n: ") is fine.
Hints
Hint 1
Count, for each class, how many messages it has and how often each word appears in it.
Hint 2
score(class) = log P(class) + Σ log((count(word, class) + 1) / (words in class + V)), where V is the number of different words in all the training messages.
Hint 3
Choose spam only if its score is strictly bigger than ham's.
Solution
Show one correct solution (try it yourself first)
from math import log
t = int(input())
counts = {"spam": {}, "ham": {}}
messages = {"spam": 0, "ham": 0}
for _ in range(t):
label, *words = input().split()
messages[label] += 1
for word in words:
counts[label][word] = counts[label].get(word, 0) + 1
vocabulary = {w for c in counts.values() for w in c}
def score(words, label):
total = sum(counts[label].values())
s = log(messages[label] / t)
for word in words:
s += log((counts[label].get(word, 0) + 1) / (total + len(vocabulary)))
return s
for _ in range(int(input())):
words = input().split()
print("spam" if score(words, "spam") > score(words, "ham") else "ham")