Freedom Sale
Independence Day Special — Unlock the AI Path 70% off our most popular AI course · Limited time offer
--Days
--Hrs
--Min
--Sec
Claim Your Discount
✦ Beginner ⏱ 30 min

📧 Build a Spam Email Detector with Naive Bayes

🎯 What You'll Build

A text classification model that reads email content and predicts spam or ham (not spam) — trained on 5,500 real emails with 97%+ accuracy.

📋 What You'll Need

1

Load the SMS Spam dataset

We use the UCI SMS Spam Collection — 5,574 labelled messages, available free without any account.

import pandas as pd

# Download the dataset
url = 'https://raw.githubusercontent.com/justmarkham/pycon-2016-tutorial/master/data/sms.tsv'
df = pd.read_csv(url, sep='\t', header=None, names=['label', 'text'])

print(df.shape)               # (5574, 2)
print(df['label'].value_counts())
print(df.sample(3))
(5574, 2)
ham     4827
spam     747
Name: label, dtype: int64

   label                                               text
12   ham  I've been searching for the right words to ...
45  spam  Free entry in 2 a wkly comp to win FA Cup fi...
89   ham  Ok lar... Joking wif u oni...
2

Convert text to numbers with TF-IDF

Machine learning models need numbers, not words. TF-IDF converts each message into a vector of word importance scores.

from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import TfidfVectorizer

X = df['text']
y = df['label']

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

vectorizer = TfidfVectorizer(stop_words='english', max_features=5000)
X_train_vec = vectorizer.fit_transform(X_train)
X_test_vec  = vectorizer.transform(X_test)

print(f'Training samples: {X_train_vec.shape[0]}')
print(f'Features (words): {X_train_vec.shape[1]}')
Training samples: 4459
Features (words): 5000
💡 Tip: TF-IDF stands for Term Frequency-Inverse Document Frequency. Words that appear often in spam but rarely in normal emails (like "FREE", "WIN", "CLAIM") get high scores.
3

Train a Naive Bayes classifier

MultinomialNB is the classic choice for text classification — fast, accurate, and interpretable.

from sklearn.naive_bayes import MultinomialNB
from sklearn.metrics import accuracy_score, classification_report

model = MultinomialNB()
model.fit(X_train_vec, y_train)

y_pred = model.predict(X_test_vec)

print(f'Accuracy: {accuracy_score(y_test, y_pred):.4f}')
print()
print(classification_report(y_test, y_pred))
Accuracy: 0.9739

              precision    recall  f1-score   support
         ham       0.97      1.00      0.98       965
        spam       1.00      0.79      0.88       150

    accuracy                           0.97      1115
4

Predict new messages

Pass any text through the vectorizer and model to get a spam/ham prediction.

def predict_spam(message):
    vec = vectorizer.transform([message])
    prediction = model.predict(vec)[0]
    probability = model.predict_proba(vec)[0]
    spam_prob = probability[model.classes_.tolist().index('spam')]
    label = '🚫 SPAM' if prediction == 'spam' else '✅ HAM (not spam)'
    print(f'{label}  (spam probability: {spam_prob:.1%})\n  "{message[:60]}..."')

predict_spam("Congratulations! You've won a FREE iPhone. Click here NOW to claim!")
predict_spam("Hey, are we still on for lunch tomorrow at 1pm?")
predict_spam("URGENT: Your bank account has been suspended. Verify now!")
predict_spam("Can you send me the meeting notes from this morning?")
🚫 SPAM  (spam probability: 99.8%)
  "Congratulations! You've won a FREE iPhone. Click here NOW to..."

✅ HAM (not spam)  (spam probability: 0.1%)
  "Hey, are we still on for lunch tomorrow at 1pm?..."

🚫 SPAM  (spam probability: 97.4%)
  "URGENT: Your bank account has been suspended. Verify now!..."

✅ HAM (not spam)  (spam probability: 0.3%)
  "Can you send me the meeting notes from this morning?..."
💡 Tip: To see which words are most associated with spam, check: pd.Series(model.feature_log_prob_[1], index=vectorizer.get_feature_names_out()).nlargest(10) — you will see words like "free", "prize", "win", "claim".

🎉 You Did It!

97.4% accuracy with just 20 lines of code. Naive Bayes is fast enough to classify thousands of messages per second. The same TF-IDF + classifier pipeline works for sentiment analysis, topic classification, and any other text problem.

Found something wrong?

Spotted a bug, broken code, or something that doesn't look right? Tell us what's off and we'll fix it.