--- 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 --- # Spam Email Classifier with XAI Explanations **ENGT 375 — Applied Machine Learning | Spring 2026 | Old Dominion University** > **Disclaimer:** This model was created as a student project for Applied Machine Learning at ODU. It is intended for **educational and research purposes only** and should not be used as a sole spam/phishing filter in production. Classification accuracy may vary, and the model may produce incorrect or misleading results. Always use established email security tools for real-world spam filtering. 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 ```