01Loading the dataset

We'll use the SMS Spam Collection dataset from the UCI Machine Learning Repository — 5,572 real SMS messages, each labelled as "spam" or "ham" (legitimate).

data_loading.py
import pandas as pd

# UCI SMS Spam Collection dataset (real labelled SMS messages)
url = "https://raw.githubusercontent.com/justmarkham/pycon-2016-tutorial/master/data/sms.tsv"
df = pd.read_csv(url, sep='\t', header=None, names=['label', 'message'])

print(df.shape)
print(df.head())
print(df['label'].value_counts())
Output

(5572, 2) — 4,825 ham messages and 747 spam messages (~13.4% spam rate). Like our churn and loan datasets, this is imbalanced, so we'll keep that in mind during evaluation.

02Exploratory data analysis

For text data, useful EDA includes message length distribution and the most common words in each class — spam messages are often noticeably longer and contain distinctive vocabulary (free, win, claim, urgent).

eda.py
import matplotlib.pyplot as plt
import seaborn as sns

df['length'] = df['message'].apply(len)

plt.figure(figsize=(8, 5))
sns.histplot(data=df, x='length', hue='label', bins=50,
             palette=['#1a4a3a', '#e24b4a'], alpha=0.6)
plt.title('Message Length by Class')
plt.savefig('message_length.png')

print(df.groupby('label')['length'].mean())
Key finding

Spam messages average ~139 characters vs ~71 characters for ham — spam tends to be noticeably longer, since it usually contains a call-to-action, a link, or promotional text packed into the message.

03Text preprocessing & TF-IDF

Machine learning models need numbers, not raw text. We clean the text (lowercase, remove punctuation), then convert it to numeric vectors using TF-IDF (Term Frequency-Inverse Document Frequency), which weighs words by how distinctive they are to a message, not just how often they appear.

preprocessing.py
import re
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.model_selection import train_test_split

def clean_text(text):
    text = text.lower()
    text = re.sub(r'[^a-z\s]', '', text)  # remove punctuation/numbers
    return text

df['clean_message'] = df['message'].apply(clean_text)
df['label_num'] = df['label'].map({'ham': 0, 'spam': 1})

# Train/test split on raw text first
X_train_text, X_test_text, y_train, y_test = train_test_split(
    df['clean_message'], df['label_num'],
    test_size=0.2, random_state=42, stratify=df['label_num']
)

# TF-IDF vectorisation — fit only on training data to avoid data leakage
vectorizer = TfidfVectorizer(stop_words='english', max_features=3000)
X_train = vectorizer.fit_transform(X_train_text)
X_test = vectorizer.transform(X_test_text)

print(f"Vocabulary size: {len(vectorizer.vocabulary_)}")
print(f"Training matrix shape: {X_train.shape}")

04Training the model

Multinomial Naive Bayes is the classical algorithm for text classification — it's fast, works well on high-dimensional sparse data like TF-IDF vectors, and despite its simplicity (it "naively" assumes word independence), performs remarkably well on spam detection.

train_model.py
from sklearn.naive_bayes import MultinomialNB

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

# Inspect which words are most indicative of spam
feature_names = vectorizer.get_feature_names_out()
spam_log_prob = model.feature_log_prob_[1]
top_spam_words = pd.DataFrame({
    'word': feature_names,
    'log_prob': spam_log_prob
}).sort_values('log_prob', ascending=False).head(15)

print(top_spam_words)
Most spam-indicative words

Words like "free", "win", "call", "claim", "prize", and "urgent" top the list — exactly the vocabulary a human would intuitively flag, confirming the model has learned genuinely meaningful patterns.

05Evaluation

For spam filters, precision matters enormously — a false positive (legitimate message marked as spam) is far more annoying to a user than an occasional spam message slipping through. We check this tradeoff explicitly.

evaluate.py
from sklearn.metrics import classification_report, confusion_matrix
import seaborn as sns

y_pred = model.predict(X_test)

print(classification_report(y_test, y_pred, target_names=['Ham', 'Spam']))

cm = confusion_matrix(y_test, y_pred)
plt.figure(figsize=(6, 5))
sns.heatmap(cm, annot=True, fmt='d', cmap='Greens',
            xticklabels=['Ham', 'Spam'], yticklabels=['Ham', 'Spam'])
plt.title('Confusion Matrix')
plt.ylabel('Actual')
plt.xlabel('Predicted')
plt.savefig('spam_confusion_matrix.png')

# Try it on a new message
new_message = ["Congratulations! You've won a free iPhone. Click here to claim now!"]
new_vec = vectorizer.transform(new_message)
prediction = model.predict(new_vec)
print("Spam" if prediction[0] == 1 else "Ham")
MetricSpam ClassWhat it means
Precision0.9797% of messages flagged as spam are actually spam
Recall0.89Model catches 89% of all actual spam messages
F1-Score0.93Strong overall balance of precision and recall

The high precision (0.97) is exactly what you want in a spam filter — very few legitimate messages get wrongly blocked. The slightly lower recall (0.89) means a small fraction of spam still gets through, which is a far more acceptable failure mode than blocking real messages.

06Real-world use case

Where this exact technique is used in industry

Email Spam Filters
Gmail, Outlook and most email providers use Naive Bayes or similar probabilistic models as one layer of their multi-stage spam detection pipeline.
SMS & OTP Fraud Detection
Telecom operators in India use text classification to flag fraudulent SMS and phishing attempts targeting users.
Content Moderation
Social platforms use the same TF-IDF + classifier approach as a first-pass filter for spam comments and reviews before human review.
Customer Support Routing
The text classification techniques here extend directly to routing support tickets to the right team based on message content.

This project introduces the foundation of NLP: turning unstructured text into structured numeric features (TF-IDF) that any classical ML algorithm can use. The same pipeline — clean text → vectorise → classify — underlies sentiment analysis, topic classification and many other text-based ML tasks.

Want to build this with guided support?

Text preprocessing, TF-IDF and NLP fundamentals are all covered hands-on in our Artificial Intelligence training programme.

View Training Programs WhatsApp Us