A document classifier that sorts news articles into topics — sports, technology, politics, health — using TF-IDF features and Naive Bayes, built into scikit-learn.
scikit-learn includes 20,000 news articles across 20 categories — built in, no download.
from sklearn.datasets import fetch_20newsgroups
# Use a subset of 4 categories for clarity
categories = [
'sci.space',
'comp.graphics',
'rec.sport.hockey',
'talk.politics.guns',
]
train = fetch_20newsgroups(subset='train', categories=categories, remove=('headers','footers','quotes'))
test = fetch_20newsgroups(subset='test', categories=categories, remove=('headers','footers','quotes'))
print(f"Training: {len(train.data)} articles")
print(f"Testing: {len(test.data)} articles")
print(f"Classes: {train.target_names}")
# Preview one article
print("\n--- Sample Article ---")
print(train.data[0][:400])
print(f"Category: {train.target_names[train.target[0]]}")
TF-IDF converts text to numerical features. Naive Bayes classifies based on word frequency.
from sklearn.pipeline import Pipeline
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.metrics import classification_report
pipeline = Pipeline([
('tfidf', TfidfVectorizer(max_features=10000, stop_words='english', ngram_range=(1,2))),
('clf', MultinomialNB(alpha=0.1)),
])
pipeline.fit(train.data, train.target)
y_pred = pipeline.predict(test.data)
target_names = [c.split('.')[-1] for c in test.target_names]
print(classification_report(test.target, y_pred, target_names=target_names))
precision recall f1-score support
space 0.97 0.96 0.97 394
graphics 0.93 0.94 0.93 389
hockey 0.99 0.98 0.98 399
guns 0.95 0.96 0.95 364
accuracy 0.96 1546Predict the category of any new text and show which words drove the decision.
import numpy as np
def classify_and_explain(text, top_n=10):
probs = pipeline.predict_proba([text])[0]
pred_idx = np.argmax(probs)
pred_cat = train.target_names[pred_idx]
print(f"Predicted category: {pred_cat.split('.')[-1]} ({probs[pred_idx]:.1%} confidence)")
print(f"\nAll probabilities:")
for i, p in enumerate(probs):
print(f" {train.target_names[i].split('.')[-1]:12} {p:.2%}")
# Top keywords
tfidf = pipeline.named_steps['tfidf']
clf = pipeline.named_steps['clf']
features = tfidf.transform([text]).toarray()[0]
feat_names = np.array(tfidf.get_feature_names_out())
top_idx = features.argsort()[-top_n:][::-1]
print(f"\nTop keywords: {list(feat_names[top_idx])}")
new_article = """
The team scored three goals in the second period to win the championship.
The goalie made 42 saves in a historic performance. Playoffs start next week.
"""
classify_and_explain(new_article)
96% accuracy with zero neural networks — just TF-IDF and Naive Bayes. For many text classification tasks, this simple pipeline outperforms complex deep learning models and runs in milliseconds. Use it for email routing, ticket triage, and content moderation.
Spotted a bug, broken code, or something that doesn't look right? Tell us what's off and we'll fix it.