--- title: Spam Email Classifier with XAI (v2) emoji: 📧 colorFrom: blue colorTo: red sdk: gradio sdk_version: "5.23.0" python_version: "3.11" app_file: app.py pinned: false license: mit tags: - spam-detection - xai - lime - shap - eli5 - scikit-learn - nlp - explainable-ai models: - VoltageVagabond/spam-xai-model-v2 - VoltageVagabond/spam-classifier-mlx - VoltageVagabond/spam-classifier-liquid datasets: - VoltageVagabond/spam-email-dataset --- ## Senior Project Notice This repository was created for a senior project in ENGT 375 Applied Machine Learning at Old Dominion University. It is provided for educational and research demonstration purposes only. It is not intended for production use, security filtering, or making real-world spam/phishing decisions. Always use established security tools for operational email protection. # Spam Email Classifier with XAI Explanations **ENGT 375 — Applied Machine Learning | Spring 2026 | Old Dominion University** A Gradio web app that classifies emails as spam or ham and provides explainable AI (XAI) insights using three different methods (LIME, SHAP, and ELI5). **What's new in v2:** beginner-friendly notebook refactor (explicit for-loops over comprehensions, no decorators, no premature abstractions), lecture-style charts in the student teaching notebook, a separate `app_student.py` / `utils_student.py` / `retrain_student.py` track for course readers, and a fresh full-dataset retrain (99,999 samples — 69,999 train / 30,000 test) producing a re-tuned classification threshold of 0.3714. v2 is deployed as its own HuggingFace Space at `VoltageVagabond/spam-xai-classifier-v2`. ## Features - Paste any email and get an instant spam/ham prediction - **LIME** explanations — which words pushed the decision - **SHAP** feature importance — game-theoretic attribution - **ELI5** — model internal feature weights and permutation importance - **Side-by-side comparison** of all three XAI methods - **Plain English summary** of why the model made its decision - **User feedback** — thumbs up/down to log corrections for batch retraining - Adjustable classification threshold ## How to Run Locally ```bash # Install dependencies pip install -r requirements.txt # Train the model (first run only — produces models/voting_model.joblib) python3 train_ensemble.py # Launch the Gradio web app python3 app.py # Or open the student teaching notebook jupyter notebook notebooks/spam_classifier_xai_student.ipynb ``` You can also double-click any of these `.command` files in Finder: - `launch-gradio.command` — opens the Gradio web UI in your browser - `launch-notebook.command` — opens the student notebook in Jupyter - `launch-app.command` — opens the legacy Streamlit app (kept for reference; the active UI is `launch-gradio.command`) - `retrain-fast.command` — quick retrain (~2-5 min, single RF, no grid search) - `retrain-full.command` — full retrain (~15-30 min, voting ensemble + grid search) ## Retraining ```bash python3 retrain.py --mode fast # quick retrain, single RF python3 retrain.py --mode full # full retrain, voting ensemble + grid search python3 retrain.py --mode full --no-feedback # full retrain, ignore user feedback log ``` The retrain script reads accumulated user corrections from `data/feedback/feedback_log.csv` and merges them into the training data with 5x weighting. ## Model **Voting ensemble** (Random Forest + Logistic Regression + Linear SVM with calibration) trained on the full Kaggle 100K spam dataset + GitHub email-dataset (99,999 samples total: 69,999 train / 30,000 test), using 3,000 TF-IDF features + 24 hand-crafted metadata features. | Model | Accuracy | F1 Score | |-------|----------|----------| | Random Forest | 97.75% | 0.976 | | Logistic Regression | 96.57% | 0.964 | | SVM (LinearSVC + calibration) | 96.89% | 0.967 | | **VotingClassifier (deployed)** | **97.40%** | **0.973** | Optimal classification threshold: 0.3714 (targeting 99% ham precision; value read from `models/optimal_threshold.joblib` written by `train_ensemble.py`). ## Notebooks | Notebook | Purpose | |----------|---------| | `notebooks/spam_classifier_xai_student.ipynb` | **Main teaching notebook** (turn-in artifact for the course). Full XAI walkthrough with LIME, SHAP, ELI5, and a feature reduction experiment based on Kuzlu et al. 2020 | | `notebooks/spam_classifier_gradio.ipynb` | Shorter pipeline focused on the ensemble model and Gradio deployment | ## Documentation - `docs/references/how-to.html` — full reference index with clickable links to all local PDFs (LIME, SHAP, TreeSHAP, Kuzlu et al., 5 spam-detection papers) and HTML guides (sklearn user guide, Gradio quickstart, HF Spaces docs, Molnar Interpretable ML book) - `docs/07-code-sources-reference.md` — markdown version of the references with citation entries - `CHANGELOG.md` — full project history from v0.1 (Streamlit) through v1.1 (merged Gradio) ## Tech Stack - **scikit-learn** — Random Forest, Logistic Regression, LinearSVC, VotingClassifier, CalibratedClassifierCV, TfidfVectorizer, MinMaxScaler, GridSearchCV, metrics - **LIME + SHAP + ELI5** — explainability - **Gradio** — web interface (live deployment on HuggingFace Spaces) - **NLTK** — text preprocessing (Porter stemmer, English stopwords) - **scipy.sparse** — efficient handling of TF-IDF + metadata feature combination ## Sibling Projects This is the sklearn / classical ML variant. Two LLM-based variants are in sibling folders: - `../spam-classifier-mlx/` — Apple MLX LoRA fine-tune of Qwen3.5-0.8B - `../spam-classifier-liquid/` — HuggingFace TRL+PEFT LoRA fine-tune of Liquid AI LFM2.5-1.2B ## Citation If you reference this work academically: ``` Balfour, D. (2026). Spam Email Classifier with Explainable AI. ENGT 375 Applied Machine Learning project, Old Dominion University, Spring 2026. https://huggingface.co/spaces/VoltageVagabond/spam-xai-classifier-v2 ```