init commit
This commit is contained in:
64
lab4/generate_spam_data.py
Normal file
64
lab4/generate_spam_data.py
Normal file
@@ -0,0 +1,64 @@
|
||||
import csv
|
||||
import random
|
||||
|
||||
random.seed(42)
|
||||
|
||||
SPAM_TEMPLATES = [
|
||||
"CONGRATULATIONS! You've WON a {prize}! Click {link} now to claim!!!",
|
||||
"URGENT: Your account will be suspended. Verify at {link} immediately",
|
||||
"Make ${amount} a week working from home, no experience needed! {link}",
|
||||
"FREE {prize} for the first 100 people! Limited time offer {link}",
|
||||
"Dear winner, you have been selected to receive {amount} dollars. Reply now",
|
||||
"Lowest prices on {product}! Buy now and save 90%! {link}",
|
||||
"Your {product} order could not be delivered, click {link} to reschedule",
|
||||
"Hot singles in your area want to meet you! {link}",
|
||||
"Act now! This {product} offer expires in 24 hours {link}",
|
||||
"You have 1 unread message regarding your {amount} refund, claim at {link}",
|
||||
]
|
||||
|
||||
HAM_TEMPLATES = [
|
||||
"Hey, are we still on for lunch tomorrow at noon?",
|
||||
"Please find attached the {product} report you requested.",
|
||||
"Can you review the pull request I sent over this morning?",
|
||||
"Reminder: team meeting moved to 3pm today.",
|
||||
"Thanks for your help with the {product} demo yesterday.",
|
||||
"The invoice for {amount} has been processed, receipt attached.",
|
||||
"Let's catch up sometime this week, been a while.",
|
||||
"I'll be out of office next Monday, please contact the team lead.",
|
||||
"Great presentation earlier, learned a lot about {product}.",
|
||||
"Attached is the agenda for tomorrow's {product} planning session.",
|
||||
]
|
||||
|
||||
PRIZES = ["iPhone", "vacation package", "gift card", "laptop", "cash prize"]
|
||||
PRODUCTS = ["software", "quarterly", "marketing", "onboarding", "budget"]
|
||||
LINKS = ["http://bit.ly/xyz123", "http://claim-now.co/win", "http://free-gift.biz"]
|
||||
AMOUNTS = ["500", "1000", "2500", "10000"]
|
||||
|
||||
|
||||
def fill(template):
|
||||
return template.format(
|
||||
prize=random.choice(PRIZES),
|
||||
link=random.choice(LINKS),
|
||||
amount=random.choice(AMOUNTS),
|
||||
product=random.choice(PRODUCTS),
|
||||
)
|
||||
|
||||
|
||||
def generate(n_per_class=300):
|
||||
rows = []
|
||||
for _ in range(n_per_class):
|
||||
rows.append((fill(random.choice(SPAM_TEMPLATES)), 1,
|
||||
round(min(1.0, max(0.0, random.gauss(0.85, 0.1))), 3)))
|
||||
rows.append((fill(random.choice(HAM_TEMPLATES)), 0,
|
||||
round(min(1.0, max(0.0, random.gauss(0.08, 0.07))), 3)))
|
||||
random.shuffle(rows)
|
||||
return rows
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
rows = generate(n_per_class=300)
|
||||
with open("data.csv", "w", newline="", encoding="utf-8") as f:
|
||||
writer = csv.writer(f)
|
||||
writer.writerow(["text", "label", "spam_score"])
|
||||
writer.writerows(rows)
|
||||
print(f"Wrote {len(rows)} rows to data.csv")
|
||||
15
lab4/test_model.py
Normal file
15
lab4/test_model.py
Normal file
@@ -0,0 +1,15 @@
|
||||
import joblib
|
||||
|
||||
vectorizer = joblib.load("vectorizer.joblib")
|
||||
clf = joblib.load("classifier.joblib")
|
||||
|
||||
print("Type text to classify. Ctrl+C or empty line to quit.\n")
|
||||
while True:
|
||||
text = input("> ").strip()
|
||||
if not text:
|
||||
break
|
||||
X = vectorizer.transform([text])
|
||||
pred = clf.predict(X)[0]
|
||||
verdict = "SPAM" if pred == 1 else "HAM"
|
||||
print(f"[{verdict}] {text}\n")
|
||||
|
||||
75
lab4/train_spam_model.py
Normal file
75
lab4/train_spam_model.py
Normal file
@@ -0,0 +1,75 @@
|
||||
import joblib
|
||||
import csv
|
||||
|
||||
import numpy as np
|
||||
from sklearn.feature_extraction.text import TfidfVectorizer
|
||||
from sklearn.linear_model import LogisticRegression, Ridge
|
||||
from sklearn.metrics import (
|
||||
accuracy_score,
|
||||
classification_report,
|
||||
mean_absolute_error,
|
||||
r2_score,
|
||||
)
|
||||
from sklearn.model_selection import train_test_split
|
||||
|
||||
|
||||
def load_data(path="data.csv"):
|
||||
texts, labels, scores = [], [], []
|
||||
with open(path, newline="", encoding="utf-8") as f:
|
||||
for row in csv.DictReader(f):
|
||||
texts.append(row["text"])
|
||||
labels.append(int(row["label"]))
|
||||
scores.append(float(row["spam_score"]))
|
||||
return texts, np.array(labels), np.array(scores)
|
||||
|
||||
|
||||
def main():
|
||||
texts, labels, scores = load_data()
|
||||
|
||||
X_train_txt, X_test_txt, y_train, y_test, s_train, s_test = train_test_split(
|
||||
texts, labels, scores, test_size=0.25, random_state=42, stratify=labels
|
||||
)
|
||||
|
||||
vectorizer = TfidfVectorizer(lowercase=True, ngram_range=(1, 2), max_features=2000)
|
||||
X_train = vectorizer.fit_transform(X_train_txt)
|
||||
X_test = vectorizer.transform(X_test_txt)
|
||||
|
||||
# Classification Model (Spam/Ham)
|
||||
clf = LogisticRegression(max_iter=1000)
|
||||
clf.fit(X_train, y_train)
|
||||
y_pred = clf.predict(X_test)
|
||||
|
||||
print("Classification: Spam vs Ham")
|
||||
print(f"Accuracy: {accuracy_score(y_test, y_pred):.3f}")
|
||||
print(classification_report(y_test, y_pred, target_names=["ham", "spam"]))
|
||||
|
||||
# Regression model
|
||||
reg = Ridge(alpha=1.0)
|
||||
reg.fit(X_train, s_train)
|
||||
s_pred = reg.predict(X_test)
|
||||
s_pred = np.clip(s_pred, 0, 1)
|
||||
|
||||
print("Regression: Spam Score (0-1)")
|
||||
print(f"MAE: {mean_absolute_error(s_test, s_pred):.3f}")
|
||||
print(f"R^2: {r2_score(s_test, s_pred):.3f}")
|
||||
|
||||
# Demo model
|
||||
print("\nTest Samples")
|
||||
samples = [
|
||||
"Congratulations! You've won a free vacation, click here now!",
|
||||
"Hey, can you send me the meeting notes from earlier?",
|
||||
]
|
||||
X_demo = vectorizer.transform(samples)
|
||||
preds = clf.predict(X_demo)
|
||||
scores_demo = np.clip(reg.predict(X_demo), 0, 1)
|
||||
for text, label, score in zip(samples, preds, scores_demo):
|
||||
verdict = "SPAM" if label == 1 else "HAM"
|
||||
print(f"[{verdict}] score={score:.2f} :: {text}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# persist our model
|
||||
joblib.dump(vectorizer, "vectorizer.joblib")
|
||||
joblib.dump(clf, "classifier.joblib")
|
||||
print("\nSaved model artifacts.")
|
||||
main()
|
||||
Reference in New Issue
Block a user