{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "4fdb8ebc-f8b6-450f-b3f1-0d279af091c7",
   "metadata": {},
   "source": [
    "# 📩 SMS Spam Classification using NLP\n",
    "\n",
    "## Project Information\n",
    "- **Student Name:** Fahad AbuBaker Baashwan \n",
    "- **University:** MidOcean University \n",
    "- **Course:** Practical ImageProcessing and Natural Language Processing - Second Trimester 2025\n",
    "- **Project Title:** SMS Spam Classification using NLP  - Project (2)\n",
    "\n",
    "---\n",
    "\n",
    "## Project Overview\n",
    "This project applies **Natural Language Processing (NLP)** techniques to classify SMS messages as **spam** or **ham (not spam)**.  \n",
    "We will use the **SMS Spam Collection Dataset** from Kaggle.  https://www.kaggle.com/datasets/uciml/sms-spam-collection-dataset\n",
    "\n",
    "### Objectives\n",
    "1. Apply data preprocessing  \n",
    "2. Split the dataset  \n",
    "3. Apply feature representation methods (Bag-of-Words, TF-IDF)  \n",
    "4. Train and evaluate classification models  \n",
    "\n",
    "---\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "58a6e268-b3a7-41d5-a04a-fac1b843fdb5",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 📌 Step 1: Import Libraries\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "from sklearn.naive_bayes import MultinomialNB\n",
    "from sklearn.svm import LinearSVC\n",
    "from sklearn.metrics import classification_report, confusion_matrix\n",
    "import seaborn as sns\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f559777d-bc7b-4ff0-b581-a508983aaab8",
   "metadata": {},
   "source": [
    "## Step 2: Load and Inspect Dataset\n",
    "We load the SMS Spam Collection dataset from Kaggle (`spam.csv`).  \n",
    "It contains:\n",
    "- **label** → `ham` or `spam`  \n",
    "- **message** → the text of the SMS  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "5d2f9d23-6a18-4451-b15f-4fcbdecae42c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>label</th>\n",
       "      <th>message</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>ham</td>\n",
       "      <td>Go until jurong point, crazy.. Available only ...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>ham</td>\n",
       "      <td>Ok lar... Joking wif u oni...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>spam</td>\n",
       "      <td>Free entry in 2 a wkly comp to win FA Cup fina...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>ham</td>\n",
       "      <td>U dun say so early hor... U c already then say...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>ham</td>\n",
       "      <td>Nah I don't think he goes to usf, he lives aro...</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  label                                            message\n",
       "0   ham  Go until jurong point, crazy.. Available only ...\n",
       "1   ham                      Ok lar... Joking wif u oni...\n",
       "2  spam  Free entry in 2 a wkly comp to win FA Cup fina...\n",
       "3   ham  U dun say so early hor... U c already then say...\n",
       "4   ham  Nah I don't think he goes to usf, he lives aro..."
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Load dataset\n",
    "df = pd.read_csv(\"spam.csv\", encoding='latin-1')\n",
    "\n",
    "# Keep only necessary columns\n",
    "df = df[['v1', 'v2']]\n",
    "df.columns = ['label', 'message']\n",
    "\n",
    "# Show sample\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9026f59e-9f64-42f0-8bb9-ea8ac439c0a3",
   "metadata": {},
   "source": [
    "## Step 3: Data Preprocessing\n",
    "- Convert labels (`ham`, `spam`) into numeric values  \n",
    "- Handle missing values  \n",
    "- Text preprocessing (lowercase, stopword removal handled by vectorizer)  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "3f7ac57f-d501-40f1-b094-93163ab583ae",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "label\n",
      "0    4825\n",
      "1     747\n",
      "Name: count, dtype: int64\n"
     ]
    }
   ],
   "source": [
    "# Encode labels\n",
    "df['label'] = df['label'].map({'ham': 0, 'spam': 1})\n",
    "\n",
    "# Check class balance\n",
    "print(df['label'].value_counts())\n",
    "\n",
    "# Features and labels\n",
    "X = df['message']\n",
    "y = df['label']"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4e53b6f2-dcfc-4da3-928f-37ec9fb69deb",
   "metadata": {},
   "source": [
    "## Step 4: Train-Test Split\n",
    "We split the dataset:\n",
    "- 80% training  \n",
    "- 20% testing  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "a9c850f5-0c7b-45a0-b341-ea04ce7a3275",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Training samples: 4457\n",
      "Testing samples: 1115\n"
     ]
    }
   ],
   "source": [
    "X_train, X_test, y_train, y_test = train_test_split(\n",
    "    X, y, test_size=0.2, random_state=42, stratify=y\n",
    ")\n",
    "print(\"Training samples:\", len(X_train))\n",
    "print(\"Testing samples:\", len(X_test))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "72cef874-5c8b-4e13-a8ba-38b16c5b1353",
   "metadata": {},
   "source": [
    "## Step 5: Feature Representation\n",
    "We compare:\n",
    "1. **Bag-of-Words (CountVectorizer)**  \n",
    "2. **TF-IDF (TfidfVectorizer)**  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "ba00720a-3602-48ba-9b67-1b57706986fe",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Count Vectorizer\n",
    "count_vec = CountVectorizer(stop_words=\"english\")\n",
    "X_train_count = count_vec.fit_transform(X_train)\n",
    "X_test_count = count_vec.transform(X_test)\n",
    "\n",
    "# TF-IDF Vectorizer\n",
    "tfidf = TfidfVectorizer(stop_words=\"english\")\n",
    "X_train_tfidf = tfidf.fit_transform(X_train)\n",
    "X_test_tfidf = tfidf.transform(X_test)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5e13ed3b-09ac-4618-b681-eba474fbd76e",
   "metadata": {},
   "source": [
    "## Step 6: Train Models\n",
    "We train three models using **TF-IDF features**:\n",
    "1. Logistic Regression  \n",
    "2. Naive Bayes  \n",
    "3. Support Vector Machine (SVM)  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "a344b6ae-474f-45d1-9699-e996696e7e86",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Logistic Regression\n",
    "lr = LogisticRegression(max_iter=200)\n",
    "lr.fit(X_train_tfidf, y_train)\n",
    "y_pred_lr = lr.predict(X_test_tfidf)\n",
    "\n",
    "# Naive Bayes\n",
    "nb = MultinomialNB()\n",
    "nb.fit(X_train_tfidf, y_train)\n",
    "y_pred_nb = nb.predict(X_test_tfidf)\n",
    "\n",
    "# SVM\n",
    "svm = LinearSVC()\n",
    "svm.fit(X_train_tfidf, y_train)\n",
    "y_pred_svm = svm.predict(X_test_tfidf)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "28c2abb5-d165-4d29-9f95-abe0fb9454b4",
   "metadata": {},
   "source": [
    "## Step 7: Evaluation\n",
    "We use:\n",
    "- Accuracy  \n",
    "- Precision  \n",
    "- Recall  \n",
    "- F1-score  \n",
    "- Confusion Matrix  \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "24ad6316-7c3d-4f6f-8349-49488abbc42b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "📊 Logistic Regression:\n",
      "              precision    recall  f1-score   support\n",
      "\n",
      "           0       0.96      1.00      0.98       966\n",
      "           1       1.00      0.76      0.86       149\n",
      "\n",
      "    accuracy                           0.97      1115\n",
      "   macro avg       0.98      0.88      0.92      1115\n",
      "weighted avg       0.97      0.97      0.97      1115\n",
      "\n",
      "📊 Naive Bayes:\n",
      "              precision    recall  f1-score   support\n",
      "\n",
      "           0       0.97      1.00      0.98       966\n",
      "           1       1.00      0.77      0.87       149\n",
      "\n",
      "    accuracy                           0.97      1115\n",
      "   macro avg       0.98      0.88      0.92      1115\n",
      "weighted avg       0.97      0.97      0.97      1115\n",
      "\n",
      "📊 SVM:\n",
      "              precision    recall  f1-score   support\n",
      "\n",
      "           0       0.98      1.00      0.99       966\n",
      "           1       0.99      0.89      0.94       149\n",
      "\n",
      "    accuracy                           0.98      1115\n",
      "   macro avg       0.99      0.94      0.96      1115\n",
      "weighted avg       0.98      0.98      0.98      1115\n",
      "\n"
     ]
    }
   ],
   "source": [
    "print(\"📊 Logistic Regression:\")\n",
    "print(classification_report(y_test, y_pred_lr))\n",
    "\n",
    "print(\"📊 Naive Bayes:\")\n",
    "print(classification_report(y_test, y_pred_nb))\n",
    "\n",
    "print(\"📊 SVM:\")\n",
    "print(classification_report(y_test, y_pred_svm))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "c39ff5f0-07ba-4471-a725-7d65f173ecea",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAhsAAAHHCAYAAAAWM5p0AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAPNFJREFUeJzt3QmcTfX/x/HPGcYY+5I1ico22SlZSiJC9lR+Qj9byb7FlCUKpSJLURIqhZCkhB+yRGWJskRFlrKvoWFw/4/Pt8e9/7ljaIb7nTtzz+v5e5zfzD3n3HO/947pvOfz/X7PcTwej0cAAAAsCbN1YAAAAEXYAAAAVhE2AACAVYQNAABgFWEDAABYRdgAAABWETYAAIBVhA0AAGAVYQMAAFhF2IDr/PLLL1K7dm3JmjWrOI4j8+bNC+jxf//9d3PcqVOnBvS4qdn9999vFgDuRNhAUPz222/y1FNPyW233Sbp06eXLFmySNWqVWXMmDHy999/W33tNm3ayE8//STDhg2TDz74QCpWrCih4sknnzRBRz/PhD5HDVq6XZfXXnstycf/888/5YUXXpBNmzZJanHhwgXz76pcuXLmc8mWLZvceeed0rFjR/n555/NPg0bNpQMGTLIX3/9ddXjtGzZUtKlSyfHjh0zj72fY/v27RPc//nnn/ftc/ToUUvvDkgd0ga7AXCfL774Qpo3by4RERHSunVrKVmypDkhrF69Wvr27Stbt26Vd955x8pr6wl47dq15kTQpUsXK69x6623mtcJDw+XYEibNq2cO3dOPv/8c3n00Uf9tk2fPt2Eu5iYmOs6toaNIUOGSKFChaRs2bKJft7ixYslWJo1ayYLFy6UFi1aSIcOHSQ2NtaEjAULFkiVKlWkePHiJkjo5/Xpp5+af5Px6ef52WefyUMPPSQ5c+b0rdfPcs6cOfLWW2+ZIBLXxx9/fEOfNRBKCBtIVrt375bHH3/cnJCXLVsm+fLl823r3Lmz/PrrryaM2HLkyBHzVf+6tUX/ktWTTLBoiNMqkZ7s4oeNjz76SOrXr29OkMlBT9JaMYh/Ik4u69atM6FCq1jPPfec37bx48fLyZMnfZWNzJkzm88nobChQePs2bMmlMSl4WP+/PkmzDRq1Mi3fs2aNebfugad5PqsgZSMbhQkq5EjR8qZM2dk8uTJfkHD64477pDu3bv7Hl+8eFFefPFFuf32281JVP+i1pPG+fPn/Z6n6x9++GFTHbn77rvNyV67aN5//33fPlr+15CjtIKioUCf5+1+8H4flz5H94tryZIlUq1aNRNYMmXKJMWKFfM7kV1tzIaGq3vvvVcyZsxonqsnp+3btyf4ehq6tE26n44t+e9//2tO3In1n//8x5wAvSdT74lXu1F0W3zHjx+XPn36SKlSpcx70u6GunXryubNm337fP3113LXXXeZ77U93i4C7/vUMRlapdqwYYPcd999JmR4P5f4Yza0K0t/RvHff506dSR79uymghKo7jql4Su+NGnS+KoUkZGR0rRpU1m6dKkcPnz4in01hGgY0VAS180332zeq26PX0HSz1I/DwCEDSQzLVVrCNDydWJof/igQYOkfPnyMnr0aKlevbqMGDHCVEfi0xP0I488Ig8++KC8/vrr5qSlJ2ztllF6MtFjKC2p63iNN954I0nt12NpqNGwM3ToUPM6egL65ptvrvm8//3vf+ZEqicyDRS9evUyf/3qSVDDSXxakdDxA/pe9Xs9oWv3RWLpe9UgMHfuXN86PSFql4F+lvHt2rXLDJTV9zZq1CgTxnRci37e3hN/iRIlzHtWOt5BPz9d9GTrpeMZNKRoF4t+tjVq1EiwfTqGIleuXCZ0XLp0yax7++23TXfLuHHjJH/+/BII3nCpJ38NrteiVQvdZ9asWVcEsUWLFkmTJk1MKIlPw5v+u9YQrfQYn3zySYKhDnAtD5BMTp065dF/co0aNUrU/ps2bTL7t2/f3m99nz59zPply5b51t16661m3cqVK33rDh8+7ImIiPD07t3bt2737t1mv1dffdXvmG3atDHHiG/w4MFmf6/Ro0ebx0eOHLlqu72vMWXKFN+6smXLenLnzu05duyYb93mzZs9YWFhntatW1/xem3btvU7ZpMmTTw5c+a86mvGfR8ZM2Y03z/yyCOemjVrmu8vXbrkyZs3r2fIkCEJfgYxMTFmn/jvQz+/oUOH+tatW7fuivfmVb16dbNt4sSJCW7TJa5FixaZ/V966SXPrl27PJkyZfI0btzYE0iXL1/2tStPnjyeFi1aeN58803Pnj17rtj34sWLnnz58nkqV67st17fjz5f2xuXruvcubPn+PHjnnTp0nk++OADs/6LL77wOI7j+f33330/z2v9ewHcgMoGks3p06fN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",
      "text/plain": [
       "<Figure size 640x480 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Confusion Matrix Visualization (SVM as example)\n",
    "cm = confusion_matrix(y_test, y_pred_svm)\n",
    "sns.heatmap(cm, annot=True, fmt=\"d\", cmap=\"Blues\", xticklabels=['Ham','Spam'], yticklabels=['Ham','Spam'])\n",
    "plt.title(\"Confusion Matrix - SVM\")\n",
    "plt.xlabel(\"Predicted\")\n",
    "plt.ylabel(\"Actual\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "39d5a6d4-2b1e-47ff-b48f-891462028bc7",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
