-
Notifications
You must be signed in to change notification settings - Fork 4
ml spam detector
ghdrako edited this page Aug 28, 2026
·
11 revisions
import pandas as pd
# Load spam dataset
emails = pd.read_csv("spam.csv")
# Display first records
print(emails.head())
# Display dataset dimensions
print(emails.shape)
# Display dataset information
print(emails.info())
# Check missing values
print(emails.isnull().sum())
# Display label counts
print(
emails["label"].value_counts()
)
# Display percentages
print(
emails["label"]
.value_counts(normalize=True) * 100
)
import matplotlib.pyplot as plt
emails["label"].value_counts().plot(
kind="bar"
)
plt.xlabel("Email Category")
plt.ylabel("Number of Emails")
plt.title("Spam and Ham Distribution")
plt.show()
import re
def clean_text(text):
text = text.lower() # Converting Text to Lowercase
text = re.sub(
r"http\S+",
"",
text
)
text = re.sub(
r"[^a-z\s]",
"",
text
)
# Removing Extra Spaces
text = re.sub(
r"\s+",
" ",
text
).strip()
return text
emails["clean_message"] = (
emails["message"]
.apply(clean_text)
)
print(
emails[
["message", "clean_message"]
].head()
)
Zbyt agresywne usuwanie cech spamu w preprocessingu:
- Wyrażenie re.sub(r"http\S+", "", text) całkowicie usuwa linki. W wykrywaniu spamu sama obecność linku jest jedną z najsilniejszych cech. Zamiast go kasować, lepiej zamienić go na token, np. re.sub(r"http\S+", " httplink ", text).
- Podobnie wyrażenie re.sub(r"[^a-z\s]", "", text) usuwa znaki walut ($, €, £) oraz wykrzykniki (!), które są typowymi wyznacznikami wiadomości phishingowych/spamowych.
from sklearn.model_selection import train_test_split
X = emails["clean_message"]
y = emails["label"]
X_train, X_test, y_train, y_test = train_test_split(
X,
y,
test_size=0.20,
random_state=42,
stratify=y
)
from sklearn.feature_extraction.text import TfidfVectorizer
vectorizer = TfidfVectorizer(
stop_words="english",
max_features=5000
)
X_train_tfidf = vectorizer.fit_transform(
X_train
)
X_test_tfidf = vectorizer.transform(
X_test)
from sklearn.naive_bayes import MultinomialNB
model = MultinomialNB()
model.fit(
X_train_tfidf,
y_train
)
print("Training completed.")
predictions = model.predict(
X_test_tfidf
)
print(predictions[:10])
from sklearn.metrics import (
accuracy_score,
precision_score,
recall_score,
f1_score
)
print(
"Accuracy:",
accuracy_score(
y_test,
predictions
)
)
print(
"Precision:",
precision_score(
y_test,
predictions,
pos_label="spam"
)
)
print(
"Recall:",
recall_score(
y_test,
predictions,
pos_label="spam"
)
)
print(
"F1 Score:",
f1_score(
y_test,
predictions,
pos_label="spam"
)
)
from sklearn.metrics import confusion_matrix
matrix = confusion_matrix(
y_test,
predictions,
labels=[
"ham",
"spam"
]
)
print(matrix)
from sklearn.metrics import classification_report
print(
classification_report(
y_test,
predictions
)
)
# Although TF-IDF does not directly indicate feature importance, examining the vocabulary provides insight into the terms learned during training.
feature_names = (
vectorizer.get_feature_names_out()
)
print(feature_names[:50])
new_email = [
"Congratulations! You have won a free vacation. Click here to claim your prize."
]
new_email_clean = [
clean_text(text)
for text in new_email
]
new_email_vector = vectorizer.transform(
new_email_clean
)
prediction = model.predict(
new_email_vector
)
probability = model.predict_proba(
new_email_vector
)
print("Prediction:", prediction[0])
print(
"Confidence:",
probability.max()
)
import joblib
joblib.dump(
model,
"spam_model.pkl"
)
joblib.dump(
vectorizer,
"tfidf_vectorizer.pkl"
)
from sklearn.pipeline import Pipeline
pipeline = Pipeline([
(
"tfidf",
TfidfVectorizer(
preprocessor=clean_text,
stop_words="english",
max_features=5000
)
),
(
"classifier",
MultinomialNB()
)
])
pipeline.fit(
X_train,
y_train
)
pipeline_prediction = pipeline.predict(
new_email
)
print(pipeline_prediction)
import joblib
import pandas as pd
model = joblib.load(
"spam_model.pkl"
)
vectorizer = joblib.load(
"tfidf_vectorizer.pkl"
)
st.title(
"Spam Analyzer"
)
st.write(
"Classifing email using machine learning."
)
review = st.text_area(
"Enter a email text"
)
import re
def clean_input(text):
text = text.lower()
text = re.sub(
r"http\S+",
"",
text
)
text = re.sub(
r"[^a-z\s]",
"",
text
)
text = re.sub(
r"\s+",
" ",
text
).strip()
return text
if st.button("Analyze"):
cleaned_review = clean_input(
review
)
review_vector = vectorizer.transform(
[cleaned_review]
)
prediction = model.predict(
review_vector
)
probability = model.predict_proba(
review_vector
)
st.write(
"Predicted Spam:",
prediction[0]
)
st.write(
f"Confidence: {probability.max():.2%}"
)
st.subheader(
"Dataset Overview"
)
st.write(
reviews["Sentiment"]
.value_counts()
)
st.subheader(
"Sentiment Distribution"
)
st.bar_chart(
reviews["Sentiment"]
.value_counts()
)
st.subheader(
"Sample Reviews"
)
st.dataframe(
reviews[
["Review", "Sentiment"]
].head(10)
)
streamlit run app.py
Test