8.2 KiB
8.2 KiB
In [ ]:
from pathlib import Path
import pandas as pd
DATA_PATH = Path("data/SMSSpamCollection")
if not DATA_PATH.exists():
raise FileNotFoundError(
"Missing data/SMSSpamCollection. Follow data/README.md to download "
"and extract the official UCI SMS Spam Collection."
)
In [ ]:
raw_df = pd.read_csv(
DATA_PATH,
sep="\t",
header=None,
names=["label", "message"],
encoding="utf-8",
)
print("Raw shape:", raw_df.shape)
print(raw_df["label"].value_counts(dropna=False))
raw_df.head(10)
In [ ]:
audited_df = raw_df.copy()
audited_df["label"] = audited_df["label"].astype("string").str.strip().str.lower()
audited_df["message"] = audited_df["message"].astype("string").str.strip()
audited_df = audited_df.dropna(subset=["label", "message"])
audited_df = audited_df[audited_df["message"].ne("")]
audited_df = audited_df[audited_df["label"].isin(["ham", "spam"])]
exact_duplicate_count = int(audited_df.duplicated(subset=["label", "message"]).sum())
label_counts_per_message = audited_df.groupby("message")["label"].nunique()
conflicting_messages = label_counts_per_message[label_counts_per_message.gt(1)].index
print("Exact duplicate rows:", exact_duplicate_count)
print("Conflicting message texts:", len(conflicting_messages))
In [ ]:
clean_df = audited_df[~audited_df["message"].isin(conflicting_messages)].copy()
clean_df = clean_df.drop_duplicates(subset=["label", "message"]).reset_index(drop=True)
clean_df["target"] = clean_df["label"].map({"ham": 0, "spam": 1}).astype(int)
print("Clean shape:", clean_df.shape)
print(clean_df["target"].value_counts().sort_index().rename(index={0: "ham", 1: "spam"}))
In [ ]:
clean_df["character_count"] = clean_df["message"].str.len()
clean_df["word_count"] = clean_df["message"].str.split().str.len()
length_summary = clean_df.groupby("label").agg(
message_count=("message", "size"),
median_characters=("character_count", "median"),
median_words=("word_count", "median"),
)
class_distribution = clean_df["label"].value_counts(normalize=True)
print(length_summary)
print("Class proportions:")
print(class_distribution)
In [ ]:
assert list(raw_df.columns) == ["label", "message"]
assert clean_df["message"].notna().all()
assert clean_df["message"].ne("").all()
assert set(clean_df["label"].unique()) == {"ham", "spam"}
assert set(clean_df["target"].unique()) == {0, 1}
assert not clean_df.duplicated(subset=["label", "message"]).any()
assert not clean_df["message"].isin(conflicting_messages).any()
assert class_distribution.loc["ham"] > class_distribution.loc["spam"]
assert {"character_count", "word_count"}.issubset(clean_df.columns)
print("✓ Lab 1 completed")
In [ ]: