9.0 KiB
9.0 KiB
In [1]:
from pathlib import Path
import numpy as np
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression, Perceptron
from sklearn.metrics import (
accuracy_score,
confusion_matrix,
f1_score,
precision_score,
recall_score,
)
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import MultinomialNB
from sklearn.pipeline import Pipeline
from sklearn.svm import LinearSVC
DATA_PATH = Path("data/SMSSpamCollection")
RANDOM_STATE = 42
if not DATA_PATH.exists():
raise FileNotFoundError(
"Missing data/SMSSpamCollection. Follow data/README.md to download the official dataset."
)
In [2]:
df = pd.read_csv(DATA_PATH, sep="\t", header=None, names=["label", "message"])
df["label"] = df["label"].astype("string").str.strip().str.lower()
df["message"] = df["message"].astype("string").str.strip()
df = df.dropna(subset=["label", "message"])
df = df[df["label"].isin(["ham", "spam"]) & df["message"].ne("")]
conflict_counts = df.groupby("message")["label"].nunique()
df = df[~df["message"].isin(conflict_counts[conflict_counts.gt(1)].index)]
df = df.drop_duplicates(subset=["label", "message"]).reset_index(drop=True)
X = df["message"]
y = df["label"].map({"ham": 0, "spam": 1}).astype(int)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.20, random_state=RANDOM_STATE, stratify=y
)
In [3]:
# TODO 1: create four pipelines with identical TF-IDF settings.
# Models: MultinomialNB, Perceptron, LinearSVC, and LogisticRegression.
models = None
print("Models:", None)
Models: None
In [4]:
# TODO 2: fit every pipeline on the same training split.
# TODO 3: record accuracy, spam precision, spam recall, spam F1,
# false positives, and false negatives for each model.
fitted_models = None
predictions = None
comparison = None
comparison
In [5]:
# TODO 4: select the model with the highest spam F1.
best_model_name = None
best_pipeline = None
best_predictions = None
# TODO 5: create a DataFrame containing the best model's test errors.
best_errors = None
print("Best model by spam F1:", best_model_name)
print("Number of errors:", None)
best_errors.head(10)
Best model by spam F1: None Number of errors: None
[0;31m---------------------------------------------------------------------------[0m [0;31mAttributeError[0m Traceback (most recent call last) Cell [0;32mIn[5], line 11[0m [1;32m 9[0m [38;5;28mprint[39m([38;5;124m"[39m[38;5;124mBest model by spam F1:[39m[38;5;124m"[39m, best_model_name) [1;32m 10[0m [38;5;28mprint[39m([38;5;124m"[39m[38;5;124mNumber of errors:[39m[38;5;124m"[39m, [38;5;28;01mNone[39;00m) [0;32m---> 11[0m [43mbest_errors[49m[38;5;241;43m.[39;49m[43mhead[49m([38;5;241m10[39m) [0;31mAttributeError[0m: 'NoneType' object has no attribute 'head'
In [ ]:
assert set(models) == {"MultinomialNB", "Perceptron", "LinearSVC", "LogisticRegression"}
assert set(fitted_models) == set(models)
assert set(predictions) == set(models)
assert comparison.shape == (4, 6)
assert comparison.index.is_unique
assert comparison["spam_f1"].between(0, 1).all()
assert best_model_name in models
assert len(best_predictions) == len(y_test)
assert set(best_errors["error_type"].unique()).issubset({"false_positive", "false_negative"})
print("✓ Lab 4 completed")