{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "094693df",
   "metadata": {},
   "source": [
    "# SMS Spam Detection : BiLSTM vs TF-IDF\n",
    "\n",
    "**Author:** Fils Aboubakar Sidik MBOHOU  \n",
    "**School:** ESAIP Engineering School, France  \n",
    "**Program:** MSc Cybersecurity & Data Science  \n",
    "**Program period:** 2024–2026  \n",
    "**Project type:** Individual academic project\n",
    "\n",
    "This notebook classifies SMS messages as **ham** or **spam** and compares two approaches: a Bidirectional LSTM and TF-IDF + Logistic Regression.\n",
    "\n",
    "The project uses the 5,572-row CSV variant of the SMS Spam Collection. After removing exact duplicate messages, 5,157 unique messages remain for modeling. The main question is not only which model scores best, but whether the extra complexity of the BiLSTM produces a meaningful gain over a much simpler baseline.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bbd49d3d",
   "metadata": {},
   "source": [
    "## 1. Environment and reproducibility\n",
    "\n",
    "A fixed random seed is used for reproducibility. The published outputs were generated with the **JAX** Keras backend. To make the public notebook easier to run on Windows, the setup cell uses JAX when it is installed and otherwise falls back to TensorFlow, then PyTorch.\n",
    "\n",
    "> Deep-learning scores can vary slightly with the backend, operating system and library versions. The data split, threshold-selection rule and evaluation protocol stay unchanged.\n",
    "\n",
    "Required packages: `numpy`, `pandas`, `matplotlib`, `scikit-learn`, `keras` and at least one Keras backend (`jax`, `tensorflow` or `torch`).\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "64ca1bf2",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-18T18:30:20.663151Z",
     "iopub.status.busy": "2026-10-18T18:30:20.663025Z",
     "iopub.status.idle": "2026-10-18T18:30:22.811699Z",
     "shell.execute_reply": "2026-10-18T18:30:22.810820Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Python: 3.13.5\n",
      "Keras: 3.13.2\n",
      "Keras backend: jax\n",
      "Random seed: 42\n"
     ]
    }
   ],
   "source": [
    "# Select an available Keras backend before importing Keras.\n",
    "import importlib.util\n",
    "import os\n",
    "from pathlib import Path\n",
    "\n",
    "os.environ[\"PYTHONHASHSEED\"] = \"42\"\n",
    "os.environ.setdefault(\"MPLCONFIGDIR\", str((Path.cwd() / \".mplconfig\").resolve()))\n",
    "\n",
    "if \"KERAS_BACKEND\" not in os.environ:\n",
    "    if importlib.util.find_spec(\"jax\") is not None:\n",
    "        os.environ[\"KERAS_BACKEND\"] = \"jax\"\n",
    "    elif importlib.util.find_spec(\"tensorflow\") is not None:\n",
    "        os.environ[\"KERAS_BACKEND\"] = \"tensorflow\"\n",
    "    elif importlib.util.find_spec(\"torch\") is not None:\n",
    "        os.environ[\"KERAS_BACKEND\"] = \"torch\"\n",
    "    else:\n",
    "        raise ImportError(\n",
    "            \"Install a Keras backend first: tensorflow, jax or torch.\"\n",
    "        )\n",
    "\n",
    "import json\n",
    "import random\n",
    "import re\n",
    "import platform\n",
    "from collections import Counter\n",
    "\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "from sklearn.metrics import (\n",
    "    accuracy_score,\n",
    "    average_precision_score,\n",
    "    classification_report,\n",
    "    confusion_matrix,\n",
    "    ConfusionMatrixDisplay,\n",
    "    precision_recall_fscore_support,\n",
    "    roc_auc_score,\n",
    ")\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.utils.class_weight import compute_class_weight\n",
    "\n",
    "import keras\n",
    "from keras import layers\n",
    "\n",
    "SEED = 42\n",
    "random.seed(SEED)\n",
    "np.random.seed(SEED)\n",
    "keras.utils.set_random_seed(SEED)\n",
    "\n",
    "ASSET_DIR = Path(\"spam_final_assets\")\n",
    "ASSET_DIR.mkdir(exist_ok=True)\n",
    "\n",
    "print(\"Python:\", platform.python_version())\n",
    "print(\"Keras:\", keras.__version__)\n",
    "print(\"Keras backend:\", keras.backend.backend())\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ec579984",
   "metadata": {},
   "source": [
    "## 2. Load and check the dataset\n",
    "\n",
    "Place `spam.csv` in the same folder as the notebook. The loader accepts the two common schemas for the 5,572-row CSV variant:\n",
    "\n",
    "- `Category`, `Message`; or\n",
    "- `v1`, `v2` (the common Kaggle export).\n",
    "\n",
    "The notebook verifies the exact row and class counts used for the portfolio results before continuing. This prevents a different SMS collection from silently producing different metrics.\n",
    "\n",
    "Dataset origin: SMS Spam Collection by Almeida & Hidalgo (UCI Machine Learning Repository, DOI: https://doi.org/10.24432/C5CC84). The public CSV variant used here is the common 5,572-row export."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "5f6a4250",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-18T18:30:22.813642Z",
     "iopub.status.busy": "2026-10-18T18:30:22.813178Z",
     "iopub.status.idle": "2026-10-18T18:30:22.863958Z",
     "shell.execute_reply": "2026-10-18T18:30:22.863279Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Raw shape: (5572, 2)\n",
      "Missing values:\n",
      "Category    0\n",
      "Message     0\n",
      "dtype: int64\n",
      "\n",
      "Raw class distribution:\n",
      "Category\n",
      "ham     4825\n",
      "spam     747\n",
      "Name: count, dtype: int64\n"
     ]
    }
   ],
   "source": [
    "DATA_PATH = Path(\"spam.csv\")\n",
    "\n",
    "if not DATA_PATH.exists():\n",
    "    raise FileNotFoundError(\n",
    "        \"Place spam.csv in the same folder as this notebook before running it. \"\n",
    "        \"Expected: the 5,572-row SMS Spam Collection CSV variant.\"\n",
    "    )\n",
    "\n",
    "raw = pd.read_csv(DATA_PATH, encoding=\"latin1\")\n",
    "raw = raw.loc[:, ~raw.columns.astype(str).str.startswith(\"Unnamed\")]\n",
    "\n",
    "if {\"Category\", \"Message\"}.issubset(raw.columns):\n",
    "    source = raw[[\"Category\", \"Message\"]].copy()\n",
    "elif {\"v1\", \"v2\"}.issubset(raw.columns):\n",
    "    source = raw[[\"v1\", \"v2\"]].rename(\n",
    "        columns={\"v1\": \"Category\", \"v2\": \"Message\"}\n",
    "    )\n",
    "else:\n",
    "    raise ValueError(\n",
    "        \"Unsupported spam.csv schema. Expected Category/Message or v1/v2. \"\n",
    "        f\"Found: {list(raw.columns)}\"\n",
    "    )\n",
    "\n",
    "print(\"Raw shape:\", source.shape)\n",
    "print(\"Missing values:\")\n",
    "print(source.isna().sum())\n",
    "\n",
    "if source.isna().any().any():\n",
    "    raise ValueError(\"The canonical project dataset contains no missing label/message values.\")\n",
    "\n",
    "df_raw = source.copy()\n",
    "df_raw[\"Category\"] = df_raw[\"Category\"].astype(str).str.strip().str.lower()\n",
    "df_raw[\"Message\"] = df_raw[\"Message\"].astype(str).str.strip()\n",
    "\n",
    "print()\n",
    "print(\"Raw class distribution:\")\n",
    "print(df_raw[\"Category\"].value_counts())\n",
    "\n",
    "expected = {\"rows\": 5572, \"ham\": 4825, \"spam\": 747}\n",
    "observed = {\n",
    "    \"rows\": len(df_raw),\n",
    "    \"ham\": int((df_raw[\"Category\"] == \"ham\").sum()),\n",
    "    \"spam\": int((df_raw[\"Category\"] == \"spam\").sum()),\n",
    "}\n",
    "if observed != expected:\n",
    "    raise ValueError(\n",
    "        \"This notebook reproduces the published portfolio metrics for the \"\n",
    "        f\"5,572-row CSV variant {expected}, but this file contains {observed}. \"\n",
    "        \"Use the same spam.csv variant to reproduce the published scores.\"\n",
    "    )\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "42475824",
   "metadata": {},
   "source": [
    "## 3. Explore the data\n",
    "\n",
    "Before choosing a model, I look at the data itself.\n",
    "\n",
    "The main questions are:\n",
    "\n",
    "- How imbalanced are ham and spam messages?\n",
    "- Are spam messages typically longer?\n",
    "- Which words appear frequently in each class?\n",
    "\n",
    "These checks do not train the final models. They help explain the problem and guide later choices such as class weighting and evaluation metrics.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "d066e0a2",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-18T18:30:22.865562Z",
     "iopub.status.busy": "2026-10-18T18:30:22.865420Z",
     "iopub.status.idle": "2026-10-18T18:30:23.068926Z",
     "shell.execute_reply": "2026-10-18T18:30:23.068349Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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bNmidu3a6f7779fmzZsl/T0LZbPZzNOAOTl58qSio6PVt29fVaxY0WFb1s9LRkaG1q9fryeeeEJVqlQxt5crV049evTQli1blJqa6rDvgAED5OTklONrhoeHOzzPuqEkL+8bb29vbd++XcePH8/1vij8CE4oMho2bKivvvpKZ86c0U8//aSxY8fq7Nmz6tKliw4cOJDjPj169NCBAwe0e/duLVq0SE8//fQNg0xoaKjWrVun5ORkRUdHKzw8XMeOHVP79u1veIH4kSNHJMnyacSrrVq1So0bN5arq6tKly6tsmXLas6cOUpJSTH7dOvWTU2aNFH//v3l5+enp59+WsuWLXMIUWPGjJGHh4ceeughVa9eXeHh4Q6n8q7n2LFjqlatWravy81OmUl/nxq599571bZtW1WoUMEMn7lRuXLlXPWvXr26w3MPDw+VK1fuli8pcOzYMVWvXj3bnX5Zp/aOHTvm0H5tIMgKUddej3W1jIwMJSYm5ulx8uRJS+PI6et9+vRpDRs2TH5+fnJzc1PZsmXNfle/D0NCQnTlyhXFxMTo0KFDOnHihEJCQtSsWTOH4BQUFKTSpUtft4as8Hijn5eTJ0/qwoULOb4Pa9WqpczMTCUkJNx0bFmufd9UrVpVxYoVy9P7Ztq0adq3b58CAgL00EMPaeLEiQUeiJF/CE4ocpydndWwYUO98cYbmjNnji5fvqzly5fn2LdRo0aqWrWqhg8frri4OMtLCri7uyskJEQzZ87UuHHjdObMGa1duzY/hyHp718yHTt2lKurq2bPnq01a9YoMjJSPXr0MK8/kf6eEYiOjtb333+vZ599Vnv27FG3bt3UunVrZWRkSPr7l8mhQ4e0ZMkSNW3aVF9++aWaNm2qCRMm5HvdWXx9fbVr1y5999136tixozZs2KC2bduqd+/elo9x9WzHrZb1tbodrjfzcfX39VoJCQkqV65cnh4NGza0VFdOX++uXbtq/vz5GjRokL766iutX7/eDMBXh/MGDRrI1dVV0dHR2rx5s3x9fXXvvfcqJCREP/30k9LS0rR58+brzurearl5L137H4Xr/Ycqp/dM165d9ccff+iDDz5Q+fLl9fbbb6t27dq35N8I3H5cHI4irUGDBpKkv/7667p9unfvrtdff121atXS/ffff0teI+vi83379qlatWqWj/3ll1/K1dVV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AAAAVhVocHrppZe0adMmHT16VFu3btWTTz4pJycnde/eXV5eXurXr59GjhypDRs2KDY2Vn369FFwcLAaN24sSWrTpo2CgoL07LPPavfu3Vq3bp3GjRun8PBwubi4SJIGDRqkP/74Q6NHj9bBgwc1e/ZsLVu2TCNGjCjIoQMAgDtQgV7j9Oeff6p79+46deqUypYtq6ZNm2rbtm0qW7asJGn69OkqVqyYOnfurLS0NIWGhmr27Nnm/k5OTlq1apVeeOEFBQcHq2TJkurdu7cmT55s9qlcubJWr16tESNG6P3331eFChX00UcfWV7DCQAAIEuBruN0p2AdJwAAiq47ah0nAACAOwXBCQAAwCKCEwAAgEUEJwAAAIsK9K463DkCX15d0CWgABx9M6ygSwCAQoUZJwAAAIsITgAAABYRnAAAACwiOAEAAFhEcAIAALCI4AQAAGARwQkAAMAighMAAIBFBCcAAACLCE4AAAAWEZwAAAAsIjgBAABYRHACAACwiOAEAABgEcEJAADAIoITAACARQQnAAAAiwhOAAAAFhGcAAAALCI4AQAAWERwAgAAsIjgBAAAYBHBCQAAwCKCEwAAgEUEJwAAAIsITgAAABYRnAAAACwiOAEAAFhEcAIAALCI4AQAAGARwQkAAMAighMAAIBFBCcAAACLCE4AAAAWEZwAAAAsIjgBAABYRHACAACwiOAEAABgEcEJAADAIoITAACARQQnAAAAiwhOAAAAFhGcAAAALCI4AQAAWFRogtObb74pm82m4cOHm22XLl1SeHi4fHx85OHhoc6dOyspKclhv/j4eIWFhcnd3V2+vr4aNWqUrly54tBn48aNevDBB+Xi4qJq1appwYIFt2FEAACgqCkUwWnHjh2aN2+e6tat69A+YsQIrVy5UsuXL9emTZt0/PhxderUydyekZGhsLAwpaena+vWrVq4cKEWLFig8ePHm33i4uIUFhamFi1aaNeuXRo+fLj69++vdevW3bbxAQCAoqHAg9O5c+fUs2dPzZ8/X6VKlTLbU1JS9PHHH+vdd9/Vo48+qvr16+uTTz7R1q1btW3bNknS+vXrdeDAAX3++ee6//771bZtW7322muaNWuW0tPTJUlz585V5cqV9c4776hWrVoaMmSIunTpounTpxfIeAEAwJ2rwINTeHi4wsLC1KpVK4f22NhYXb58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",
      "text/plain": [
       "<Figure size 600x400 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "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>count</th>\n",
       "      <th>mean</th>\n",
       "      <th>median</th>\n",
       "      <th>min</th>\n",
       "      <th>max</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Category</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>ham</th>\n",
       "      <td>4825</td>\n",
       "      <td>71.5</td>\n",
       "      <td>52.0</td>\n",
       "      <td>2</td>\n",
       "      <td>910</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>spam</th>\n",
       "      <td>747</td>\n",
       "      <td>138.4</td>\n",
       "      <td>149.0</td>\n",
       "      <td>7</td>\n",
       "      <td>224</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "          count   mean  median  min  max\n",
       "Category                                \n",
       "ham        4825   71.5    52.0    2  910\n",
       "spam        747  138.4   149.0    7  224"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Message length is a simple descriptive feature for exploration only.\n",
    "eda = df_raw.copy()\n",
    "eda[\"message_length\"] = eda[\"Message\"].str.len()\n",
    "\n",
    "# Class distribution\n",
    "fig, ax = plt.subplots(figsize=(6, 4))\n",
    "eda[\"Category\"].value_counts().reindex([\"ham\", \"spam\"]).plot(kind=\"bar\", ax=ax)\n",
    "ax.set_title(\"SMS class distribution : raw corpus\")\n",
    "ax.set_xlabel(\"Class\")\n",
    "ax.set_ylabel(\"Messages\")\n",
    "ax.tick_params(axis=\"x\", rotation=0)\n",
    "fig.tight_layout()\n",
    "fig.savefig(ASSET_DIR / \"01_class_distribution.png\", dpi=160, bbox_inches=\"tight\")\n",
    "plt.show()\n",
    "\n",
    "# Summary of message lengths by class\n",
    "length_summary = eda.groupby(\"Category\")[\"message_length\"].agg(\n",
    "    [\"count\", \"mean\", \"median\", \"min\", \"max\"]\n",
    ")\n",
    "display(length_summary.round(1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "cef566d1",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-18T18:30:23.070278Z",
     "iopub.status.busy": "2026-10-18T18:30:23.070127Z",
     "iopub.status.idle": "2026-10-18T18:30:23.372952Z",
     "shell.execute_reply": "2026-10-18T18:30:23.372173Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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nFz9jNatW5djH68eq380adIkY7PZzLFjx4wxxvzyyy9GknnrrbduuP1bOU4B4CpOhQKAP9GlSxf99ttvWrFihX799VetWLHihqdBLVy4UN7e3mrZsqV+/vln61W3bl15enpaMwQ+Pj6SpBUrVigjI+O66/Lx8dHFixftTsO6lpubm5ycfv9PeVZWls6dOydPT09VqVJFO3futMatWrVK5cqV0+OPP261ubu7q1+/fnbrS0xM1KFDh9S9e3edO3fOqv/ixYtq0aKFNm7cqOzs7D//0P6/8+fPa+3aterSpYt+/fVXa33nzp1TZGSkDh06lONUoP79+8tms1nvGzdurKysLB07dkyStGbNGmVmZmrgwIF2yw0ePPiW67qqevXqaty4sfW+TJkyqlKlin744YdbWr5jx452Mw7169dXgwYN9NVXX1ltPXv21KlTp+xmh2JjY+Xh4aFOnTrdcN3Z2dlatmyZ2rdvr3r16uXo/+NndC0PDw/r54sXL+rnn39Ww4YNZYyxTsvy8PCQq6ur1q9fn+M0vatu5TgFgKsIFgDwJ8qUKaOIiAh99tlnWrJkibKystS5c+frjj106JBSU1Pl7++vMmXK2L0uXLigs2fPSpKaNm2qTp06ady4cSpdurQ6dOiguXPnKj093VrXwIEDdf/996tNmzYqX768+vTpo1WrVtltLzs7W++9954qV64sNzc3lS5dWmXKlNHu3buVmppqjTt27Jjuu+++HF9GK1WqlKN+SYqOjs5R/0cffaT09HS79f6Zw4cPyxij0aNH51jfq6++KknWZ3JVSEiI3ftSpUpJkvXl92rAuLZ2X19fa+ytunZbV7d3oy/a16pcuXKOtvvvv9/uGoWWLVuqbNmyio2NlfT77+zzzz9Xhw4dVLJkyRuu+6efflJaWppq1qx5S7X80fHjx9WrVy/5+vrK09NTZcqUUdOmTSXJ+v25ubnpzTff1MqVKxUQEKAmTZpo8uTJSk5OttZzK8cpAFzFNRYAcAu6d++ufv36KTk5WW3atLH+knut7Oxs+fv7W18ir1WmTBlJv/+1edGiRdq2bZuWL1+u1atXq0+fPnrnnXe0bds2eXp6yt/fX4mJiVq9erVWrlyplStXau7cuerZs6c++eQTSb9fADx69Gj16dNHr732mnx9feXk5KShQ4fe1szCH+uXpLfeeksPPvjg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KlmypJo2bSpJ1rKJiYlq3LixihUrdsu17tq1S4cPH1bJkiXl6ekpT09P+fr66vLly/rf//53w3patmypChUqqGLFiurRo4diY2N16dKlm27LxcVFDz30kPW+atWq8vHx0b59+6xaxo8fb9Xh6empfv366fTp03brrlev3p/uV0xMjJKTkxUbG6vw8HAtXLhQNWrUUFxcXI6xTz/9tLZu3aoffvhB8+bNu+4siLOzs+bOnasff/xRkydPVrly5fT666+rRo0aOn369J/WAwD5jWABAIVQ5cqVZbPZ7O4odDPXfrG32WzKzs6WJC1YsEAvvPCC+vbtq6+//lqJiYnq3bt3jguirz3l6uLFi4qMjJSXl5diY2O1fft2LV26VNL/XUzt4eFx2/t24cIF1a1bV4mJiXavgwcPqnv37jesp2TJktq5c6c+//xzlS1bVmPGjNEDDzyQ4+Lo261l3LhxdnXs2bNHhw4dkru7+w1ruZGSJUuqffv2mjhxonbt2qXGjRtrwoQJOcb5+fnpscceU9++fXX58mW1adPmhussV66cevTooenTp2vv3r26fPmyZs2adfs7CwB3GMECAAohX19fRUZGasaMGbp48WKO/tv5Mr1lyxY1bNhQAwcOVJ06dVSpUiW7mYEb2b9/v86dO6c33nhDjRs3VtWqVe1mQaTfZ0o2bdp03TslSbruHYz+8pe/6NChQ/L391elSpXsXt7e3jetycXFRREREZo8ebJ2796to0ePau3atTccn5mZqR07dljvDxw4oJSUFFWrVs2q5cCBAznqqFSpkpycHPtfpM1mU9WqVa/7+5OkPn36aP369erZs6ecnZ1vaZ2lSpVS2bJlb7hOAChIBAsAKKRmzJihrKws1a9fX4sXL9ahQ4e0b98+TZ06VeHh4be8nsqVK2vHjh1avXq1Dh48qNGjR2v79u1/ulxISIhcXV01bdo0/fDDD/r3v/+t1157zW7MoEGDlJaWpq5du2rHjh06dOiQPv30Ux04cECSFBoaqt27d+vAgQP6+eeflZGRoaioKJUuXVodOnTQpk2bdOTIEa1fv17PPfecfvzxxxvWs2LFCk2dOlWJiYk6duyY5s+fr+zsbFWpUuWGyxQrVkyDBw9WfHy8EhIS1KtXLz388MOqX7++JGnMmDGaP3++xo0bp71792rfvn1asGCBXnnllVv5aC2JiYnq0KGDFi1apKSkJB0+fFj/+Mc/9PHHH6tDhw7XXaZ169b66aefNH78+Ov2f/jhhxowYIC+/vpr/e9//9PevXv10ksvae/evWrfvv1t1QcA+YFgAQCFVMWKFbVz5041b95czz//vGrWrKmWLVtqzZo1mjlz5i2v55lnntGTTz6pv/71r2rQoIHOnTungQMH/ulyZcqU0bx587Rw4UJVr15db7zxht5++227MX5+flq7dq0uXLigpk2bqm7dupozZ451ala/fv1UpUoV1atXT2XKlNGWLVtUvHhxbdy4USEhIXryySdVrVo165QgLy+vG9bj4+OjJUuW6NFHH1W1atU0a9Ysff7556pRo8YNlylevLheeuklde/eXY0aNZKnp6e++OILqz8yMlIrVqzQ119/rYceekgPP/yw3nvvPVWoUOFPP58/Kl++vEJDQzVu3Dg1aNBAf/nLX/T+++9r3Lhxevnll6+7jM1mU+nSpXNc13JV/fr1deHCBT377LOqUaOGmjZtqm3btmnZsmXWtS4AUJjYzO1eIQgAQBEwb948DR061KFrMAAAt44ZCwAAAAAOI1gAAAAAcBinQgEAAABwGDMWAAAAABxGsAAAAADgMIIFAAAAAIcRLAAAAAA4jGABAAAAwGEECwAAAAAOI1gAAAAAcBjBAgAAAIDDCBYAAAAAHPb/AAsoN27ITCAKAAAAAElFTkSuQmCC",
      "text/plain": [
       "<Figure size 800x400 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Compare the distribution of SMS lengths for ham and spam.\n",
    "fig, ax = plt.subplots(figsize=(8, 4))\n",
    "\n",
    "for category in [\"ham\", \"spam\"]:\n",
    "    lengths = eda.loc[eda[\"Category\"] == category, \"message_length\"]\n",
    "    ax.hist(lengths, bins=50, alpha=0.55, label=category)\n",
    "\n",
    "ax.set_title(\"Message length by class\")\n",
    "ax.set_xlabel(\"Characters per SMS\")\n",
    "ax.set_ylabel(\"Messages\")\n",
    "ax.legend()\n",
    "fig.tight_layout()\n",
    "fig.savefig(ASSET_DIR / \"02_message_length_distribution.png\", dpi=160, bbox_inches=\"tight\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "34e24c74",
   "metadata": {},
   "source": [
    "## 4. Remove exact duplicate messages\n",
    "\n",
    "The dataset contains repeated SMS messages.\n",
    "\n",
    "If the same message appears in both training and test data, the evaluation can become artificially easy because the model may see an identical example during training.\n",
    "\n",
    "I therefore:\n",
    "\n",
    "1. check that identical messages do not have contradictory labels;\n",
    "2. remove exact duplicates;\n",
    "3. split the remaining unique messages only after this cleanup.\n",
    "\n",
    "This leaves **5,157 unique messages** for modeling.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "85622ac9",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-18T18:30:23.374354Z",
     "iopub.status.busy": "2026-10-18T18:30:23.374185Z",
     "iopub.status.idle": "2026-10-18T18:30:23.386592Z",
     "shell.execute_reply": "2026-10-18T18:30:23.385753Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Exact duplicate rows: 415\n",
      "Identical messages with conflicting labels: 0\n",
      "\n",
      "Unique modeling corpus: (5157, 2)\n",
      "Category\n",
      "ham     4516\n",
      "spam     641\n",
      "Name: count, dtype: int64\n"
     ]
    }
   ],
   "source": [
    "# Number of distinct labels attached to each exact message.\n",
    "label_counts_per_message = df_raw.groupby(\"Message\")[\"Category\"].nunique()\n",
    "conflicting_messages = int((label_counts_per_message > 1).sum())\n",
    "\n",
    "# Count repeated messages, keeping the first occurrence as the canonical row.\n",
    "exact_duplicates = int(\n",
    "    df_raw.duplicated(subset=[\"Message\"], keep=\"first\").sum()\n",
    ")\n",
    "\n",
    "print(\"Exact duplicate rows:\", exact_duplicates)\n",
    "print(\"Identical messages with conflicting labels:\", conflicting_messages)\n",
    "\n",
    "if conflicting_messages > 0:\n",
    "    raise ValueError(\n",
    "        \"At least one identical message has different labels. Manual review is required.\"\n",
    "    )\n",
    "\n",
    "# Canonical modeling corpus: one row per exact message.\n",
    "df = df_raw.drop_duplicates(subset=[\"Message\"], keep=\"first\").reset_index(drop=True)\n",
    "\n",
    "print()\n",
    "print(\"Unique modeling corpus:\", df.shape)\n",
    "print(df[\"Category\"].value_counts())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5136a469",
   "metadata": {},
   "source": [
    "## 5. Prepare the text\n",
    "\n",
    "The cleaning is intentionally light.\n",
    "\n",
    "I convert text to lowercase, replace URLs with a `urltoken` marker, remove punctuation and collapse repeated spaces. URLs are replaced rather than simply deleted because the presence of a link can itself be useful information in spam detection.\n",
    "\n",
    "The target is encoded as:\n",
    "\n",
    "- `ham = 0`\n",
    "- `spam = 1`\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "598b9e08",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-18T18:30:23.387825Z",
     "iopub.status.busy": "2026-10-18T18:30:23.387698Z",
     "iopub.status.idle": "2026-10-18T18:30:23.441442Z",
     "shell.execute_reply": "2026-10-18T18:30:23.440923Z"
    }
   },
   "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>Category</th>\n",
       "      <th>Message</th>\n",
       "      <th>cleaned_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",
       "      <td>go until jurong point crazy available only in ...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>ham</td>\n",
       "      <td>Ok lar... Joking wif u oni...</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",
       "      <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",
       "      <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",
       "      <td>nah i don t think he goes to usf he lives arou...</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  Category  ...                                    cleaned_message\n",
       "0      ham  ...  go until jurong point crazy available only in ...\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 arou...\n",
       "\n",
       "[5 rows x 3 columns]"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "URL_PATTERN = re.compile(r\"https?://\\S+|www\\.\\S+\", flags=re.IGNORECASE)\n",
    "\n",
    "\n",
    "def clean_text(text):\n",
    "    \"\"\"Return a simple normalized representation of one SMS.\"\"\"\n",
    "    text = str(text).lower()\n",
    "    text = URL_PATTERN.sub(\" urltoken \", text)       # keep the information that a URL existed\n",
    "    text = re.sub(r\"[^a-z0-9_]+\", \" \", text)       # keep letters, digits and underscores\n",
    "    text = re.sub(r\"\\s+\", \" \", text)             # collapse repeated spaces\n",
    "    return text.strip()\n",
    "\n",
    "\n",
    "df[\"cleaned_message\"] = df[\"Message\"].map(clean_text)\n",
    "df[\"label\"] = df[\"Category\"].map({\"ham\": 0, \"spam\": 1}).astype(int)\n",
    "\n",
    "df[[\"Category\", \"Message\", \"cleaned_message\"]].head()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c22f39b7",
   "metadata": {},
   "source": [
    "## 6. Look at common terms\n",
    "\n",
    "This section is descriptive. It shows frequent terms in ham and spam messages so the reader can see some of the vocabulary patterns in the corpus.\n",
    "\n",
    "These counts are not used directly as final model inputs. The BiLSTM and TF-IDF pipeline each build their own representation later.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "f85416be",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-18T18:30:23.443068Z",
     "iopub.status.busy": "2026-10-18T18:30:23.442933Z",
     "iopub.status.idle": "2026-10-18T18:30:23.952402Z",
     "shell.execute_reply": "2026-10-18T18:30:23.951774Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Top terms : HAM\n"
     ]
    },
    {
     "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>term</th>\n",
       "      <th>frequency</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>gt</td>\n",
       "      <td>288</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>lt</td>\n",
       "      <td>287</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>just</td>\n",
       "      <td>282</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>ok</td>\n",
       "      <td>256</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>ll</td>\n",
       "      <td>233</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>got</td>\n",
       "      <td>227</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>know</td>\n",
       "      <td>226</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>like</td>\n",
       "      <td>224</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>good</td>\n",
       "      <td>217</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>come</td>\n",
       "      <td>214</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>ur</td>\n",
       "      <td>203</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>11</th>\n",
       "      <td>time</td>\n",
       "      <td>193</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>12</th>\n",
       "      <td>love</td>\n",
       "      <td>186</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>13</th>\n",
       "      <td>day</td>\n",
       "      <td>185</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>14</th>\n",
       "      <td>going</td>\n",
       "      <td>164</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "     term  frequency\n",
       "0      gt        288\n",
       "1      lt        287\n",
       "2    just        282\n",
       "3      ok        256\n",
       "4      ll        233\n",
       "5     got        227\n",
       "6    know        226\n",
       "7    like        224\n",
       "8    good        217\n",
       "9    come        214\n",
       "10     ur        203\n",
       "11   time        193\n",
       "12   love        186\n",
       "13    day        185\n",
       "14  going        164"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAArEAAAHqCAYAAAATexaEAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAASjhJREFUeJzt3XtYVWX+///XBmHLGQ8ooCiKhqKmRknopEyaeMChNNOkFHOsJhs/mDnFZz7loSmcsrLD1DQ1o1aYZaZZUzla4ikzT5nmCU2SScs03RslEeH+/eHX/WuHxzjsveD5uK51Xe57rX2v99qLjS9v77WWzRhjBAAAAFiIj6cLAAAAAC4XIRYAAACWQ4gFAACA5RBiAQAAYDmEWAAAAFgOIRYAAACWQ4gFAACA5RBiAQAAYDmEWAAAAFgOIRYAfqUpU6bIZrN5ugwAqJMIsUAtZrPZLmnJy8ur1joOHDigKVOm6IsvvqjW/VhdQUGBbDabZsyYcc71Z0Pz4cOHz7n+lltukc1m0wMPPHDO9Xl5ea5z/vrrr59zmx49eshms6ljx46/7iAAoIbU83QBAKrPa6+95vb61Vdf1dKlSyu0t2/fvlrrOHDggKZOnarY2Fh16dKlWvdVk/7v//5PDz74oKfLkCQ5nU699957io2N1RtvvKHp06efd5S4fv36mjt3rm677Ta39oKCAn366aeqX79+TZQMAJVCiAVqsV+GlM8++0xLly6t0G5VJ06cUFBQkMf2X69ePdWr5x2/RhcsWKCysjL961//0vXXX6+VK1eqV69e59x2wIABWrx4sQ4fPqzGjRu72ufOnaumTZuqbdu2Onr0aE2VDgC/CtMJgDruxIkTmjhxomJiYmS32xUfH68ZM2bIGOO2nc1m07333qvc3FzFx8erfv36SkxM1MqVKy/Yf15enq655hpJ0ujRo13/nT179mzXNuvWrVO/fv0UFhamwMBA9erVS2vWrHHr5+x/pW/fvl0jRoxQgwYN9Jvf/EaSFBsbq7S0NOXl5enqq69WQECAOnXq5Jom8c4776hTp06umjdv3uzW93fffafRo0erefPmstvtioqKUnp6ugoKCi54bOeaE3v2c1q0aJE6duwou92uDh066KOPPrpgX5WVm5urG264Qb/97W/Vvn175ebmnnfb9PR02e12zZ8/36197ty5uuWWW+Tr63tJ+0xJSVHHjh315ZdfqlevXgoMDFSbNm309ttvS5JWrFihpKQkBQQEKD4+XsuWLavQx7fffqs77rhDTZs2dX1W//rXvyps99xzz6lDhw4KDAxUgwYNdPXVV2vu3Lmu9UVFRcrKylJsbKzsdruaNGmiG264QZs2bXJts2rVKg0dOlQtWrSQ3W5XTEyMJkyYoJ9++qnC/ubPn6+EhATVr19fHTt21MKFC5WZmanY2Fi37crLyzVz5kx16NBB9evXV9OmTXXXXXdV+EfAhg0blJqaqsaNGysgIECtWrXSHXfccUmfM4BzI8QCdZgxRr/73e/09NNPq1+/fnrqqacUHx+vSZMm6b777quw/YoVK5SVlaXbbrtN06ZN05EjR9SvXz9t27btvPto3769pk2bJkm688479dprr+m1115Tz549JUmffPKJevbsKafTqcmTJ+uxxx7TsWPHdP311+vzzz+v0N/QoUNVXFysxx57TGPHjnW179mzRyNGjNCgQYOUk5Ojo0ePatCgQcrNzdWECRN02223aerUqdq7d69uueUWlZeXu947ZMgQLVy4UKNHj9YLL7yg8ePHq6ioSPv37/9Vn+vq1at1zz33aPjw4Xr88cd18uRJDRkyREeOHLmk9xcXF+vw4cMVluLi4nNuf+DAAS1fvly33nqrJOnWW2/V22+/rVOnTp1z+8DAQKWnp+uNN95wtW3ZskVfffWVRowYcVnHevToUaWlpSkpKUmPP/647Ha7hg8frjfffFPDhw/XgAEDNH36dJ04cUI333yzioqKXO/9/vvvde2112rZsmW699579cwzz6hNmzYaM2aMZs6c6dru5Zdf1vjx45WQkKCZM2dq6tSp6tKli9atW+fa5u6779aLL76oIUOG6IUXXtD999+vgIAA7dixw7XN/PnzVVxcrD/84Q967rnnlJqaqueee04jR450O6Z///vfGjZsmPz8/JSTk6PBgwdrzJgx2rhxY4Xjv+uuuzRp0iT16NFDzzzzjEaPHq3c3FylpqaqtLRUknTo0CH17dtXBQUFevDBB/Xcc88pIyNDn3322WV91gB+wQCoM8aNG2d+/rVftGiRkWT+8pe/uG138803G5vNZvbs2eNqk2QkmQ0bNrjavvnmG1O/fn1z0003XXC/69evN5LMrFmz3NrLy8tN27ZtTWpqqikvL3e1FxcXm1atWpkbbrjB1TZ58mQjydx6660V+m/ZsqWRZD799FNX25IlS4wkExAQYL755htX+0svvWQkmeXLlxtjjDl69KiRZJ544okLHsO5nK3p5yQZf39/t89uy5YtRpJ57rnnLtjfvn37XJ/zhZYffvjB7X0zZswwAQEBxul0GmOM2b17t5FkFi5c6Lbd8uXLjSQzf/588/777xubzWb2799vjDFm0qRJpnXr1sYYY3r16mU6dOhw0ePv1auXkWTmzp3ratu5c6eRZHx8fMxnn33maj97Pn7+MzBmzBgTFRVlDh8+7Nbv8OHDTVhYmCkuLjbGGJOenn7ResLCwsy4ceMuuM3Z/n4uJyfH2Gw2t5+RTp06mebNm5uioiJXW15enpFkWrZs6WpbtWqVkWRyc3Pd+vzoo4/c2hcuXGgkmfXr11+wPgCXh5FYoA774IMP5Ovrq/Hjx7u1T5w4UcYYffjhh27tycnJSkxMdL1u0aKF0tPTtWTJEpWVlV32/r/44gvl5+drxIgROnLkiGvE8cSJE+rdu7dWrlzpNmIqnRlxO5eEhAQlJye7XiclJUmSrr/+erVo0aJC+9dffy1JCggIkL+/v/Ly8qpsHmifPn0UFxfnen3llVcqNDTUtc+LufPOO7V06dIKy+23337O7XNzczVw4ECFhIRIktq2bavExMQLTino27evGjZsqHnz5skYo3nz5rlGci9HcHCwhg8f7nodHx+v8PBwtW/f3vVZSxU/d2OMFixYoEGDBskY4zbinJqaKofD4ZoKEB4erv/+979av379eesIDw/XunXrdODAgfNuExAQ4PrziRMndPjwYXXv3l3GGNcUkwMHDmjr1q0aOXKkgoODXdv36tVLnTp1cutv/vz5CgsL0w033OBWf2JiooKDg7V8+XJXbZL0/vvvu0ZnAVSed1yRAMAjvvnmG0VHR7vCz1ln71bwzTffuLW3bdu2Qh9XXHGFiouL9cMPPygyMvKy9p+fny9JGjVq1Hm3cTgcatCgget1q1atzrndz4OqJIWFhUmSYmJiztl+NrDa7Xb99a9/1cSJE9W0aVNde+21SktL08iRIy/7eM5XiyQ1aNDgkkNy27Zt1adPnwrtq1evrtC2Y8cObd68WSNHjtSePXtc7SkpKfrb3/4mp9Op0NDQCu/z8/PT0KFDNXfuXHXr1k2FhYWXPZVAkpo3b15hXnBYWNhFP/cffvhBx44d0z/+8Q/94x//OGffhw4dkiQ98MADWrZsmbp166Y2bdqob9++GjFihHr06OHa9vHHH9eoUaMUExOjxMREDRgwQCNHjlTr1q1d2+zfv18PP/ywFi9eXOFcOBwOSf//z3ybNm0q1NOmTRu3Obb5+flyOBxq0qTJBevv1auXhgwZoqlTp+rpp59WSkqKbrzxRo0YMUJ2u/2c7wVwcYRYAB5zdpT1iSeeOO+tt34+Gia5j6b93PkuRjpfu/nZhWtZWVkaNGiQFi1apCVLluihhx5STk6OPvnkE3Xt2vVih/Gr9llVzt7vdcKECZowYUKF9QsWLNDo0aPP+d4RI0bo73//u6ZMmaLOnTsrISHhsvf/az/3s+f+tttuO+8/Yq688kpJZ/5RtWvXLr3//vv66KOPtGDBAr3wwgt6+OGHNXXqVEln7pF73XXXaeHChfrPf/6jJ554Qn/961/1zjvvqH///iorK9MNN9ygH3/8UQ888IDatWunoKAgffvtt8rMzKww4n8pysvL1aRJk/OOeEdEREg6c7Hf22+/rc8++0zvvfeelixZojvuuENPPvmkPvvsswo/4wAuDSEWqMNatmypZcuWqaioyG00dufOna71P3d25PTndu/ercDAQNdf2OdyvvuVnv0v99DQ0HOOPNakuLg4TZw4URMnTlR+fr66dOmiJ5988rwPBfAGxhjNnTtXv/3tb3XPPfdUWP/II48oNzf3vCH2N7/5jVq0aKG8vDz99a9/re5y3URERCgkJERlZWWXdO6DgoI0bNgwDRs2TKdOndLgwYP16KOPKjs723Vf26ioKN1zzz265557dOjQIV111VV69NFH1b9/f23dulW7d+/WnDlz3C7kWrp0qdt+zv7M/3xU+6xftsXFxWnZsmXq0aPHef9x9XPXXnutrr32Wj366KOaO3euMjIyNG/ePP3+97+/6HsBVMScWKAOGzBggMrKyvT888+7tT/99NOy2Wzq37+/W/vatWvd/ju1sLBQ7777rvr27XvB2zKdvZfrsWPH3NoTExMVFxenGTNm6Pjx4xXe98MPP1zuIV224uJinTx50q0tLi5OISEhKikpqfb9V8aaNWtUUFCg0aNH6+abb66wDBs2TMuXLz/vPFGbzaZnn31WkydPPu982+ri6+urIUOGaMGCBee8u8XPz/0v7+rg7++vhIQEGWNUWlqqsrIy13SAs5o0aaLo6GjXOTz78/nz0XBjjJ555hm390VHR6tjx4569dVX3X4mV6xYoa1bt7pte8stt6isrEyPPPJIhfpPnz7t+nk/evRohVH4s//z4O0/Y4A3YyQWqMMGDRqk3/72t/rzn/+sgoICde7cWf/5z3/07rvvKisry+3iJEnq2LGjUlNTNX78eNntdr3wwguS5Pov3fOJi4tTeHi4/v73vyskJERBQUFKSkpSq1at9Morr6h///7q0KGDRo8erWbNmunbb7/V8uXLFRoaqvfee6/ajl86M5Lcu3dv3XLLLUpISFC9evW0cOFCff/9924XLHmj3Nxc+fr6auDAgedc/7vf/U5//vOfNW/evHPeMk06c8/Y9PT06izzvKZPn67ly5crKSlJY8eOVUJCgn788Udt2rRJy5Yt048//ijpzEVokZGR6tGjh5o2baodO3bo+eefd13MduzYMTVv3lw333yzOnfurODgYC1btkzr16/Xk08+KUlq166d4uLidP/99+vbb79VaGioFixYcM55yo899pjS09PVo0cPjR49WkePHtXzzz+vjh07ugXbXr166a677lJOTo6++OIL9e3bV35+fsrPz9f8+fP1zDPP6Oabb9acOXP0wgsv6KabblJcXJyKior08ssvKzQ0VAMGDKiZDxuojTxyTwQAHvHLW2wZY0xRUZGZMGGCiY6ONn5+fqZt27bmiSeecLvllTFnbh01btw48/rrr5u2bdsau91uunbt6rpV1cW8++67JiEhwdSrV6/CrZY2b95sBg8ebBo1amTsdrtp2bKlueWWW8zHH3/s2ubs7ax+eXspY87cYmvgwIEV2s/W/HNnb2N19pZahw8fNuPGjTPt2rUzQUFBJiwszCQlJZm33nrrosd0vltsnetWTy1btjSjRo26YH+/rO18+/vhhx/MqVOnTKNGjcx11113wT5btWplunbtaoxxv8XWhVzOLbbOtd3lnI/vv//ejBs3zsTExBg/Pz8TGRlpevfubf7xj3+4tnnppZdMz549XT8fcXFxZtKkScbhcBhjjCkpKTGTJk0ynTt3NiEhISYoKMh07tzZvPDCC2772r59u+nTp48JDg42jRs3NmPHjnXd/uyXt3+bN2+eadeunbHb7aZjx45m8eLFZsiQIaZdu3YVjusf//iHSUxMNAEBASYkJMR06tTJ/OlPfzIHDhwwxhizadMmc+utt5oWLVoYu91umjRpYtLS0txuVwfg8tmMqYYrDQDUOjabTePGjasw9QCoK7p06aKIiIgK82gBeAZzYgEA+JnS0lKdPn3arS0vL09btmxRSkqKZ4oCUAFzYgEA+Jlvv/1Wffr00W233abo6Gjt3LlTf//73xUZGXneh20AqHmEWAAAfqZBgwZKTEzUK6+8oh9++EFBQUEaOHCgpk+frkaNGnm6PAD/D3NiAQAAYDnMiQUAAIDlEGIBAABgOXVmTmx5ebkOHDigkJCQ8z4CEwAAANXHGKOioiJFR0fLx6dyY6l1JsQeOHBAMTExni4DAACgzissLFTz5s0r1UedCbEhISGSznxooaGhHq4GAACg7nE6nYqJiXHlssqoMyH27BSC0NBQQiwAAIAHVcXUTi7sAgAAgOUQYgEAAGA5hFgAAABYDiEWAAAAlkOIBQAAgOUQYgEAAGA5hFgAAABYDiEWAAAAlkOIBQAAgOUQYgEAAGA5hFgAAABYDiEWAAAAlkOIBQAAgOUQYgEAAGA5hFgAAABYDiEWAAAAlkOIBQAAgOXU83QBNa3j5CXysQd6ugwAAACPK5g+0NMl/GqMxAIAAMByCLEAAACwHEIsAAAALIcQCwAAAMshxAIAAMByLBdiY2NjNXPmTE+XAQAAAA+yXIgFAAAAvC7EFhUVKSMjQ0FBQYqKitLTTz+tlJQUZWVlKSUlRd98840mTJggm80mm83m6XIBAADgAV4XYu+77z6tWbNGixcv1tKlS7Vq1Spt2rRJkvTOO++oefPmmjZtmg4ePKiDBw+et5+SkhI5nU63BQAAALWDVz2xq6ioSHPmzNHcuXPVu3dvSdKsWbMUHR0tSWrYsKF8fX0VEhKiyMjIC/aVk5OjqVOnVnvNAAAAqHleNRL79ddfq7S0VN26dXO1hYWFKT4+/rL7ys7OlsPhcC2FhYVVWSoAAAA8yKtGYquS3W6X3W73dBkAAACoBl41Etu6dWv5+flp/fr1rjaHw6Hdu3e7Xvv7+6usrMwT5QEAAMBLeFWIDQkJ0ahRozRp0iQtX75cX331lcaMGSMfHx/XnQhiY2O1cuVKffvttzp8+LCHKwYAAIAneFWIlaSnnnpKycnJSktLU58+fdSjRw+1b99e9evXlyRNmzZNBQUFiouLU0REhIerBQAAgCd4XYgNCQlRbm6uTpw4oYMHD+rOO+/Url271KZNG0nStddeqy1btujkyZMyxni4WgAAAHiC113YtXnzZu3cuVPdunWTw+HQtGnTJEnp6ekergwAAADewutCrCTNmDFDu3btkr+/vxITE7Vq1So1btzY02UBAADAS3hdiO3atas2btzo6TIAAADgxbwuxFa3bVNTFRoa6ukyAAAAUAled2EXAAAAcDGEWAAAAFgOIRYAAACWQ4gFAACA5RBiAQAAYDl17u4EHScvkY890NNlAAAAeEzB9IGeLqHSGIkFAACA5RBiAQAAYDmEWAAAAFgOIRYAAACWY4kQm5KSoqysLE+XAQAAAC9hiRD7c7GxsZo5c6anywAAAIAHWS7EAgAAAJYKsSkpKfrmm280YcIE2Ww22Ww2T5cEAAAAD7BUiH3nnXfUvHlzTZs2TQcPHtTBgwfPu21JSYmcTqfbAgAAgNrBUiG2YcOG8vX1VUhIiCIjIxUZGXnebXNychQWFuZaYmJiarBSAAAAVCdLhdjLkZ2dLYfD4VoKCws9XRIAAACqSD1PF1Bd7Ha77Ha7p8sAAABANbDcSKy/v7/Kyso8XQYAAAA8yHIhNjY2VitXrtS3336rw4cPe7ocAAAAeIDlQuy0adNUUFCguLg4RUREeLocAAAAeIAl5sTm5eW5/nzttddqy5YtnisGAAAAHme5kVgAAACAEAsAAADLIcQCAADAciwxJ7YqbZuaqtDQUE+XAQAAgEpgJBYAAACWQ4gFAACA5RBiAQAAYDmEWAAAAFgOIRYAAACWU+fuTtBx8hL52AM9XQYAAECVK5g+0NMl1BhGYgEAAGA5hFgAAABYDiEWAAAAlkOIBQAAgOXUSIjNzMzUjTfeWBO7AgAAQB1QIyH2mWee0ezZs6ukr9jYWM2cObNK+gIAAIA11cgttsLCwmpiNwAAAKgjanw6wblGUrt06aIpU6ZIkowxmjJlilq0aCG73a7o6GiNHz9ekpSSkqJvvvlGEyZMkM1mk81mq4nyAQAA4GW87mEHCxYs0NNPP6158+apQ4cO+u6777RlyxZJ0jvvvKPOnTvrzjvv1NixYy/YT0lJiUpKSlyvnU5ntdYNAACAmuN1IXb//v2KjIxUnz595OfnpxYtWqhbt26SpIYNG8rX11chISGKjIy8YD85OTmaOnVqTZQMAACAGuZ1t9gaOnSofvrpJ7Vu3Vpjx47VwoULdfr06cvuJzs7Ww6Hw7UUFhZWQ7UAAADwhBoPsT4+PjLGuLWVlpa6/hwTE6Ndu3bphRdeUEBAgO655x717NnTbZtLYbfbFRoa6rYAAACgdqjxEBsREaGDBw+6XjudTu3bt89tm4CAAA0aNEjPPvus8vLytHbtWm3dulWS5O/vr7KyshqtGQAAAN6lxufEXn/99Zo9e7YGDRqk8PBwPfzww/L19XWtnz17tsrKypSUlKTAwEC9/vrrCggIUMuWLSWdubvBypUrNXz4cNntdjVu3LimDwEAAAAeVuMjsdnZ2erVq5fS0tI0cOBA3XjjjYqLi3OtDw8P18svv6wePXroyiuv1LJly/Tee++pUaNGkqRp06apoKBAcXFxioiIqOnyAQAA4AVs5pcTVKvBrbfeKl9fX73++uvVvavzcjqdCgsLU0zWW/KxB3qsDgAAgOpSMH2gp0u4oLN5zOFwVPp6pWodiT19+rS2b9+utWvXqkOHDtW5KwAAANQh1Rpit23bpquvvlodOnTQ3XffXZ27AgAAQB1SrRd2denSRcXFxdW5CwAAANRBXvewAwAAAOBivO6xs9Vt29RUHnwAAABgcYzEAgAAwHIIsQAAALAcQiwAAAAshxALAAAAy6lzF3Z1nLyEJ3YBAACvf7oVLoyRWAAAAFgOIRYAAACWQ4gFAACA5RBiAQAAYDmWCLF5eXmy2Ww6duyYp0sBAACAF7BEiAUAAAB+jhALAAAAy/GaEFtSUqLx48erSZMmql+/vn7zm99o/fr159y2uLhY/fv3V48ePZhiAAAAUAd5TYj905/+pAULFmjOnDnatGmT2rRpo9TUVP34449u2x07dkw33HCDysvLtXTpUoWHh5+zv5KSEjmdTrcFAAAAtYNXhNgTJ07oxRdf1BNPPKH+/fsrISFBL7/8sgICAvTPf/7Ttd13332nXr16KSoqSu+9954CA8//5K2cnByFhYW5lpiYmJo4FAAAANQArwixe/fuVWlpqXr06OFq8/PzU7du3bRjxw5X2w033KA2bdrozTfflL+//wX7zM7OlsPhcC2FhYXVVj8AAABqlleE2Es1cOBArVy5Utu3b7/otna7XaGhoW4LAAAAagevCLFxcXHy9/fXmjVrXG2lpaVav369EhISXG3Tp0/XqFGj1Lt370sKsgAAAKid6nm6AEkKCgrSH/7wB02aNEkNGzZUixYt9Pjjj6u4uFhjxozRli1bXNvOmDFDZWVluv7665WXl6d27dp5sHIAAAB4gleEWOnMKGt5ebluv/12FRUV6eqrr9aSJUvUoEGDCts+/fTTbkH2iiuu8EDFAAAA8BSbMcZ4uoia4HQ6z9ylIOst+djPf1cDAABQNxRMH+jpEuqcs3nM4XBU+nolr5gTCwAAAFwOQiwAAAAshxALAAAAyyHEAgAAwHK85u4ENWXb1FQefAAAAGBxjMQCAADAcgixAAAAsBxCLAAAACyHEAsAAADLqXMXdnWcvIQndgEAUIV48hU8gZFYAAAAWA4hFgAAAJZDiAUAAIDlEGIBAABgOZYJsSkpKcrKypIkxcbGaubMmR6tBwAAAJ5jmRALAAAAnEWIBQAAgOUQYgEAAGA5tfZhByUlJSopKXG9djqdHqwGAAAAVanWjsTm5OQoLCzMtcTExHi6JAAAAFSRWhtis7Oz5XA4XEthYaGnSwIAAEAVqbXTCex2u+x2u6fLAAAAQDWotSOxAAAAqL0IsQAAALAcQiwAAAAsxzJzYvPy8lx/Ligo8FgdAAAA8DxGYgEAAGA5hFgAAABYDiEWAAAAlkOIBQAAgOVY5sKuqrJtaqpCQ0M9XQYAAAAqgZFYAAAAWA4hFgAAAJZDiAUAAIDlEGIBAABgOXXuwq6Ok5fIxx7o6TIAAPBKBdMHeroE4JIwEgsAAADLIcQCAADAcgixAAAAsBxCLAAAACyHEAsAAADLsVyInT17tsLDwz1dBgAAADzIciEWAAAAqPEQW1RUpIyMDAUFBSkqKkpPP/20UlJSlJWVJUk6evSoRo4cqQYNGigwMFD9+/dXfn6+JCkvL0+jR4+Ww+GQzWaTzWbTlClTavoQAAAA4GE1HmLvu+8+rVmzRosXL9bSpUu1atUqbdq0ybU+MzNTGzZs0OLFi7V27VoZYzRgwACVlpaqe/fumjlzpkJDQ3Xw4EEdPHhQ999//zn3U1JSIqfT6bYAAACgdqjRJ3YVFRVpzpw5mjt3rnr37i1JmjVrlqKjoyVJ+fn5Wrx4sdasWaPu3btLknJzcxUTE6NFixZp6NChCgsLk81mU2Rk5AX3lZOTo6lTp1bvAQEAAMAjanQk9uuvv1Zpaam6devmagsLC1N8fLwkaceOHapXr56SkpJc6xs1aqT4+Hjt2LHjsvaVnZ0th8PhWgoLC6vmIAAAAOBxNToSW5PsdrvsdrunywAAAEA1qNGR2NatW8vPz0/r1693tTkcDu3evVuS1L59e50+fVrr1q1zrT9y5Ih27dqlhIQESZK/v7/KyspqsmwAAAB4mRoNsSEhIRo1apQmTZqk5cuX66uvvtKYMWPk4+Mjm82mtm3bKj09XWPHjtXq1au1ZcsW3XbbbWrWrJnS09MlSbGxsTp+/Lg+/vhjHT58WMXFxTV5CAAAAPACNX53gqeeekrJyclKS0tTnz591KNHD7Vv317169eXdOZCr8TERKWlpSk5OVnGGH3wwQfy8/OTJHXv3l133323hg0bpoiICD3++OM1fQgAAADwMJsxxniygBMnTqhZs2Z68sknNWbMmGrbj9PpVFhYmGKy3pKPPbDa9gMAgJUVTB/o6RJQi53NYw6HQ6GhoZXqq8Yv7Nq8ebN27typbt26yeFwaNq0aZLkmi4AAAAAXIxH7k4wY8YM7dq1S/7+/kpMTNSqVavUuHFjT5QCAAAAC6rxENu1a1dt3LixpncLAACAWqTGL+wCAAAAKqvWPuzgfLZNTa30RGIAAAB4FiOxAAAAsBxCLAAAACyHEAsAAADLIcQCAADAcurchV0dJy/hiV0AAPwCT+qC1TASCwAAAMshxAIAAMByCLEAAACwHEIsAAAALOdXhdiUlBRlZWVVcSkAAADApWEkFgAAAJZDiAUAAIDlVEmI/fe//62wsDDl5uYqMzNTN954o2bMmKGoqCg1atRI48aNU2lpqWv7o0ePauTIkWrQoIECAwPVv39/5efnS5KMMYqIiNDbb7/t2r5Lly6KiopyvV69erXsdruKi4uronwAAABYTKVD7Ny5c3XrrbcqNzdXGRkZkqTly5dr7969Wr58uebMmaPZs2dr9uzZrvdkZmZqw4YNWrx4sdauXStjjAYMGKDS0lLZbDb17NlTeXl5ks4E3h07duinn37Szp07JUkrVqzQNddco8DA8z+0oKSkRE6n020BAABA7VCpEPu3v/1N99xzj9577z2lpaW52hs0aKDnn39e7dq1U1pamgYOHKiPP/5YkpSfn6/FixfrlVde0XXXXafOnTsrNzdX3377rRYtWiTpzIVjZ0PsypUr1bVrV7e2vLw89erV64K15eTkKCwszLXExMRU5lABAADgRX51iH377bc1YcIELV26tEKg7NChg3x9fV2vo6KidOjQIUnSjh07VK9ePSUlJbnWN2rUSPHx8dqxY4ckqVevXtq+fbt++OEHrVixQikpKa4QW1paqk8//VQpKSkXrC87O1sOh8O1FBYW/tpDBQAAgJf51SG2a9euioiI0L/+9S8ZY9zW+fn5ub222WwqLy+/5L47deqkhg0basWKFW4hdsWKFVq/fr1KS0vVvXv3C/Zht9sVGhrqtgAAAKB2+NUhNi4uTsuXL9e7776rP/7xj5f8vvbt2+v06dNat26dq+3IkSPatWuXEhISJJ0Jvdddd53effddffXVV/rNb36jK6+8UiUlJXrppZd09dVXKygo6NeWDgAAAIur1JzYK664QsuXL9eCBQsu+eEHbdu2VXp6usaOHavVq1dry5Ytuu2229SsWTOlp6e7tktJSdEbb7yhLl26KDg4WD4+PurZs6dyc3MvOh8WAAAAtVul704QHx+vTz75RG+88YYmTpx4Se+ZNWuWEhMTlZaWpuTkZBlj9MEHH7hNQ+jVq5fKysrc5r6mpKRUaAMAAEDdYzO/nNBaSzmdzjN3Kch6Sz7289+aCwCAuqhg+kBPl4A64Gweczgclb5eiSd2AQAAwHIIsQAAALAcQiwAAAAshxALAAAAy6nn6QJq2rapqTz4AAAAwOIYiQUAAIDlEGIBAABgOYRYAAAAWA4hFgAAAJZT5y7s6jh5CU/sAgDUeTyhC1bHSCwAAAAshxALAAAAyyHEAgAAwHIIsQAAALCcGguxKSkpysrKkiTFxsZq5syZrnU2m02LFi2qqVIAAABgcR65O8H69esVFBTkiV0DAACgFvBIiI2IiPDEbgEAAFBLeGRO7C+nE/zS5MmTFRUVpS+//FKStHr1al133XUKCAhQTEyMxo8frxMnTtRQtQAAAPA2XnVhlzFGf/zjH/Xqq69q1apVuvLKK7V3717169dPQ4YM0Zdffqk333xTq1ev1r333nvBvkpKSuR0Ot0WAAAA1A5eE2JPnz6t2267TR9//LFWr16tNm3aSJJycnKUkZGhrKwstW3bVt27d9ezzz6rV199VSdPnjxvfzk5OQoLC3MtMTExNXUoAAAAqGZe89jZCRMmyG6367PPPlPjxo1d7Vu2bNGXX36p3NxcV5sxRuXl5dq3b5/at29/zv6ys7N13333uV47nU6CLAAAQC3hNSH2hhtu0BtvvKElS5YoIyPD1X78+HHdddddGj9+fIX3tGjR4rz92e122e32aqkVAAAAnuU1IfZ3v/udBg0apBEjRsjX11fDhw+XJF111VXavn27a3oBAAAA4DVzYiXppptu0muvvabRo0fr7bffliQ98MAD+vTTT3Xvvffqiy++UH5+vt59992LXtgFAACA2strRmLPuvnmm1VeXq7bb79dPj4+Gjx4sFasWKE///nPuu6662SMUVxcnIYNG+bpUgEAAOAhNmOM8XQRNcHpdJ65S0HWW/KxB3q6HAAAPKpg+kBPl4A66GweczgcCg0NrVRfXjWdAAAAALgUhFgAAABYDiEWAAAAlkOIBQAAgOV43d0Jqtu2qamVnkgMAAAAz2IkFgAAAJZDiAUAAIDlEGIBAABgOYRYAAAAWE6du7Cr4+QlPLELAFBr8OQt1FWMxAIAAMByCLEAAACwHEIsAAAALIcQCwAAAMuxbIiNjY3VzJkzPV0GAAAAPMCyIRYAAAB1FyEWAAAAllPpEFtUVKSMjAwFBQUpKipKTz/9tFJSUpSVlSVJOnr0qEaOHKkGDRooMDBQ/fv3V35+vlsfCxYsUIcOHWS32xUbG6snn3zSbf2hQ4c0aNAgBQQEqFWrVsrNza1s2QAAALCwSofY++67T2vWrNHixYu1dOlSrVq1Sps2bXKtz8zM1IYNG7R48WKtXbtWxhgNGDBApaWlkqSNGzfqlltu0fDhw7V161ZNmTJFDz30kGbPnu3WR2FhoZYvX663335bL7zwgg4dOnTBukpKSuR0Ot0WAAAA1A6VemJXUVGR5syZo7lz56p3796SpFmzZik6OlqSlJ+fr8WLF2vNmjXq3r27JCk3N1cxMTFatGiRhg4dqqeeekq9e/fWQw89JEm64oortH37dj3xxBPKzMzU7t279eGHH+rzzz/XNddcI0n65z//qfbt21+wtpycHE2dOrUyhwcAAAAvVamR2K+//lqlpaXq1q2bqy0sLEzx8fGSpB07dqhevXpKSkpyrW/UqJHi4+O1Y8cO1zY9evRw67dHjx7Kz89XWVmZq4/ExETX+nbt2ik8PPyCtWVnZ8vhcLiWwsLCyhwqAAAAvEilRmK9md1ul91u93QZAAAAqAaVGolt3bq1/Pz8tH79elebw+HQ7t27JUnt27fX6dOntW7dOtf6I0eOaNeuXUpISHBts2bNGrd+16xZoyuuuEK+vr5q166dTp8+rY0bN7rW79q1S8eOHatM6QAAALCwSo3EhoSEaNSoUZo0aZIaNmyoJk2aaPLkyfLx8ZHNZlPbtm2Vnp6usWPH6qWXXlJISIgefPBBNWvWTOnp6ZKkiRMn6pprrtEjjzyiYcOGae3atXr++ef1wgsvSJLi4+PVr18/3XXXXXrxxRdVr149ZWVlKSAgoPJHDwAAAEuq9N0JnnrqKSUnJystLU19+vRRjx491L59e9WvX1/SmQu9EhMTlZaWpuTkZBlj9MEHH8jPz0+SdNVVV+mtt97SvHnz1LFjRz388MOaNm2aMjMzXfs4e7FYr169NHjwYN15551q0qRJZUsHAACARdmMMaYqOzxx4oSaNWumJ598UmPGjKnKrivF6XQqLCxMMVlvycce6OlyAACoEgXTB3q6BOCSnc1jDodDoaGhleqr0hd2bd68WTt37lS3bt3kcDg0bdo0SXJNFwAAAACqWpXcnWDGjBnatWuX/P39lZiYqFWrVqlx48ZV0TUAAABQQaVDbNeuXd3uHAAAAABUt0pf2AUAAADUtFr7sIPz2TY1tdITiQEAAOBZjMQCAADAcgixAAAAsBxCLAAAACyHEAsAAADLqXMXdnWcvIQndgEALIcncwHuGIkFAACA5RBiAQAAYDmEWAAAAFgOIRYAAACWQ4gFAACA5RBiAQAAYDmEWAAAAFjOrwqx5eXlevzxx9WmTRvZ7Xa1aNFCjz76qCRp69atuv766xUQEKBGjRrpzjvv1PHjx13vzczM1I033qjHHntMTZs2VXh4uKZNm6bTp09r0qRJatiwoZo3b65Zs2a57bOwsFC33HKLwsPD1bBhQ6Wnp6ugoODXHzkAAAAs61eF2OzsbE2fPl0PPfSQtm/frrlz56pp06Y6ceKEUlNT1aBBA61fv17z58/XsmXLdO+997q9/5NPPtGBAwe0cuVKPfXUU5o8ebLS0tLUoEEDrVu3Tnfffbfuuusu/fe//5UklZaWKjU1VSEhIVq1apXWrFmj4OBg9evXT6dOnTpnjSUlJXI6nW4LAAAAagebMcZczhuKiooUERGh559/Xr///e/d1r388st64IEHVFhYqKCgIEnSBx98oEGDBunAgQNq2rSpMjMzlZeXp6+//lo+PmcydLt27dSkSROtXLlSklRWVqawsDC98sorGj58uF5//XX95S9/0Y4dO2Sz2SRJp06dUnh4uBYtWqS+fftWqHPKlCmaOnVqhfaYrLd4YhcAwHJ4YhdqA6fTqbCwMDkcDoWGhlaqr8seid2xY4dKSkrUu3fvc67r3LmzK8BKUo8ePVReXq5du3a52jp06OAKsJLUtGlTderUyfXa19dXjRo10qFDhyRJW7Zs0Z49exQSEqLg4GAFBwerYcOGOnnypPbu3XvOOrOzs+VwOFxLYWHh5R4qAAAAvFS9y31DQEBApXfq5+fn9tpms52zrby8XJJ0/PhxJSYmKjc3t0JfERER59yH3W6X3W6vdK0AAADwPpc9Etu2bVsFBATo448/rrCuffv22rJli06cOOFqW7NmjXx8fBQfH/+ri7zqqquUn5+vJk2aqE2bNm5LWFjYr+4XAAAA1nTZIbZ+/fp64IEH9Kc//Umvvvqq9u7dq88++0z//Oc/lZGRofr162vUqFHatm2bli9frj/+8Y+6/fbb1bRp019dZEZGhho3bqz09HStWrVK+/btU15ensaPH++6+AsAAAB1x2VPJ5Ckhx56SPXq1dPDDz+sAwcOKCoqSnfffbcCAwO1ZMkS/c///I+uueYaBQYGasiQIXrqqacqVWRgYKBWrlypBx54QIMHD1ZRUZGaNWum3r17V3pSMAAAAKznsu9OYFVnr4bj7gQAACvi7gSoDTx6dwIAAADA0wixAAAAsBxCLAAAACyHEAsAAADL+VV3J7CybVNTuaMBAACAxTESCwAAAMshxAIAAMByCLEAAACwHEIsAAAALKfOXdjVcfISntgFAKg2PFkLqBmMxAIAAMByCLEAAACwHEIsAAAALIcQCwAAAMshxAIAAMByCLEAAACwHMuH2NLSUk+XAAAAgBrmdSE2NjZWM2fOdGvr0qWLpkyZIkmy2Wx68cUX9bvf/U5BQUF69NFHa75IAAAAeJQlH3YwZcoUTZ8+XTNnzlS9euc+hJKSEpWUlLheO53OmioPAAAA1cySIXbEiBEaPXr0BbfJycnR1KlTa6giAAAA1CSvm05wKa6++uqLbpOdnS2Hw+FaCgsLa6AyAAAA1ASvG4n18fGRMcat7ZcXbwUFBV20H7vdLrvdXqW1AQAAwDt43UhsRESEDh486HrtdDq1b98+D1YEAAAAb+N1Ifb666/Xa6+9plWrVmnr1q0aNWqUfH19PV0WAAAAvIjXTSfIzs7Wvn37lJaWprCwMD3yyCOMxAIAAMCN14XY0NBQzZs3z61t1KhRrj//cr4sAAAA6h6vm04AAAAAXAwhFgAAAJZDiAUAAIDlEGIBAABgOV53YVd12zY1VaGhoZ4uAwAAAJXASCwAAAAshxALAAAAyyHEAgAAwHIIsQAAALCcOndhV8fJS+RjD/R0GQAAL1EwfaCnSwDwKzASCwAAAMshxAIAAMByCLEAAACwHEIsAAAALKdaQ2xeXp5sNpuOHTtWnbsBAABAHVOlITYlJUVZWVmu1927d9fBgwcVFhZWlbsBAABAHVett9jy9/dXZGRkde4CAAAAdVCVjcRmZmZqxYoVeuaZZ2Sz2WSz2TR79my36QSzZ89WeHi43n//fcXHxyswMFA333yziouLNWfOHMXGxqpBgwYaP368ysrKXH2XlJTo/vvvV7NmzRQUFKSkpCTl5eVVVekAAACwmCobiX3mmWe0e/dudezYUdOmTZMkffXVVxW2Ky4u1rPPPqt58+apqKhIgwcP1k033aTw8HB98MEH+vrrrzVkyBD16NFDw4YNkyTde++92r59u+bNm6fo6GgtXLhQ/fr109atW9W2bdtz1lNSUqKSkhLXa6fTWVWHCgAAAA+rshAbFhYmf39/BQYGuqYQ7Ny5s8J2paWlevHFFxUXFydJuvnmm/Xaa6/p+++/V3BwsBISEvTb3/5Wy5cv17Bhw7R//37NmjVL+/fvV3R0tCTp/vvv10cffaRZs2bpscceO2c9OTk5mjp1alUdHgAAALxIjT92NjAw0BVgJalp06aKjY1VcHCwW9uhQ4ckSVu3blVZWZmuuOIKt35KSkrUqFGj8+4nOztb9913n+u10+lUTExMVR0GAAAAPKjGQ6yfn5/ba5vNds628vJySdLx48fl6+urjRs3ytfX1227nwffX7Lb7bLb7VVUNQAAALxJlYZYf39/twuyqkLXrl1VVlamQ4cO6brrrqvSvgEAAGBNVXqf2NjYWK1bt04FBQU6fPiwazS1Mq644gplZGRo5MiReuedd7Rv3z59/vnnysnJ0b///e8qqBoAAABWU6Uh9v7775evr68SEhIUERGh/fv3V0m/s2bN0siRIzVx4kTFx8frxhtv1Pr169WiRYsq6R8AAADWYjPGGE8XUROcTqfCwsIUk/WWfOyBni4HAOAlCqYP9HQJQJ1xNo85HA6FhoZWqq8qHYkFAAAAagIhFgAAAJZDiAUAAIDlEGIBAABgOTX+sANP2zY1tdITiQEAAOBZjMQCAADAcgixAAAAsBxCLAAAACyHEAsAAADLqXMXdnWcvIQndgFALcNTt4C6h5FYAAAAWA4hFgAAAJZDiAUAAIDlEGIBAABgOdUSYlNSUpSVlVUdXQMAAACMxAIAAMB6CLEAAACwnGoPsUePHtXIkSPVoEEDBQYGqn///srPz5ckOZ1OBQQE6MMPP3R7z8KFCxUSEqLi4mJJUmFhoW655RaFh4erYcOGSk9PV0FBQXWXDgAAAC9V7SE2MzNTGzZs0OLFi7V27VoZYzRgwACVlpYqNDRUaWlpmjt3rtt7cnNzdeONNyowMFClpaVKTU1VSEiIVq1apTVr1ig4OFj9+vXTqVOnqrt8AAAAeKFqfWJXfn6+Fi9erDVr1qh79+6SzgTUmJgYLVq0SEOHDlVGRoZuv/12FRcXKzAwUE6nU//+97+1cOFCSdKbb76p8vJyvfLKK7LZbJKkWbNmKTw8XHl5eerbt+85911SUqKSkhLXa6fTWZ2HCgAAgBpUrSOxO3bsUL169ZSUlORqa9SokeLj47Vjxw5J0oABA+Tn56fFixdLkhYsWKDQ0FD16dNHkrRlyxbt2bNHISEhCg4OVnBwsBo2bKiTJ09q79695913Tk6OwsLCXEtMTEw1HikAAABqUrWOxF4Kf39/3XzzzZo7d66GDx+uuXPnatiwYapX70xpx48fV2JionJzcyu8NyIi4rz9Zmdn67777nO9djqdBFkAAIBaolpDbPv27XX69GmtW7fONZ3gyJEj2rVrlxISElzbZWRk6IYbbtBXX32lTz75RH/5y19c66666iq9+eabatKkiUJDQy9533a7XXa7veoOBgAAAF6jWqcTtG3bVunp6Ro7dqxWr16tLVu26LbbblOzZs2Unp7u2q5nz56KjIxURkaGWrVq5Tb9ICMjQ40bN1Z6erpWrVqlffv2KS8vT+PHj9d///vf6iwfAAAAXqra704wa9YsJSYmKi0tTcnJyTLG6IMPPpCfn59rG5vNpltvvVVbtmxRRkaG2/sDAwO1cuVKtWjRQoMHD1b79u01ZswYnTx58rJGZgEAAFB72IwxxtNF1ASn03nmAq+st+RjD/R0OQCAKlQwfaCnSwBwCc7mMYfDUenBSJ7YBQAAAMshxAIAAMByCLEAAACwHEIsAAAALMfjDzuoadumpnJXAwAAAItjJBYAAACWQ4gFAACA5RBiAQAAYDmEWAAAAFhOnbuwq+PkJTyxCwBqCZ7UBdRdjMQCAADAcgixAAAAsBxCLAAAACyHEAsAAADL8ViITUlJUVZWlqd2DwAAAAtjJBYAAACWQ4gFAACA5dRIiD1x4oRGjhyp4OBgRUVF6cknn3Rb/9prr+nqq69WSEiIIiMjNWLECB06dEiSZIxRmzZtNGPGDLf3fPHFF7LZbNqzZ09NHAIAAAC8SI2E2EmTJmnFihV699139Z///Ed5eXnatGmTa31paakeeeQRbdmyRYsWLVJBQYEyMzMlSTabTXfccYdmzZrl1uesWbPUs2dPtWnTpiYOAQAAAF6k2p/Ydfz4cf3zn//U66+/rt69e0uS5syZo+bNm7u2ueOOO1x/bt26tZ599lldc801On78uIKDg5WZmamHH35Yn3/+ubp166bS0lLNnTu3wujsz5WUlKikpMT12ul0VsPRAQAAwBOqfSR27969OnXqlJKSklxtDRs2VHx8vOv1xo0bNWjQILVo0UIhISHq1auXJGn//v2SpOjoaA0cOFD/+te/JEnvvfeeSkpKNHTo0PPuNycnR2FhYa4lJiamOg4PAAAAHuDxC7tOnDih1NRUhYaGKjc3V+vXr9fChQslSadOnXJt9/vf/17z5s3TTz/9pFmzZmnYsGEKDAw8b7/Z2dlyOByupbCwsNqPBQAAADWj2qcTxMXFyc/PT+vWrVOLFi0kSUePHtXu3bvVq1cv7dy5U0eOHNH06dNdo6UbNmyo0M+AAQMUFBSkF198UR999JFWrlx5wf3a7XbZ7faqPyAAAAB4XLWH2ODgYI0ZM0aTJk1So0aN1KRJE/35z3+Wj8+ZQeAWLVrI399fzz33nO6++25t27ZNjzzySIV+fH19lZmZqezsbLVt21bJycnVXToAAAC8VI1MJ3jiiSd03XXXadCgQerTp49+85vfKDExUZIUERGh2bNna/78+UpISND06dPPe8HWmDFjdOrUKY0ePbomygYAAICXshljjKeLuFSrVq1S7969VVhYqKZNm17We51O55kLvLLeko/9/HNpAQDWUTB9oKdLAHAZzuYxh8Oh0NDQSvVV7dMJqkJJSYl++OEHTZkyRUOHDr3sAAsAAIDaxeN3J7gUb7zxhlq2bKljx47p8ccf93Q5AAAA8DBLhNjMzEyVlZVp48aNatasmafLAQAAgIdZIsQCAAAAP2eJObFVadvU1EpPJAYAAIBnMRILAAAAyyHEAgAAwHIIsQAAALAcQiwAAAAsp85d2NVx8hKe2AUAF8GTsAB4O0ZiAQAAYDmEWAAAAFgOIRYAAACWQ4gFAACA5dR4iJ09e7bCw8NrercAAACoRWo8xA4bNky7d++u6d0CAACgFqnxW2wFBAQoICCgpncLAACAWuSyR2KLioqUkZGhoKAgRUVF6emnn1ZKSoqysrIkSUePHtXIkSPVoEEDBQYGqn///srPz3e9/5fTCaZMmaIuXbrotddeU2xsrMLCwjR8+HAVFRVd8j4BAABQt1x2iL3vvvu0Zs0aLV68WEuXLtWqVau0adMm1/rMzExt2LBBixcv1tq1a2WM0YABA1RaWnrePvfu3atFixbp/fff1/vvv68VK1Zo+vTpl7xPAAAA1C2XNZ2gqKhIc+bM0dy5c9W7d29J0qxZsxQdHS1Jys/P1+LFi7VmzRp1795dkpSbm6uYmBgtWrRIQ4cOPWe/5eXlmj17tkJCQiRJt99+uz7++GM9+uijF93n+ZSUlKikpMT12ul0Xs6hAgAAwItd1kjs119/rdLSUnXr1s3VFhYWpvj4eEnSjh07VK9ePSUlJbnWN2rUSPHx8dqxY8d5+42NjXUFWEmKiorSoUOHLmmf55OTk6OwsDDXEhMTczmHCgAAAC/mFfeJ9fPzc3tts9lUXl5eqT6zs7PlcDhcS2FhYaX6AwAAgPe4rBDbunVr+fn5af369a42h8PhumVW+/btdfr0aa1bt861/siRI9q1a5cSEhJ+VYEX2+f52O12hYaGui0AAACoHS5rTmxISIhGjRqlSZMmqWHDhmrSpIkmT54sHx8f2Ww2tW3bVunp6Ro7dqxeeuklhYSE6MEHH1SzZs2Unp7+qwq82D4BAABQ91z2dIKnnnpKycnJSktLU58+fdSjRw+1b99e9evXl3TmoqvExESlpaUpOTlZxhh98MEHFaYMVOU+AQAAULfYjDGmMh2cOHFCzZo105NPPqkxY8ZUVV1Vvk+n03nmAq+st+RjD6zmCgHA2gqmD/R0CQBqobN5zOFwVHqq52U/sWvz5s3auXOnunXrJofDoWnTpknSr54u4K37BAAAgPf6VY+dnTFjhnbt2iV/f38lJiZq1apVaty4cVXX5vF9AgAAwDtddojt2rWrNm7cWB21eNU+AQAA4L284j6xAAAAwOX4VdMJrGzb1FTuGQsAAGBxjMQCAADAcgixAAAAsBxCLAAAACyHEAsAAADLIcQCAADAcgixAAAAsBxCLAAAACyHEAsAAADLIcQCAADAcgixAAAAsBxCLAAAACyHEAsAAADLIcQCAADAcgixAAAAsBxCLAAAACyHEAsAAADLIcQCAADAcup5uoCaYoyRJDmdTg9XAgAAUDedzWFnc1ll1JkQe+TIEUlSTEyMhysBAACo24qKihQWFlapPupMiG3YsKEkaf/+/ZX+0FA1nE6nYmJiVFhYqNDQUE+XA3FOvBHnxDtxXrwP58T7nOucGGNUVFSk6OjoSvdfZ0Ksj8+Z6b9hYWH8cHuZ0NBQzomX4Zx4H86Jd+K8eB/Oiff55TmpqsFELuwCAACA5RBiAQAAYDl1JsTa7XZNnjxZdrvd06Xg/+GceB/OiffhnHgnzov34Zx4n+o+JzZTFfc4AAAAAGpQnRmJBQAAQO1BiAUAAIDlEGIBAABgOYRYAAAAWE6dCLF/+9vfFBsbq/r16yspKUmff/65p0uqM6ZMmSKbzea2tGvXzrX+5MmTGjdunBo1aqTg4GANGTJE33//vQcrrp1WrlypQYMGKTo6WjabTYsWLXJbb4zRww8/rKioKAUEBKhPnz7Kz8932+bHH39URkaGQkNDFR4erjFjxuj48eM1eBS1y8XOSWZmZoXvTr9+/dy24ZxUrZycHF1zzTUKCQlRkyZNdOONN2rXrl1u21zK76z9+/dr4MCBCgwMVJMmTTRp0iSdPn26Jg+l1riUc5KSklLhu3L33Xe7bcM5qTovvviirrzyStcDDJKTk/Xhhx+61tfkd6TWh9g333xT9913nyZPnqxNmzapc+fOSk1N1aFDhzxdWp3RoUMHHTx40LWsXr3atW7ChAl67733NH/+fK1YsUIHDhzQ4MGDPVht7XTixAl17txZf/vb3865/vHHH9ezzz6rv//971q3bp2CgoKUmpqqkydPurbJyMjQV199paVLl+r999/XypUrdeedd9bUIdQ6FzsnktSvXz+3784bb7zhtp5zUrVWrFihcePG6bPPPtPSpUtVWlqqvn376sSJE65tLvY7q6ysTAMHDtSpU6f06aefas6cOZo9e7YefvhhTxyS5V3KOZGksWPHun1XHn/8cdc6zknVat68uaZPn66NGzdqw4YNuv7665Wenq6vvvpKUg1/R0wt161bNzNu3DjX67KyMhMdHW1ycnI8WFXdMXnyZNO5c+dzrjt27Jjx8/Mz8+fPd7Xt2LHDSDJr166toQrrHklm4cKFrtfl5eUmMjLSPPHEE662Y8eOGbvdbt544w1jjDHbt283ksz69etd23z44YfGZrOZb7/9tsZqr61+eU6MMWbUqFEmPT39vO/hnFS/Q4cOGUlmxYoVxphL+531wQcfGB8fH/Pdd9+5tnnxxRdNaGioKSkpqdkDqIV+eU6MMaZXr17mf/7nf877Hs5J9WvQoIF55ZVXavw7UqtHYk+dOqWNGzeqT58+rjYfHx/16dNHa9eu9WBldUt+fr6io6PVunVrZWRkaP/+/ZKkjRs3qrS01O38tGvXTi1atOD81KB9+/bpu+++czsPYWFhSkpKcp2HtWvXKjw8XFdffbVrmz59+sjHx0fr1q2r8Zrriry8PDVp0kTx8fH6wx/+oCNHjrjWcU6qn8PhkCQ1bNhQ0qX9zlq7dq06deqkpk2burZJTU2V0+l0jVTh1/vlOTkrNzdXjRs3VseOHZWdna3i4mLXOs5J9SkrK9O8efN04sQJJScn1/h3pF7VHIZ3Onz4sMrKytw+KElq2rSpdu7c6aGq6pakpCTNnj1b8fHxOnjwoKZOnarrrrtO27Zt03fffSd/f3+Fh4e7vadp06b67rvvPFNwHXT2sz7X9+Tsuu+++05NmjRxW1+vXj01bNiQc1VN+vXrp8GDB6tVq1bau3ev/vd//1f9+/fX2rVr5evryzmpZuXl5crKylKPHj3UsWNHSbqk31nffffdOb9LZ9fh1zvXOZGkESNGqGXLloqOjtaXX36pBx54QLt27dI777wjiXNSHbZu3ark5GSdPHlSwcHBWrhwoRISEvTFF1/U6HekVodYeF7//v1df77yyiuVlJSkli1b6q233lJAQIAHKwO82/Dhw11/7tSpk6688krFxcUpLy9PvXv39mBldcO4ceO0bds2tzn88KzznZOfzwPv1KmToqKi1Lt3b+3du1dxcXE1XWadEB8fry+++EIOh0Nvv/22Ro0apRUrVtR4HbV6OkHjxo3l6+tb4aq477//XpGRkR6qqm4LDw/XFVdcoT179igyMlKnTp3SsWPH3Lbh/NSss5/1hb4nkZGRFS6GPH36tH788UfOVQ1p3bq1GjdurD179kjinFSne++9V++//76WL1+u5s2bu9ov5XdWZGTkOb9LZ9fh1znfOTmXpKQkSXL7rnBOqpa/v7/atGmjxMRE5eTkqHPnznrmmWdq/DtSq0Osv7+/EhMT9fHHH7vaysvL9fHHHys5OdmDldVdx48f1969exUVFaXExET5+fm5nZ9du3Zp//79nJ8a1KpVK0VGRrqdB6fTqXXr1rnOQ3Jyso4dO6aNGze6tvnkk09UXl7u+gsD1eu///2vjhw5oqioKEmck+pgjNG9996rhQsX6pNPPlGrVq3c1l/K76zk5GRt3brV7R8YS5cuVWhoqBISEmrmQGqRi52Tc/niiy8kye27wjmpXuXl5SopKan570hVXJXmzebNm2fsdruZPXu22b59u7nzzjtNeHi421VxqD4TJ040eXl5Zt++fWbNmjWmT58+pnHjxubQoUPGGGPuvvtu06JFC/PJJ5+YDRs2mOTkZJOcnOzhqmufoqIis3nzZrN582YjyTz11FNm8+bN5ptvvjHGGDN9+nQTHh5u3n33XfPll1+a9PR006pVK/PTTz+5+ujXr5/p2rWrWbdunVm9erVp27atufXWWz11SJZ3oXNSVFRk7r//frN27Vqzb98+s2zZMnPVVVeZtm3bmpMnT7r64JxUrT/84Q8mLCzM5OXlmYMHD7qW4uJi1zYX+511+vRp07FjR9O3b1/zxRdfmI8++shERESY7OxsTxyS5V3snOzZs8dMmzbNbNiwwezbt8+8++67pnXr1qZnz56uPjgnVevBBx80K1asMPv27TNffvmlefDBB43NZjP/+c9/jDE1+x2p9SHWGGOee+4506JFC+Pv72+6detmPvvsM0+XVGcMGzbMREVFGX9/f9OsWTMzbNgws2fPHtf6n376ydxzzz2mQYMGJjAw0Nx0003m4MGDHqy4dlq+fLmRVGEZNWqUMebMbbYeeugh07RpU2O3203v3r3Nrl273Po4cuSIufXWW01wcLAJDQ01o0ePNkVFRR44mtrhQuekuLjY9O3b10RERBg/Pz/TsmVLM3bs2Ar/+OacVK1znQ9JZtasWa5tLuV3VkFBgenfv78JCAgwjRs3NhMnTjSlpaU1fDS1w8XOyf79+03Pnj1Nw4YNjd1uN23atDGTJk0yDofDrR/OSdW54447TMuWLY2/v7+JiIgwvXv3dgVYY2r2O2IzxpjLG7sFAAAAPKtWz4kFAABA7USIBQAAgOUQYgEAAGA5hFgAAABYDiEWAAAAlkOIBQAAgOUQYgEAAGA5hFgAAABYDiEWAAAAlkOIBQAAgOUQYgEAAGA5hFgAAABYzv8H8rPo04ipiukAAAAASUVORK5CYII=",
      "text/plain": [
       "<Figure size 700x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Top terms : SPAM\n"
     ]
    },
    {
     "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>term</th>\n",
       "      <th>frequency</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>free</td>\n",
       "      <td>190</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>txt</td>\n",
       "      <td>131</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>ur</td>\n",
       "      <td>119</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>stop</td>\n",
       "      <td>110</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>text</td>\n",
       "      <td>107</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>mobile</td>\n",
       "      <td>105</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>reply</td>\n",
       "      <td>96</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>claim</td>\n",
       "      <td>94</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>urltoken</td>\n",
       "      <td>88</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>prize</td>\n",
       "      <td>78</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>just</td>\n",
       "      <td>65</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>11</th>\n",
       "      <td>new</td>\n",
       "      <td>64</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>12</th>\n",
       "      <td>cash</td>\n",
       "      <td>64</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>13</th>\n",
       "      <td>150p</td>\n",
       "      <td>61</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>14</th>\n",
       "      <td>send</td>\n",
       "      <td>59</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "        term  frequency\n",
       "0       free        190\n",
       "1        txt        131\n",
       "2         ur        119\n",
       "3       stop        110\n",
       "4       text        107\n",
       "5     mobile        105\n",
       "6      reply         96\n",
       "7      claim         94\n",
       "8   urltoken         88\n",
       "9      prize         78\n",
       "10      just         65\n",
       "11       new         64\n",
       "12      cash         64\n",
       "13      150p         61\n",
       "14      send         59"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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8TpC5cqVdccddygrK6tE282dO1d16tTR6NGjC61777339MknnxQbZCtWrKgmTZooNTVVTz/99A19zNi1qFKlinJzc6/pvnB3d1e7du3Url07FRQU6JlnntF7772nkSNH2kZKAwMDlZiYqMTEROXm5qpp06YaM2aM+vTpoxMnTmjZsmVKTk7WqFGjbPv98/1erlw5eXh4aO/evYVq+HNblSpVZBiGIiMjbaH7SqKjoxUdHa2XXnpJa9asUZMmTfTuu+8W+3IK4FbH1AIAV/Xggw8qPz9fb775pl37lClTZLFYCs37W7t2rd03vTMzM/XNN9+oVatWxY6ySbI96/XP38KuX7++qlSpotdee63IB+xfz3SFkjpz5ozOnTtn11alShX5+voW+Yas0rR+/XqdPn26UPuGDRt07NgxVa9e/Zr3lZmZqVWrVqlLly7629/+VmhJTEzU3r17tX79+mL3MW7cOI0ePVoDBw68rvP5K7p06aK1a9dq8eLFhdadPHlSFy9elKRCT4JwcXFR3bp1Jcn23+/PfXx8fFS1alXb+kv37p9HzKdOnWr3+dII+IIFC3TgwAFb+969ewvNJ+/UqZNcXV2VnJxcaL+GYdhqysnJsZ3LJdHR0XJxcbnp9x/gTBiRBXBV7dq10/33368XX3xR6enpiomJ0ffff69vvvlGgwcPtvvCkiTVqVNHrVu31rPPPiur1aq3335bkood1bukSpUqCggI0LvvvitfX195e3urUaNGioyM1IwZM9SmTRvVrl1biYmJuvPOO/Xf//5XK1askJ+fn/7v//6v1M5f+mNEuUWLFurSpYtq1aolNzc3ff311zp06JAee+yxUj32n82ZM0dz585Vx44dVb9+fbm7u2vXrl368MMP5eHhoRdeeOGa9/XJJ5/YHq9WlAcffFBubm6aO3eu7Qtwf9asWTM1a9bsus7lrxo+fLj+9a9/6aGHHlKvXr1Uv359nT59Wjt27NCXX36p9PR0BQUFqU+fPjp+/LiaN2+uChUqaP/+/Zo+fbrq1atnm+tdq1YtxcfHq379+goMDNSmTZv05ZdfasCAAZL++I3ApbnRFy5c0J133qnvv//e7nFgl4wZM0bff/+9mjRpoqefftr2D8E6derYvYK5SpUqGjdunJKSkpSenq4OHTrI19dX+/bt09dff61+/fpp2LBhWr58uQYM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AgICVK1aNe3du1chISE6f/68Tp48adeH+0zav3+/li5dqj59+lyxH/fV/1y6Z67091ZISEihL6xevHhRx48fvy3vuUshdv/+/VqyZIndaGxRGjVqpIsXLyo9Pf3mFOjEKleurKCgINufPe6twn744Qft3r37qn+PSdxbJUGQvQbu7u6qX7++li1bZmsrKCjQsmXLFBcX58DKnINhGBowYIC+/vprLV++XJGRkVfdZuvWrZKk0NDQUq7OueXm5iotLU2hoaGqX7++ypQpY3ef7d69WxkZGbf9fTZz5kyVK1dObdu2vWI/7qv/iYyMVEhIiN39lJOTo/Xr19vup7i4OJ08eVI//fSTrc/y5ctVUFBg+0fB7eJSiN2zZ4+WLl2qsmXLXnWbrVu3ysXFpdCv0G9Hv//+u44dO2b7s8e9VdgHH3yg+vXrKyYm5qp9ubdKwNHfNjOLefPmGVar1Zg1a5bxyy+/GP369TMCAgKMgwcPOro0h3v66acNf39/IzU11cjKyrItZ86cMQzDMPbu3WuMHTvW2LRpk7Fv3z7jm2++MSpXrmw0bdrUwZXffM8995yRmppq7Nu3z1i9erXRsmVLIygoyDh8+LBhGIbx1FNPGRUrVjSWL19ubNq0yYiLizPi4uIcXLVj5efnGxUrVjRGjBhh1859ZRinTp0ytmzZYmzZssWQZLz++uvGli1bbN+0nzhxohEQEGB88803xvbt24327dsbkZGRxtmzZ237SEhIMGJjY43169cbP/74oxEVFWV07drVUadUaq50rc6fP288/PDDRoUKFYytW7fa/T2Wl5dnGIZhrFmzxpgyZYqxdetWIy0tzfj444+N4OBgo0ePHg4+s9Jxpet16tQpY9iwYcbatWuNffv2GUuXLjXuuusuIyoqyjh37pxtH9xb/3viRXZ2tuHl5WW88847hba/3e6tG40gWwLTp083KlasaLi7uxsNGzY01q1b5+iSnIKkIpeZM2cahmEYGRkZRtOmTY3AwEDDarUaVatWNYYPH25kZ2c7tnAHePTRR43Q0FDD3d3duPPOO41HH33U2Lt3r2392bNnjWeeeca44447DC8vL6Njx45GVlaWAyt2vMWLFxuSjN27d9u1c18ZxooVK4r8s9ezZ0/DMP54BNfIkSON8uXLG1ar1WjRokWh63js2DGja9euho+Pj+Hn52ckJiYap06dcsDZlK4rXat9+/YV+/fYihUrDMMwjJ9++slo1KiR4e/vb3h4eBg1a9Y0JkyYYBfcbiVXul5nzpwxWrVqZQQHBxtlypQxKlWqZPTt27fQwA73Vk9bn/fee8/w9PQ0Tp48WWj72+3eutEshmEYpTrkCwAAAJQC5sgCAADAlAiyAAAAMCWCLAAAAEyJIAsAAABTIsgCAADAlAiyAAAAMCWCLAAAAEyJIAsAAABTIsgCAADAlAiyAAAAMCWCLAAAAEyJIAsAAABT+n97edwhb7svXwAAAABJRU5ErkJggg==",
      "text/plain": [
       "<Figure size 700x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Count words on the full de-duplicated corpus for descriptive analysis only.\n",
    "eda_vectorizer = CountVectorizer(stop_words=\"english\", max_features=5000)\n",
    "word_counts = eda_vectorizer.fit_transform(df[\"cleaned_message\"])\n",
    "terms = np.array(eda_vectorizer.get_feature_names_out())\n",
    "\n",
    "for class_name, class_value in [(\"ham\", 0), (\"spam\", 1)]:\n",
    "    class_mask = df[\"label\"].to_numpy() == class_value\n",
    "    frequencies = np.asarray(word_counts[class_mask].sum(axis=0)).ravel()\n",
    "\n",
    "    # Select the 15 most frequent terms for this class.\n",
    "    top_indices = np.argsort(frequencies)[-15:][::-1]\n",
    "    top_terms = pd.DataFrame({\n",
    "        \"term\": terms[top_indices],\n",
    "        \"frequency\": frequencies[top_indices],\n",
    "    })\n",
    "\n",
    "    print(f\"Top terms : {class_name.upper()}\")\n",
    "    display(top_terms)\n",
    "\n",
    "    fig, ax = plt.subplots(figsize=(7, 5))\n",
    "    ax.barh(top_terms[\"term\"][::-1], top_terms[\"frequency\"][::-1])\n",
    "    ax.set_title(f\"Top terms in {class_name.upper()} messages\")\n",
    "    fig.tight_layout()\n",
    "    fig.savefig(ASSET_DIR / f\"03_top_terms_{class_name}.png\", dpi=160, bbox_inches=\"tight\")\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2e153c33",
   "metadata": {},
   "source": [
    "## 7. Split the data into train, validation and test sets\n",
    "\n",
    "I use three separate subsets because they have different roles:\n",
    "\n",
    "- **training set**: learn model parameters;\n",
    "- **validation set**: make development choices, such as early stopping and the decision threshold;\n",
    "- **test set**: measure final performance after those choices are fixed.\n",
    "\n",
    "The split is stratified so that the proportion of spam remains similar in all three subsets.\n",
    "\n",
    "This separation is important because the test set should represent unseen data, not data used to tune the model.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "15228c26",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-18T18:30:23.954001Z",
     "iopub.status.busy": "2026-10-18T18:30:23.953889Z",
     "iopub.status.idle": "2026-10-18T18:30:23.982113Z",
     "shell.execute_reply": "2026-10-18T18:30:23.981556Z"
    }
   },
   "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>rows</th>\n",
       "      <th>ham</th>\n",
       "      <th>spam</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>train</th>\n",
       "      <td>3609</td>\n",
       "      <td>3160</td>\n",
       "      <td>449</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>validation</th>\n",
       "      <td>774</td>\n",
       "      <td>678</td>\n",
       "      <td>96</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>test</th>\n",
       "      <td>774</td>\n",
       "      <td>678</td>\n",
       "      <td>96</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "            rows   ham  spam\n",
       "train       3609  3160   449\n",
       "validation   774   678    96\n",
       "test         774   678    96"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# First reserve 30% of the data for validation + test.\n",
    "train_df, temporary_df = train_test_split(\n",
    "    df[[\"cleaned_message\", \"label\", \"Message\"]],\n",
    "    test_size=0.30,\n",
    "    stratify=df[\"label\"],\n",
    "    random_state=SEED,\n",
    ")\n",
    "\n",
    "# Split the reserved 30% equally: 15% validation, 15% test.\n",
    "validation_df, test_df = train_test_split(\n",
    "    temporary_df,\n",
    "    test_size=0.50,\n",
    "    stratify=temporary_df[\"label\"],\n",
    "    random_state=SEED,\n",
    ")\n",
    "\n",
    "split_summary = pd.DataFrame(\n",
    "    {\n",
    "        \"rows\": [len(train_df), len(validation_df), len(test_df)],\n",
    "        \"ham\": [\n",
    "            int((train_df.label == 0).sum()),\n",
    "            int((validation_df.label == 0).sum()),\n",
    "            int((test_df.label == 0).sum()),\n",
    "        ],\n",
    "        \"spam\": [\n",
    "            int((train_df.label == 1).sum()),\n",
    "            int((validation_df.label == 1).sum()),\n",
    "            int((test_df.label == 1).sum()),\n",
    "        ],\n",
    "    },\n",
    "    index=[\"train\", \"validation\", \"test\"],\n",
    ")\n",
    "\n",
    "display(split_summary)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dc66b901",
   "metadata": {},
   "source": [
    "## 8. Convert training text into sequences for the BiLSTM\n",
    "\n",
    "The BiLSTM cannot read raw text directly.\n",
    "\n",
    "A tokenizer learns a vocabulary from the **training messages only** and converts words into integer IDs. Words that were not seen during training are mapped to an out-of-vocabulary token.\n",
    "\n",
    "Messages are then padded to a common length. Instead of using the longest message in the corpus, I use the **95th percentile of training sequence lengths**. This keeps most messages intact without making every sequence unnecessarily long because of a few extreme cases.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "8bfaeacd",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-18T18:30:23.983333Z",
     "iopub.status.busy": "2026-10-18T18:30:23.983221Z",
     "iopub.status.idle": "2026-10-18T18:30:24.040446Z",
     "shell.execute_reply": "2026-10-18T18:30:24.039752Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Vocabulary size used: 5000\n",
      "95th-percentile training sequence length: 33\n",
      "Maximum training sequence length: 190\n"
     ]
    }
   ],
   "source": [
    "MAX_VOCAB_SIZE = 5000\n",
    "PAD_ID = 0\n",
    "OOV_ID = 1\n",
    "\n",
    "# Count words only in training messages.\n",
    "word_counter = Counter()\n",
    "for text in train_df[\"cleaned_message\"]:\n",
    "    word_counter.update(text.split())\n",
    "\n",
    "# Reserve 0 for padding and 1 for unknown words.\n",
    "word_index = {\"<PAD>\": PAD_ID, \"<OOV>\": OOV_ID}\n",
    "for word, _ in word_counter.most_common(MAX_VOCAB_SIZE - 2):\n",
    "    word_index[word] = len(word_index)\n",
    "\n",
    "\n",
    "def texts_to_sequences(texts):\n",
    "    \"\"\"Convert cleaned messages into lists of integer word IDs.\"\"\"\n",
    "    return [\n",
    "        [word_index.get(token, OOV_ID) for token in text.split()]\n",
    "        for text in texts\n",
    "    ]\n",
    "\n",
    "\n",
    "# Convert each data split with the same training vocabulary.\n",
    "train_sequences = texts_to_sequences(train_df[\"cleaned_message\"])\n",
    "validation_sequences = texts_to_sequences(validation_df[\"cleaned_message\"])\n",
    "test_sequences = texts_to_sequences(test_df[\"cleaned_message\"])\n",
    "\n",
    "# Choose sequence length from training data only.\n",
    "train_lengths = np.array([len(sequence) for sequence in train_sequences])\n",
    "MAX_SEQUENCE_LENGTH = max(10, int(np.percentile(train_lengths, 95)))\n",
    "\n",
    "# Pad shorter messages and truncate longer messages.\n",
    "X_train = keras.utils.pad_sequences(\n",
    "    train_sequences,\n",
    "    maxlen=MAX_SEQUENCE_LENGTH,\n",
    "    padding=\"post\",\n",
    "    truncating=\"post\",\n",
    ")\n",
    "X_validation = keras.utils.pad_sequences(\n",
    "    validation_sequences,\n",
    "    maxlen=MAX_SEQUENCE_LENGTH,\n",
    "    padding=\"post\",\n",
    "    truncating=\"post\",\n",
    ")\n",
    "X_test = keras.utils.pad_sequences(\n",
    "    test_sequences,\n",
    "    maxlen=MAX_SEQUENCE_LENGTH,\n",
    "    padding=\"post\",\n",
    "    truncating=\"post\",\n",
    ")\n",
    "\n",
    "y_train = train_df[\"label\"].to_numpy()\n",
    "y_validation = validation_df[\"label\"].to_numpy()\n",
    "y_test = test_df[\"label\"].to_numpy()\n",
    "\n",
    "print(\"Vocabulary size used:\", len(word_index))\n",
    "print(\"95th-percentile training sequence length:\", MAX_SEQUENCE_LENGTH)\n",
    "print(\"Maximum training sequence length:\", int(train_lengths.max()))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d01ad020",
   "metadata": {},
   "source": [
    "## 9. Account for class imbalance\n",
    "\n",
    "Spam is much less frequent than ham.\n",
    "\n",
    "During BiLSTM training, I use balanced class weights so that mistakes on spam messages carry more weight than they would in a purely frequency-based loss.\n",
    "\n",
    "The weights are calculated from the training labels only.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "ba2f3b51",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-18T18:30:24.042124Z",
     "iopub.status.busy": "2026-10-18T18:30:24.042000Z",
     "iopub.status.idle": "2026-10-18T18:30:24.049339Z",
     "shell.execute_reply": "2026-10-18T18:30:24.046435Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{0: 0.5710443037974684, 1: 4.018930957683741}"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "classes = np.array([0, 1])\n",
    "class_weights = compute_class_weight(\n",
    "    class_weight=\"balanced\",\n",
    "    classes=classes,\n",
    "    y=y_train,\n",
    ")\n",
    "\n",
    "class_weight_dict = {\n",
    "    int(class_id): float(weight)\n",
    "    for class_id, weight in zip(classes, class_weights)\n",
    "}\n",
    "\n",
    "class_weight_dict"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3bbaa9c9",
   "metadata": {},
   "source": [
    "## 10. Build the BiLSTM\n",
    "\n",
    "The neural network follows this structure:\n",
    "\n",
    "`Embedding → Bidirectional LSTM → Dropout → Dense → Dropout → Sigmoid`\n",
    "\n",
    "### Why this architecture?\n",
    "\n",
    "- **Embedding** learns a numeric representation of words.\n",
    "- **Bidirectional LSTM** reads the sequence in both directions and can use surrounding context.\n",
    "- **Dropout** reduces overfitting.\n",
    "- **Dense layers** combine the learned sequence representation.\n",
    "- **Sigmoid output** returns a probability that the SMS is spam.\n",
    "\n",
    "The model keeps the core idea of the original academic project while making the full experiment easier to compare with a simpler baseline.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "944a3d4c",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-18T18:30:24.051078Z",
     "iopub.status.busy": "2026-10-18T18:30:24.050963Z",
     "iopub.status.idle": "2026-10-18T18:30:24.193704Z",
     "shell.execute_reply": "2026-10-18T18:30:24.193118Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\">Model: \"sms_spam_bilstm\"</span>\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[1mModel: \"sms_spam_bilstm\"\u001b[0m\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n",
       "┃<span style=\"font-weight: bold\"> Layer (type)                    </span>┃<span style=\"font-weight: bold\"> Output Shape           </span>┃<span style=\"font-weight: bold\">       Param # </span>┃\n",
       "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n",
       "│ embedding (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Embedding</span>)           │ ?                      │   <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> (unbuilt) │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ bidirectional (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Bidirectional</span>)   │ ?                      │   <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> (unbuilt) │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ dropout (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Dropout</span>)               │ ?                      │             <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ dense (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Dense</span>)                   │ ?                      │   <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> (unbuilt) │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ dropout_1 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Dropout</span>)             │ ?                      │             <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ dense_1 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Dense</span>)                 │ ?                      │   <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> (unbuilt) │\n",
       "└─────────────────────────────────┴────────────────────────┴───────────────┘\n",
       "</pre>\n"
      ],
      "text/plain": [
       "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n",
       "┃\u001b[1m \u001b[0m\u001b[1mLayer (type)                   \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mOutput Shape          \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1m      Param #\u001b[0m\u001b[1m \u001b[0m┃\n",
       "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n",
       "│ embedding (\u001b[38;5;33mEmbedding\u001b[0m)           │ ?                      │   \u001b[38;5;34m0\u001b[0m (unbuilt) │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ bidirectional (\u001b[38;5;33mBidirectional\u001b[0m)   │ ?                      │   \u001b[38;5;34m0\u001b[0m (unbuilt) │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ dropout (\u001b[38;5;33mDropout\u001b[0m)               │ ?                      │             \u001b[38;5;34m0\u001b[0m │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ dense (\u001b[38;5;33mDense\u001b[0m)                   │ ?                      │   \u001b[38;5;34m0\u001b[0m (unbuilt) │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ dropout_1 (\u001b[38;5;33mDropout\u001b[0m)             │ ?                      │             \u001b[38;5;34m0\u001b[0m │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ dense_1 (\u001b[38;5;33mDense\u001b[0m)                 │ ?                      │   \u001b[38;5;34m0\u001b[0m (unbuilt) │\n",
       "└─────────────────────────────────┴────────────────────────┴───────────────┘\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\"> Total params: </span><span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> (0.00 B)\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[1m Total params: \u001b[0m\u001b[38;5;34m0\u001b[0m (0.00 B)\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\"> Trainable params: </span><span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> (0.00 B)\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m0\u001b[0m (0.00 B)\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\"> Non-trainable params: </span><span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> (0.00 B)\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m0\u001b[0m (0.00 B)\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "EMBEDDING_DIM = 100\n",
    "\n",
    "bilstm = keras.Sequential(\n",
    "    [\n",
    "        # Turn each word ID into a learned dense vector.\n",
    "        layers.Embedding(\n",
    "            input_dim=MAX_VOCAB_SIZE,\n",
    "            output_dim=EMBEDDING_DIM,\n",
    "            mask_zero=True,\n",
    "        ),\n",
    "\n",
    "        # Read the sequence in both directions.\n",
    "        layers.Bidirectional(layers.LSTM(128, return_sequences=False)),\n",
    "\n",
    "        # Dropout reduces overfitting by randomly disabling units during training.\n",
    "        layers.Dropout(0.5),\n",
    "        layers.Dense(64, activation=\"relu\"),\n",
    "        layers.Dropout(0.3),\n",
    "\n",
    "        # One sigmoid output = estimated probability of spam.\n",
    "        layers.Dense(1, activation=\"sigmoid\"),\n",
    "    ],\n",
    "    name=\"sms_spam_bilstm\",\n",
    ")\n",
    "\n",
    "bilstm.compile(\n",
    "    loss=\"binary_crossentropy\",\n",
    "    optimizer=keras.optimizers.Adam(learning_rate=0.001),\n",
    "    metrics=[\"accuracy\"],\n",
    ")\n",
    "\n",
    "bilstm.summary()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9e7298d7",
   "metadata": {},
   "source": [
    "## 11. Train the BiLSTM\n",
    "\n",
    "The model is trained on the training set and monitored on the validation set.\n",
    "\n",
    "I use **early stopping** on validation loss. Training stops when the model is no longer improving, and the best weights are restored.\n",
    "\n",
    "This avoids choosing the number of epochs by looking at test performance.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "44e8211a",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-18T18:30:24.195504Z",
     "iopub.status.busy": "2026-10-18T18:30:24.195138Z",
     "iopub.status.idle": "2026-10-18T18:30:44.596137Z",
     "shell.execute_reply": "2026-10-18T18:30:44.595192Z"
    }
   },
   "outputs": [],
   "source": [
    "early_stopping = keras.callbacks.EarlyStopping(\n",
    "    monitor=\"val_loss\",\n",
    "    patience=3,\n",
    "    restore_best_weights=True,\n",
    "    min_delta=1e-4,\n",
    ")\n",
    "\n",
    "history = bilstm.fit(\n",
    "    X_train,\n",
    "    y_train,\n",
    "    validation_data=(X_validation, y_validation),\n",
    "    epochs=20,\n",
    "    batch_size=32,\n",
    "    class_weight=class_weight_dict,\n",
    "    callbacks=[early_stopping],\n",
    "    verbose=2,\n",
    ")\n",
    "\n",
    "print(\"Epochs run:\", len(history.history[\"loss\"]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "0c51df80",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-18T18:30:44.597336Z",
     "iopub.status.busy": "2026-10-18T18:30:44.597190Z",
     "iopub.status.idle": "2026-10-18T18:30:44.942810Z",
     "shell.execute_reply": "2026-10-18T18:30:44.942261Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 700x400 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 700x400 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Plot training and validation accuracy.\n",
    "fig, ax = plt.subplots(figsize=(7, 4))\n",
    "ax.plot(history.history[\"accuracy\"], label=\"train\")\n",
    "ax.plot(history.history[\"val_accuracy\"], label=\"validation\")\n",
    "ax.set_title(\"BiLSTM accuracy during training\")\n",
    "ax.set_xlabel(\"Epoch\")\n",
    "ax.set_ylabel(\"Accuracy\")\n",
    "ax.legend()\n",
    "fig.tight_layout()\n",
    "fig.savefig(ASSET_DIR / \"04_bilstm_training_accuracy.png\", dpi=160, bbox_inches=\"tight\")\n",
    "plt.show()\n",
    "\n",
    "# Plot training and validation loss.\n",
    "fig, ax = plt.subplots(figsize=(7, 4))\n",
    "ax.plot(history.history[\"loss\"], label=\"train\")\n",
    "ax.plot(history.history[\"val_loss\"], label=\"validation\")\n",
    "ax.set_title(\"BiLSTM loss during training\")\n",
    "ax.set_xlabel(\"Epoch\")\n",
    "ax.set_ylabel(\"Binary cross-entropy\")\n",
    "ax.legend()\n",
    "fig.tight_layout()\n",
    "fig.savefig(ASSET_DIR / \"05_bilstm_training_loss.png\", dpi=160, bbox_inches=\"tight\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fcec1ff7",
   "metadata": {},
   "source": [
    "## 12. Choose the decision threshold\n",
    "\n",
    "The BiLSTM returns a spam probability, not a final label.\n",
    "\n",
    "A threshold is therefore needed:\n",
    "\n",
    "- probability above the threshold → spam;\n",
    "- probability below the threshold → ham.\n",
    "\n",
    "Rather than fixing `0.50` automatically, I choose the threshold that gives the best **spam F1-score on the validation set**. The test set is not used for this decision.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "1c882d46",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-18T18:30:44.944272Z",
     "iopub.status.busy": "2026-10-18T18:30:44.944145Z",
     "iopub.status.idle": "2026-10-18T18:30:45.452573Z",
     "shell.execute_reply": "2026-10-18T18:30:45.451779Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "threshold         0.8300\n",
      "spam_precision    0.9775\n",
      "spam_recall       0.9062\n",
      "spam_f1           0.9405\n",
      "Frozen BiLSTM threshold: 0.83\n"
     ]
    }
   ],
   "source": [
    "def spam_metrics_at_threshold(y_true, probabilities, threshold):\n",
    "    \"\"\"Return precision, recall and F1 for the spam class at one threshold.\"\"\"\n",
    "    predictions = (probabilities >= threshold).astype(int)\n",
    "\n",
    "    precision, recall, f1, _ = precision_recall_fscore_support(\n",
    "        y_true,\n",
    "        predictions,\n",
    "        labels=[1],\n",
    "        average=None,\n",
    "        zero_division=0,\n",
    "    )\n",
    "\n",
    "    return float(precision[0]), float(recall[0]), float(f1[0])\n",
    "\n",
    "\n",
    "validation_prob_bilstm = np.asarray(\n",
    "    bilstm.predict(X_validation, verbose=0)\n",
    ").ravel()\n",
    "\n",
    "threshold_grid = np.arange(0.10, 0.91, 0.01)\n",
    "threshold_results = []\n",
    "\n",
    "for threshold in threshold_grid:\n",
    "    precision, recall, f1 = spam_metrics_at_threshold(\n",
    "        y_validation,\n",
    "        validation_prob_bilstm,\n",
    "        threshold,\n",
    "    )\n",
    "    threshold_results.append((threshold, precision, recall, f1))\n",
    "\n",
    "bilstm_thresholds = pd.DataFrame(\n",
    "    threshold_results,\n",
    "    columns=[\"threshold\", \"spam_precision\", \"spam_recall\", \"spam_f1\"],\n",
    ")\n",
    "\n",
    "# First maximize F1. Recall and precision are used only as tie-breakers.\n",
    "best_bilstm_row = bilstm_thresholds.sort_values(\n",
    "    [\"spam_f1\", \"spam_recall\", \"spam_precision\"],\n",
    "    ascending=False,\n",
    ").iloc[0]\n",
    "\n",
    "BILSTM_THRESHOLD = float(best_bilstm_row[\"threshold\"])\n",
    "\n",
    "print(best_bilstm_row.round(4).to_string())\n",
    "print(\"Frozen BiLSTM threshold:\", round(BILSTM_THRESHOLD, 2))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "43cfd0ba",
   "metadata": {},
   "source": [
    "## 13. Evaluate the BiLSTM on unseen test messages\n",
    "\n",
    "The final BiLSTM is evaluated on **774 test messages** that were not used to train the model or choose the threshold.\n",
    "\n",
    "I report several metrics because accuracy alone can hide poor performance on the minority class:\n",
    "\n",
    "- **accuracy**: overall proportion of correct predictions;\n",
    "- **spam precision**: how often a message predicted as spam is actually spam;\n",
    "- **spam recall**: how much of the real spam is detected;\n",
    "- **spam F1-score**: balance between spam precision and recall;\n",
    "- **ROC-AUC / PR-AUC**: ranking quality across possible thresholds.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "0422abfa",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-18T18:30:45.454071Z",
     "iopub.status.busy": "2026-10-18T18:30:45.453959Z",
     "iopub.status.idle": "2026-10-18T18:30:45.712077Z",
     "shell.execute_reply": "2026-10-18T18:30:45.709477Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "accuracy          0.9832\n",
      "spam_precision    0.9560\n",
      "spam_recall       0.9062\n",
      "spam_f1           0.9305\n",
      "roc_auc           0.9937\n",
      "pr_auc            0.9733\n",
      "threshold         0.8300\n",
      "\n",
      "Classification report:\n",
      "\n",
      "              precision    recall  f1-score   support\n",
      "\n",
      "         ham     0.9868    0.9941    0.9904       678\n",
      "        spam     0.9560    0.9062    0.9305        96\n",
      "\n",
      "    accuracy                         0.9832       774\n",
      "   macro avg     0.9714    0.9502    0.9605       774\n",
      "weighted avg     0.9830    0.9832    0.9830       774\n",
      "\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAawAAAGGCAYAAAAn/7X8AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAOcRJREFUeJzt3Xl8TFf/B/DPJJLJNokgK5GILISgolV7ooitlloee0JRUmvt1ViKqqW1lVQVwWMpWmot2qJ29VhKG1ssscTSkEWQZeb8/vDL1DUJM5GYHP28X6951Zw599zvndzOZ+69Z2ZUQggBIiKiIs7C3AUQEREZg4FFRERSYGAREZEUGFhERCQFBhYREUmBgUVERFJgYBERkRQYWEREJAUGFhERSeFfEVgqlQoTJkwwdxnS8PHxQWRkZJEf05xet+15Hc2YMQO+vr6wtLREtWrVCnz8yMhI+Pj4FPi4souNjYVKpcKVK1cKfGwpAyvnCXn65urqirCwMGzfvt3o5Y8dO/bcfnfv3sXgwYNRoUIF2NrawtXVFW+99RZGjRqFBw8eYM+ePQZ15HV7tu79+/cbrE8IAS8vL6hUKrRs2TJ/Tw69NrZt22bSG60FCxYgNja20OoBgL/++gsTJkwolBejgrRz506MHDkSderUwdKlS/HZZ5+ZuyQpvYp9yhTFzF3Ay/j0009Rrlw5CCFw+/ZtxMbGonnz5ti8ebPiBf/Ro0coVsy0Tb137x5q1KiB1NRU9OrVCxUqVEBSUhL++OMPxMTEoH///qhYsSJWrFihWG7MmDFwcHDA2LFj8xzbxsYGq1atQt26dRXte/fuxfXr16FWq02qtaCdO3cOFhZSvpd5rWzbtg3z5883OrQWLFiAUqVKFeqR319//YWJEyciNDS0SB9d/Prrr7CwsMDixYthbW1dKOtYtGgRdDpdoYxdVORnn+revTs6depUKK9jUgdWs2bNUKNGDf39999/H25ubli9erUisGxsbEwee/HixUhISMCBAwdQu3ZtxWOpqamwtraGjY0NunXrpnjs888/R6lSpQzan9a8eXOsW7cOc+fOVQTpqlWrEBISgr///tvkeguSuQOT6GXduXMHtra2hRZWAGBlZVVoY8soPT0d9vb2sLS0hKWlZaGs47V6G128eHHY2toaHE3l5xpWfHw8LC0t8fbbbxs85ujomK8QzNG5c2ckJSVh165d+rbMzEysX78eXbp0yfe4BeXZ6zM5pzIPHDiAjz76CC4uLrC3t0fbtm1x9+5dxbJCCEyePBllypSBnZ0dwsLC8Oeff+a6nuTkZAwZMgReXl5Qq9Xw8/PDtGnTFO9ar1y5ApVKhZkzZ2LWrFnw9vaGra0tGjRogDNnzhiMefbsWbRv3x4lSpSAjY0NatSogU2bNin6FJXt+eabb1C+fHmo1Wq8+eab+P333/X9IiMjMX/+fAAwOLWcGx8fH/z555/Yu3evvm9oaKhJtQHAmjVrEBISAo1GA0dHRwQHB2POnDn6561Dhw4AgLCwMP169uzZk2ddwJO/SceOHeHi4gJbW1sEBgYanIE4ceIEmjVrBkdHRzg4OOCdd97B4cOHFX2M/bupVCosXboU6enp+hpjY2P1z31up7iefY1IS0vDkCFD4OPjA7VaDVdXVzRu3BjHjx/X98ntGlZ6ejqGDRumf54DAwMxc+ZMPPujGCqVCgMGDMDGjRtRuXJlqNVqVKpUCT/99NNzn0sA+ksRa9euxcSJE1G6dGloNBq0b98eKSkpyMjIwJAhQ+Dq6goHBwf07NkTGRkZijGWLl2Khg0bwtXVFWq1GkFBQYiJiVH0ed4+lfO32Lt3L6KiouDq6ooyZcooHss5bZxztDtu3DjF+KtWrYJKpTJY7/NIfYSVkpKCv//+G0II3LlzB/PmzcODBw+ee3RjLG9vb2i1WqxYsQIREREFUO0/fHx8UKtWLaxevRrNmjUDAGzfvh0pKSno1KkT5s6dW6DrKygDBw6Es7Mzxo8fjytXrmD27NkYMGAAvvvuO32fcePGYfLkyWjevDmaN2+O48ePo0mTJsjMzFSM9fDhQzRo0AA3btzABx98gLJly+LgwYMYM2YMEhMTMXv2bEX/5cuXIy0tDR9++CEeP36MOXPmoGHDhjh9+jTc3NwAAH/++Sfq1KmD0qVLY/To0bC3t8fatWvRpk0bfP/992jbtm2R2Z5Vq1YhLS0NH3zwAVQqFaZPn4733nsPly5dgpWVFT744APcvHkTu3btMjjtnJvZs2dj4MCBitPROc+LsbXt2rULnTt3xjvvvINp06YBAOLi4nDgwAEMHjwY9evXx6BBgzB37lx8/PHHqFixIgDo/5ubP/74A/Xq1YOVlRX69u0LHx8fxMfHY/PmzZgyZYr+71avXj04Ojpi5MiRsLKywsKFCxEaGoq9e/eiZs2aJv3dVqxYgW+++QZHjx7Ft99+CwAGZ0lepF+/fli/fj0GDBiAoKAgJCUlYf/+/YiLi0P16tVzXUYIgVatWmH37t14//33Ua1aNezYsQMjRozAjRs3MGvWLEX//fv344cffkBUVBQ0Gg3mzp2Ldu3aISEhASVLlnxhjVOnToWtrS1Gjx6NixcvYt68ebCysoKFhQXu37+PCRMm4PDhw4iNjUW5cuUUgRETE4NKlSqhVatWKFasGDZv3oyoqCjodDp8+OGHAJ6/T+WIioqCi4sLxo0bh/T09FzrbNiwIaKiojB16lS0adMG1atXR2JiIgYOHIhGjRqhX79+L9zWp59k6SxdulQAMLip1WoRGxtr0B+AGD9+vMHyv//+e57ruHXrlnBxcREARIUKFUS/fv3EqlWrRHJy8nNrq1SpkmjQoMFz6/7999/FV199JTQajXj48KEQQogOHTqIsLAwIYQQ3t7eokWLFi94FgqPt7e3iIiI0N/PqbtRo0ZCp9Pp24cOHSosLS31z8mdO3eEtbW1aNGihaLfxx9/LAAoxpw0aZKwt7cX58+fV6x79OjRwtLSUiQkJAghhLh8+bIAIGxtbcX169f1/Y4cOSIAiKFDh+rb3nnnHREcHCweP36sb9PpdKJ27drC39+/SG1PyZIlxb179/T9fvzxRwFAbN68Wd/24YcfClP+F81r3zO2tsGDBwtHR0eRnZ2d5zrWrVsnAIjdu3cbVVP9+vWFRqMRV69eVbQ//Xy2adNGWFtbi/j4eH3bzZs3hUajEfXr19e3Gft3E0KIiIgIYW9vr1hnznO/dOlSgzqffY1wcnISH3744XO3LSIiQnh7e+vvb9y4UQAQkydPVvRr3769UKlU4uLFi4r1WVtbK9pOnTolAIh58+Y9d727d+8WAETlypVFZmamvr1z585CpVKJZs2aKfrXqlVLUacQQv+687Tw8HDh6+uraMtrn8r5W9StW9dgf8l57PLly/q29PR04efnJypVqiQeP34sWrRoIRwdHQ32ixeR+pTg/PnzsWvXLuzatQv//e9/ERYWht69e+OHH3546bHd3Nxw6tQp9OvXD/fv38fXX3+NLl26wNXVFZMmTTI4xDdVx44d8ejRI2zZsgVpaWnYsmVLkTgd+Dx9+/ZVnJaqV68etFotrl69CgD4+eefkZmZiYEDByr6DRkyxGCsdevWoV69enB2dsbff/+tvzVq1AharRa//fabon+bNm1QunRp/f233noLNWvWxLZt2wA8mSTz66+/omPHjkhLS9OPl5SUhPDwcFy4cAE3btwoMtvzn//8B87Ozop1A8ClS5cMxn5ZxtZWvHhxpKenK05Vv4y7d+/it99+Q69evVC2bFnFYznPp1arxc6dO9GmTRv4+vrqH/fw8ECXLl2wf/9+pKamKpZ90d+tIBQvXhxHjhzBzZs3jV5m27ZtsLS0xKBBgxTtw4YNgxDCYAZzo0aNUL58ef39KlWqwNHR0eh9oEePHorraDVr1oQQAr169VL0q1mzJq5du4bs7Gx9m62trf7fOWeqGjRogEuXLiElJcWo9QNAnz59jLpeZWdnh9jYWMTFxaF+/frYunUrZs2aZbBfvIjUpwTfeustxaSLzp0744033sCAAQPQsmXLl77g6uHhgZiYGCxYsAAXLlzAjh07MG3aNIwbNw4eHh7o3bt3vsd2cXFBo0aNsGrVKjx8+BBarRbt27c3evmUlBQ8evQoX+t2cnJS7LDGenbnynnBvX//PgDoXzD8/f0V/VxcXBQvzgBw4cIF/PHHH3Bxccl1XXfu3FHcf3ZMAAgICMDatWsBABcvXoQQAtHR0YiOjs5zzKdDz5zb86J1FyRja4uKisLatWvRrFkzlC5dGk2aNEHHjh3RtGnTfK0354W3cuXKefa5e/cuHj58iMDAQIPHKlasCJ1Oh2vXrqFSpUr69lfx3E2fPh0RERHw8vJCSEgImjdvjh49eihC9VlXr16Fp6cnNBqNwXbkPP603F6snZ2djd6OZ5d3cnICAHh5eRm063Q6pKSk6E81HjhwAOPHj8ehQ4fw8OFDRf+UlBT9WC9Srlw5o/oBQJ06ddC/f3/Mnz8f4eHhBsFqDKkD61kWFhYICwvDnDlzcOHCBcVO/jJUKhUCAgIQEBCAFi1awN/fHytXrnypwAKALl26oE+fPrh16xaaNWuG4sWLG73s4MGDsWzZsnytd+nSpfma+pzXO6n8HG3qdDo0btwYI0eOzPXxgIAAk8cDgOHDhyM8PDzXPn5+for75tyeglx3QdXm6uqKkydPYseOHdi+fTu2b9+OpUuXokePHvne1wpDfp+7vCataLVag7aOHTuiXr162LBhA3bu3IkZM2Zg2rRp+OGHH/TXnV/Wy+4DeS3/onHj4+PxzjvvoEKFCvjyyy/h5eUFa2trbNu2DbNmzTJpqr4pb3wzMjL0E3Ti4+Px8OFD2NnZGb088JoFFgD9Ye+DBw8KZXxfX184OzsjMTHxpcdq27YtPvjgAxw+fFhxod8YI0eOzPfkkoIK8md5e3sDePKO/ul3onfv3jV411i+fHk8ePAAjRo1MmrsCxcuGLSdP39eP0srZ31WVlZGj/kihbk9xnjerEBT+ptSm7W1Nd599128++670Ol0iIqKwsKFCxEdHQ0/Pz+Tasp5znKbzZnDxcUFdnZ2OHfunMFjZ8+ehYWFhcERQ37lHIklJycr2vM6lejh4YGoqChERUXhzp07qF69OqZMmZJnYHl7e+Pnn39GWlqa4ijr7Nmz+seLgs2bNyMjIwObNm1SHKXt3r3boK+p++DzjB8/HnFxcZg5cyZGjRqF0aNHmzzBTOprWM/KysrCzp07YW1t/dyZS8Y4cuRIrrNejh49iqSkpFxPYZjKwcEBMTExmDBhAt59912Tlg0KCkKjRo3ydfPw8Hjp2nPTqFEjWFlZYd68eYp3ic/OkAOevIM9dOgQduzYYfBYcnKy4nw7AGzcuFFxDero0aM4cuSI/sXD1dUVoaGhWLhwYa5vJp6drm7u7TGGvb29fnlj++fW19jakpKSFI9ZWFigSpUqAKCfFm1KTS4uLqhfvz6WLFmChIQExWM5z6elpSWaNGmCH3/8UfHtGbdv39Z/uN7R0fGF6zKGo6MjSpUqZXA9ccGCBYr7Wq3W4DqOq6srPD09DaaHP6158+bQarX46quvFO2zZs2CSqUqsCOzl5VzBPb0Pp2SkoKlS5ca9M1rnzLVkSNHMHPmTAwZMgTDhg3DiBEj8NVXX2Hv3r0mjSP1Edb27dv1717u3LmDVatW4cKFCxg9erRRO/mSJUty/dzD4MGDsWLFCqxcuRJt27ZFSEgIrK2tERcXhyVLlsDGxgYff/xxgWxDQU+ZNycXFxcMHz4cU6dORcuWLdG8eXOcOHEC27dvR6lSpRR9R4wYgU2bNqFly5aIjIxESEgI0tPTcfr0aaxfvx5XrlxRLOPn54e6deuif//+yMjIwOzZs1GyZEnFaa758+ejbt26CA4ORp8+feDr64vbt2/j0KFDuH79Ok6dOlVktscYISEhAIBBgwYhPDwclpaW6NSp03P7x8TEYPLkyfDz84OrqysaNmxodG29e/fGvXv30LBhQ5QpUwZXr17FvHnzUK1aNf0bwGrVqsHS0hLTpk1DSkoK1Gq1/vM8uZk7dy7q1q2L6tWro2/fvihXrhyuXLmCrVu34uTJkwCAyZMnY9euXahbty6ioqJQrFgxLFy4EBkZGZg+fbpJz9mL9O7dG59//jl69+6NGjVq4LfffsP58+cVfdLS0lCmTBm0b98eVatWhYODA37++Wf8/vvv+OKLL/Ic+91330VYWBjGjh2LK1euoGrVqti5cyd+/PFHDBkyRDHBwpyaNGmiP5L+4IMP8ODBAyxatAiurq4Gb/by2qdM8fjxY0RERMDf31//UYaJEydi8+bN6NmzJ06fPq1/I/RCJs0pLCJym9ZuY2MjqlWrJmJiYhRTXoXIe1p7Xrdr166JP/74Q4wYMUJUr15dlChRQhQrVkx4eHiIDh06iOPHj+dZm7HT2p+nqE5rf7bunOm1T09x1mq1YuLEicLDw0PY2tqK0NBQcebMGYMxhRAiLS1NjBkzRvj5+Qlra2tRqlQpUbt2bTFz5kz9dN2cqcgzZswQX3zxhfDy8hJqtVrUq1dPnDp1yqD2+Ph40aNHD+Hu7i6srKxE6dKlRcuWLcX69euL3PY869n9NDs7WwwcOFC4uLgIlUr1winut27dEi1atBAajUYAUOyHxtS2fv160aRJE+Hq6iqsra1F2bJlxQcffCASExMV61m0aJHw9fUVlpaWRk1xP3PmjGjbtq0oXry4sLGxEYGBgSI6OlrR5/jx4yI8PFw4ODgIOzs7ERYWJg4ePKjoY8rfLbdp7UI8mc79/vvvCycnJ6HRaETHjh3FnTt3FM99RkaGGDFihKhatarQaDTC3t5eVK1aVSxYsEAx1rPT2nOe56FDhwpPT09hZWUl/P39xYwZM3J9Tcpt2nxu+9WzcrZ33bp1Rj0/48ePFwDE3bt39W2bNm0SVapUETY2NsLHx0dMmzZNLFmyxGA6el771PNey56d1p7zsYMjR44o+h07dkwUK1ZM9O/f/7nb+zSVEIVwlZeogFy5cgXlypXDjBkzMHz4cHOXQ0Rm9FpdwyIiotcXA4uIiKTAwCIiIinwGhYREUmBR1hERCQFBhYREUlB6g8Om5NOp8PNmzeh0WgK9OtLiIgKmxACaWlp8PT0hIWFPMctDKx8unnzZoF9xxkRkTlcu3ZN/0vBMmBg5VPOl1tePe4DRwd53qGQPNoGBJu7BHpNZSML+7HN4KdQijoGVj7lnAZ0dLCAo4aBRQWvmMrqxZ2I8uP/54bLdjmDr7RERCQFBhYREUmBgUVERFJgYBERkRQYWEREJAUGFhERSYGBRUREUmBgERGRFBhYREQkBQYWERFJgYFFRERSYGAREZEUGFhERCQFBhYREUmBgUVERFJgYBERkRQYWEREJAUGFhERSYGBRUREUmBgERGRFBhYREQkBQYWERFJgYFFRERSYGAREZEUGFhERCQFBhYREUmBgUVERFJgYBERkRQYWEREJAUGFhERSYGBRUREUmBgERGRFBhYREQkBQYWERFJgYFFRERSYGAREZEUGFhERCQFBhYREUmBgUVERFJgYBERkRQYWEREJAUGFhERSYGBRUREUmBgERGRFBhYREQkBQYWERFJgYFFRERSYGAREZEUGFhERCQFBhYREUmBgUVERFJgYBERkRQYWEREJAUGFhERSYGBRUREUmBgERGRFBhYREQkBQYWERFJgYFFRERSYGAREZEUGFhERCQFBhYREUmBgUVERFJgYBERkRQYWEREJAUGFhERSYGBRUREUihm7gJIbn8nWmHxFA/8vtsRGY8s4OmTgWGzEhBQ9REAINyzWq7L9f7kBjpE3VW0ZWaoMLhFAC79ZYsFO8+hfOVHhV0+vWY6DriN9z++hQ2LSuHr8aXNXQ4VMAYW5VtasiU+au2PKrXTMPm/l1C8ZDZuXFLDwUmr77P65BnFMr//6ohZw7xQt0WKwXiLJ3uipHsWLv1lW+i10+snoOpDtOh2D5f+tDF3KVRIiuwpwcjISLRp08agfc+ePVCpVEhOTn7lNZHS2vmuKOWZieGzr6HCGw/hXjYTIaFp8PTJ1Pcp4ZqtuB3a4YSqdR7AwztTMdbvv2rwv70a9Bl341VvBr0GbOy0GPXVVcweUQZpKZbmLocKSZENLCr6Du90QkDVh5jc1wcdgyshqnEAtq0skWf/+3eL4egvjgjvlGTQPnuEF0bOuwq1rSjssuk1NOCzGzj6iyNO7NOYuxQqRFIHVlJSEjp37ozSpUvDzs4OwcHBWL16taJPaGgoBg4ciCFDhsDZ2Rlubm5YtGgR0tPT0bNnT2g0Gvj5+WH79u1m2gp5JSZYY8vyUvAsl4HPVl1Cy4gkxESXwa61zrn237W2BGwdtKjb/J/TgUIAM4eURYvuSfrrXkSmaND6PvyCH2HJVA9zl0KFTOrAevz4MUJCQrB161acOXMGffv2Rffu3XH06FFFv2XLlqFUqVI4evQoBg4ciP79+6NDhw6oXbs2jh8/jiZNmqB79+54+PBhnuvKyMhAamqq4vZvJ3SAX+VH6DUmEX7Bj9C8WxKadUnC1hWlcu2/Y00JNGx7H9Y2/xxF/bi4FB49sMB/Bt5+VWXTa8TFMxP9P72JaQPKIitD6pczMoJKCFEkz8FERkbiv//9L2xslBdQtVotHj9+jPv376N48eIGy7Vs2RIVKlTAzJkzATw5wtJqtdi3b59+eScnJ7z33ntYvnw5AODWrVvw8PDAoUOH8Pbbb+daz4QJEzBx4kSD9vvnfeGo+Xf+j9L9zSBUr5+GoV9c07dtXlYSq+e4YdXxvxR9Tx+xx/C2/liw6yzKV3qsb5/QsxyO7HIEVP/01WlVsLAUaPjefYyYk1Do21FU5TXDkv5Rq2kKJiy5Am32P22WxQCd7skbqpY+VaDTqfIe4F8qW2RhD35ESkoKHB0dzV2O0Yr0LMGwsDDExMQo2o4cOYJu3boBeBI+n332GdauXYsbN24gMzMTGRkZsLOzUyxTpUoV/b8tLS1RsmRJBAcH69vc3NwAAHfu3MmzljFjxuCjjz7S309NTYWXl1f+N+41EPRmOq7FqxVtNy6p4Vo6y6DvjtUl4V/loSKsACBq0nVEjvrnInnSLSt83KU8Pv76Ciq8kfcRLxEAnNzngL5hAYq2YbOu4dpFG6yd78Kwes0U6cCyt7eHn5+fou369ev6f8+YMQNz5szB7NmzERwcDHt7ewwZMgSZmcoZaFZWVor7KpVK0aZSPdmpdTpdnrWo1Wqo1eo8H/83eq/vHQxtFYDVc11R/91knDthh23/LYkhM64r+qWnWeC3zU7oO/6mwRiuZbIA/BNwNvZP/gae3plw8TQMPqKnPUq3xNVzyo9BPH5ogbT7hu0kvyIdWC9y4MABtG7dWn/EpdPpcP78eQQFBZm5sn+HwGqPMG7xZSyd6oGVs9zh7pWJfp/eQMP37iv67f3RGRAqhLW5n8dIREQvJnVg+fv7Y/369Th48CCcnZ3x5Zdf4vbt2wysV+jtxql4u/HzJ6A075aE5t2Sntsnh7tXJnbcPFkAldG/1cj2fi/uRFKSerbAJ598gurVqyM8PByhoaFwd3fP9cPGREQkvyI7S7CoS01NhZOT0796liAVLs4SpMIi6yxBvtISEZEUGFhERCQFBhYREUmBgUVERFJgYBERkRQYWEREJAUGFhERSYGBRUREUmBgERGRFBhYREQkBQYWERFJgYFFRERSYGAREZEUGFhERCQFBhYREUmBgUVERFJgYBERkRQYWEREJAUGFhERSYGBRUREUmBgERGRFBhYREQkBQYWERFJgYFFRERSYGAREZEUGFhERCQFBhYREUmBgUVERFJgYBERkRQYWEREJAUGFhERSYGBRUREUmBgERGRFBhYREQkBQYWERFJgYFFRERSYGAREZEUihnTadOmTUYP2KpVq3wXQ0RElBejAqtNmzZGDaZSqaDVal+mHiIiolwZFVg6na6w6yAiInqul7qG9fjx44Kqg4iI6LlMDiytVotJkyahdOnScHBwwKVLlwAA0dHRWLx4cYEXSEREBOQjsKZMmYLY2FhMnz4d1tbW+vbKlSvj22+/LdDiiIiIcpgcWMuXL8c333yDrl27wtLSUt9etWpVnD17tkCLIyIiymFyYN24cQN+fn4G7TqdDllZWQVSFBER0bNMDqygoCDs27fPoH39+vV44403CqQoIiKiZxk1rf1p48aNQ0REBG7cuAGdTocffvgB586dw/Lly7Fly5bCqJGIiMj0I6zWrVtj8+bN+Pnnn2Fvb49x48YhLi4OmzdvRuPGjQujRiIiItOPsACgXr162LVrV0HXQkRElKd8BRYAHDt2DHFxcQCeXNcKCQkpsKKIiIieZXJgXb9+HZ07d8aBAwdQvHhxAEBycjJq166NNWvWoEyZMgVdIxERkenXsHr37o2srCzExcXh3r17uHfvHuLi4qDT6dC7d+/CqJGIiMj0I6y9e/fi4MGDCAwM1LcFBgZi3rx5qFevXoEWR0RElMPkIywvL69cPyCs1Wrh6elZIEURERE9y+TAmjFjBgYOHIhjx47p244dO4bBgwdj5syZBVocERFRDpUQQryok7OzM1Qqlf5+eno6srOzUazYkzOKOf+2t7fHvXv3Cq/aIiQ1NRVOTk64f94XjpqX+pUWolyFe1Yzdwn0msoWWdiDH5GSkgJHR0dzl2M0o65hzZ49u5DLICIi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",
      "text/plain": [
       "<Figure size 500x400 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Predict spam probabilities for the independent test set.\n",
    "test_prob_bilstm = np.asarray(bilstm.predict(X_test, verbose=0)).ravel()\n",
    "\n",
    "# Convert probabilities to class labels with the frozen validation-selected threshold.\n",
    "bilstm_predictions = (test_prob_bilstm >= BILSTM_THRESHOLD).astype(int)\n",
    "\n",
    "b_precision, b_recall, b_f1 = spam_metrics_at_threshold(\n",
    "    y_test,\n",
    "    test_prob_bilstm,\n",
    "    BILSTM_THRESHOLD,\n",
    ")\n",
    "\n",
    "bilstm_metrics = {\n",
    "    \"accuracy\": accuracy_score(y_test, bilstm_predictions),\n",
    "    \"spam_precision\": b_precision,\n",
    "    \"spam_recall\": b_recall,\n",
    "    \"spam_f1\": b_f1,\n",
    "    \"roc_auc\": roc_auc_score(y_test, test_prob_bilstm),\n",
    "    \"pr_auc\": average_precision_score(y_test, test_prob_bilstm),\n",
    "    \"threshold\": BILSTM_THRESHOLD,\n",
    "}\n",
    "\n",
    "print(pd.Series(bilstm_metrics).round(4).to_string())\n",
    "print()\n",
    "print(\"Classification report:\")\n",
    "print()\n",
    "print(\n",
    "    classification_report(\n",
    "        y_test,\n",
    "        bilstm_predictions,\n",
    "        target_names=[\"ham\", \"spam\"],\n",
    "        digits=4,\n",
    "        zero_division=0,\n",
    "    )\n",
    ")\n",
    "\n",
    "bilstm_cm = confusion_matrix(y_test, bilstm_predictions)\n",
    "fig, ax = plt.subplots(figsize=(5, 4))\n",
    "ConfusionMatrixDisplay(\n",
    "    bilstm_cm,\n",
    "    display_labels=[\"Ham\", \"Spam\"],\n",
    ").plot(ax=ax, colorbar=False)\n",
    "ax.set_title(\"BiLSTM : independent test confusion matrix\")\n",
    "fig.tight_layout()\n",
    "fig.savefig(ASSET_DIR / \"06_bilstm_confusion_matrix.png\", dpi=160, bbox_inches=\"tight\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f93c97dd",
   "metadata": {},
   "source": [
    "## 14. Build a simpler baseline: TF-IDF + Logistic Regression\n",
    "\n",
    "A neural network is not automatically the best choice for a text-classification problem.\n",
    "\n",
    "To test whether the BiLSTM adds real value, I compare it with a classical NLP pipeline:\n",
    "\n",
    "1. **TF-IDF** converts words and n-grams into weighted numeric features;\n",
    "2. **Logistic Regression** learns the decision boundary.\n",
    "\n",
    "The TF-IDF vocabulary is learned from the training set only. Its final probability threshold is also selected on the validation set.\n",
    "\n",
    "This gives the BiLSTM a meaningful baseline rather than comparing it only with itself.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "9b2f216d",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-18T18:30:45.713561Z",
     "iopub.status.busy": "2026-10-18T18:30:45.713359Z",
     "iopub.status.idle": "2026-10-18T18:30:45.981083Z",
     "shell.execute_reply": "2026-10-18T18:30:45.980702Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "threshold         0.5600\n",
      "spam_precision    0.9341\n",
      "spam_recall       0.8854\n",
      "spam_f1           0.9091\n",
      "Frozen baseline threshold: 0.56\n"
     ]
    }
   ],
   "source": [
    "# TF-IDF learns its vocabulary and statistics from the training text only.\n",
    "tfidf = TfidfVectorizer(\n",
    "    max_features=5000,\n",
    "    ngram_range=(1, 2),\n",
    "    min_df=2,\n",
    "    sublinear_tf=True,\n",
    ")\n",
    "\n",
    "X_train_tfidf = tfidf.fit_transform(train_df[\"cleaned_message\"])\n",
    "X_validation_tfidf = tfidf.transform(validation_df[\"cleaned_message\"])\n",
    "X_test_tfidf = tfidf.transform(test_df[\"cleaned_message\"])\n",
    "\n",
    "# Balanced class weights help the model pay more attention to minority spam examples.\n",
    "baseline = LogisticRegression(\n",
    "    max_iter=2000,\n",
    "    class_weight=\"balanced\",\n",
    "    random_state=SEED,\n",
    ")\n",
    "baseline.fit(X_train_tfidf, y_train)\n",
    "\n",
    "# Select the baseline threshold on validation data exactly as we did for the BiLSTM.\n",
    "validation_prob_baseline = baseline.predict_proba(X_validation_tfidf)[:, 1]\n",
    "baseline_threshold_results = []\n",
    "\n",
    "for threshold in threshold_grid:\n",
    "    precision, recall, f1 = spam_metrics_at_threshold(\n",
    "        y_validation,\n",
    "        validation_prob_baseline,\n",
    "        threshold,\n",
    "    )\n",
    "    baseline_threshold_results.append((threshold, precision, recall, f1))\n",
    "\n",
    "baseline_thresholds = pd.DataFrame(\n",
    "    baseline_threshold_results,\n",
    "    columns=[\"threshold\", \"spam_precision\", \"spam_recall\", \"spam_f1\"],\n",
    ")\n",
    "\n",
    "best_baseline_row = baseline_thresholds.sort_values(\n",
    "    [\"spam_f1\", \"spam_recall\", \"spam_precision\"],\n",
    "    ascending=False,\n",
    ").iloc[0]\n",
    "\n",
    "BASELINE_THRESHOLD = float(best_baseline_row[\"threshold\"])\n",
    "\n",
    "print(best_baseline_row.round(4).to_string())\n",
    "print(\"Frozen baseline threshold:\", round(BASELINE_THRESHOLD, 2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "1d5f0ab3",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-18T18:30:45.989928Z",
     "iopub.status.busy": "2026-10-18T18:30:45.989786Z",
     "iopub.status.idle": "2026-10-18T18:30:46.108957Z",
     "shell.execute_reply": "2026-10-18T18:30:46.108395Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "accuracy          0.9793\n",
      "spam_precision    0.9348\n",
      "spam_recall       0.8958\n",
      "spam_f1           0.9149\n",
      "roc_auc           0.9953\n",
      "pr_auc            0.9749\n",
      "threshold         0.5600\n",
      "\n",
      "Classification report:\n",
      "\n",
      "              precision    recall  f1-score   support\n",
      "\n",
      "         ham     0.9853    0.9912    0.9882       678\n",
      "        spam     0.9348    0.8958    0.9149        96\n",
      "\n",
      "    accuracy                         0.9793       774\n",
      "   macro avg     0.9601    0.9435    0.9516       774\n",
      "weighted avg     0.9791    0.9793    0.9791       774\n",
      "\n"
     ]
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 500x400 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Final baseline evaluation on the same untouched test set.\n",
    "test_prob_baseline = baseline.predict_proba(X_test_tfidf)[:, 1]\n",
    "baseline_predictions = (test_prob_baseline >= BASELINE_THRESHOLD).astype(int)\n",
    "\n",
    "l_precision, l_recall, l_f1 = spam_metrics_at_threshold(\n",
    "    y_test,\n",
    "    test_prob_baseline,\n",
    "    BASELINE_THRESHOLD,\n",
    ")\n",
    "\n",
    "baseline_metrics = {\n",
    "    \"accuracy\": accuracy_score(y_test, baseline_predictions),\n",
    "    \"spam_precision\": l_precision,\n",
    "    \"spam_recall\": l_recall,\n",
    "    \"spam_f1\": l_f1,\n",
    "    \"roc_auc\": roc_auc_score(y_test, test_prob_baseline),\n",
    "    \"pr_auc\": average_precision_score(y_test, test_prob_baseline),\n",
    "    \"threshold\": BASELINE_THRESHOLD,\n",
    "}\n",
    "\n",
    "print(pd.Series(baseline_metrics).round(4).to_string())\n",
    "print()\n",
    "print(\"Classification report:\")\n",
    "print()\n",
    "print(\n",
    "    classification_report(\n",
    "        y_test,\n",
    "        baseline_predictions,\n",
    "        target_names=[\"ham\", \"spam\"],\n",
    "        digits=4,\n",
    "        zero_division=0,\n",
    "    )\n",
    ")\n",
    "\n",
    "baseline_cm = confusion_matrix(y_test, baseline_predictions)\n",
    "fig, ax = plt.subplots(figsize=(5, 4))\n",
    "ConfusionMatrixDisplay(\n",
    "    baseline_cm,\n",
    "    display_labels=[\"Ham\", \"Spam\"],\n",
    ").plot(ax=ax, colorbar=False)\n",
    "ax.set_title(\"TF-IDF + Logistic Regression : test confusion matrix\")\n",
    "fig.tight_layout()\n",
    "fig.savefig(ASSET_DIR / \"07_baseline_confusion_matrix.png\", dpi=160, bbox_inches=\"tight\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0032484f",
   "metadata": {},
   "source": [
    "## 15. Compare both approaches\n",
    "\n",
    "The comparison focuses on the spam class because spam is the minority class and the main target of the project.\n",
    "\n",
    "The BiLSTM performs slightly better on the final thresholded classification metrics, while the TF-IDF baseline remains very close and even records slightly stronger ROC-AUC / PR-AUC.\n",
    "\n",
    "That makes the result more useful than a simple “deep learning wins” conclusion: the extra complexity produces only a modest gain on this dataset.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "fa716f6d",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-18T18:30:46.110459Z",
     "iopub.status.busy": "2026-10-18T18:30:46.110352Z",
     "iopub.status.idle": "2026-10-18T18:30:46.284158Z",
     "shell.execute_reply": "2026-10-18T18:30:46.283472Z"
    }
   },
   "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>accuracy</th>\n",
       "      <th>spam_precision</th>\n",
       "      <th>spam_recall</th>\n",
       "      <th>spam_f1</th>\n",
       "      <th>roc_auc</th>\n",
       "      <th>pr_auc</th>\n",
       "      <th>threshold</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>BiLSTM</th>\n",
       "      <td>0.9832</td>\n",
       "      <td>0.9560</td>\n",
       "      <td>0.9062</td>\n",
       "      <td>0.9305</td>\n",
       "      <td>0.9937</td>\n",
       "      <td>0.9733</td>\n",
       "      <td>0.83</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>TF-IDF + Logistic Regression</th>\n",
       "      <td>0.9793</td>\n",
       "      <td>0.9348</td>\n",
       "      <td>0.8958</td>\n",
       "      <td>0.9149</td>\n",
       "      <td>0.9953</td>\n",
       "      <td>0.9749</td>\n",
       "      <td>0.56</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                              accuracy  spam_precision  ...  pr_auc  threshold\n",
       "BiLSTM                          0.9832          0.9560  ...  0.9733       0.83\n",
       "TF-IDF + Logistic Regression    0.9793          0.9348  ...  0.9749       0.56\n",
       "\n",
       "[2 rows x 7 columns]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 800x400 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "comparison = pd.DataFrame(\n",
    "    [bilstm_metrics, baseline_metrics],\n",
    "    index=[\"BiLSTM\", \"TF-IDF + Logistic Regression\"],\n",
    ")\n",
    "\n",
    "display(comparison.round(4))\n",
    "\n",
    "# Visual comparison of the most intuitive classification metrics.\n",
    "plot_metrics = comparison[[\n",
    "    \"accuracy\",\n",
    "    \"spam_precision\",\n",
    "    \"spam_recall\",\n",
    "    \"spam_f1\",\n",
    "]].T\n",
    "\n",
    "ax = plot_metrics.plot(kind=\"bar\", figsize=(8, 4))\n",
    "ax.set_ylim(0, 1.05)\n",
    "ax.set_ylabel(\"Score\")\n",
    "ax.set_title(\"Independent test performance\")\n",
    "ax.legend(title=\"Model\")\n",
    "plt.xticks(rotation=0)\n",
    "plt.tight_layout()\n",
    "plt.savefig(ASSET_DIR / \"08_model_comparison.png\", dpi=160, bbox_inches=\"tight\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "58cc349b",
   "metadata": {},
   "source": [
    "## 16. Inspect the remaining errors\n",
    "\n",
    "A confusion matrix tells us how many errors were made, but not what those messages look like.\n",
    "\n",
    "I inspect:\n",
    "\n",
    "- **false negatives**: spam that the model allowed through;\n",
    "- **false positives**: legitimate messages incorrectly blocked as spam.\n",
    "\n",
    "This helps identify ambiguous language, unusual wording and cases where future features or more training data could improve the system.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "ce6903d6",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-18T18:30:46.285640Z",
     "iopub.status.busy": "2026-10-18T18:30:46.285529Z",
     "iopub.status.idle": "2026-10-18T18:30:46.308522Z",
     "shell.execute_reply": "2026-10-18T18:30:46.307563Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "BiLSTM false negatives : real spam classified as ham:\n"
     ]
    },
    {
     "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>display_message</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>671</th>\n",
       "      <td>Hi I'm sue. I am 20 years old and work as a la...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2637</th>\n",
       "      <td>Burger King - Wanna play footy at a top stadiu...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3943</th>\n",
       "      <td>Missed call alert. These numbers called but le...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5125</th>\n",
       "      <td>Want explicit SEX in 30 secs? Ring [NUMBER] no...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5050</th>\n",
       "      <td>Latest News! Police station toilet stolen, cop...</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                                        display_message\n",
       "671   Hi I'm sue. I am 20 years old and work as a la...\n",
       "2637  Burger King - Wanna play footy at a top stadiu...\n",
       "3943  Missed call alert. These numbers called but le...\n",
       "5125  Want explicit SEX in 30 secs? Ring [NUMBER] no...\n",
       "5050  Latest News! Police station toilet stolen, cop..."
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "BiLSTM false positives : real ham classified as spam:\n"
     ]
    },
    {
     "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>display_message</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>3258</th>\n",
       "      <td>Nowadays people are notixiquating the laxinorf...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4283</th>\n",
       "      <td>I wanted to wish you a Happy New Year and I wa...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4409</th>\n",
       "      <td>I (Career Tel) have added u as a contact on IN...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3593</th>\n",
       "      <td>Please protect yourself from e-threats. SIB ne...</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                                        display_message\n",
       "3258  Nowadays people are notixiquating the laxinorf...\n",
       "4283  I wanted to wish you a Happy New Year and I wa...\n",
       "4409  I (Career Tel) have added u as a contact on IN...\n",
       "3593  Please protect yourself from e-threats. SIB ne..."
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Baseline false negatives:\n"
     ]
    },
    {
     "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>display_message</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>671</th>\n",
       "      <td>Hi I'm sue. I am 20 years old and work as a la...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2637</th>\n",
       "      <td>Burger King - Wanna play footy at a top stadiu...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3943</th>\n",
       "      <td>Missed call alert. These numbers called but le...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5125</th>\n",
       "      <td>Want explicit SEX in 30 secs? Ring [NUMBER] no...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5050</th>\n",
       "      <td>Latest News! Police station toilet stolen, cop...</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                                        display_message\n",
       "671   Hi I'm sue. I am 20 years old and work as a la...\n",
       "2637  Burger King - Wanna play footy at a top stadiu...\n",
       "3943  Missed call alert. These numbers called but le...\n",
       "5125  Want explicit SEX in 30 secs? Ring [NUMBER] no...\n",
       "5050  Latest News! Police station toilet stolen, cop..."
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Baseline false positives:\n"
     ]
    },
    {
     "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>display_message</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>152</th>\n",
       "      <td>Ok... Ur typical reply...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>178</th>\n",
       "      <td>Hi! You just spoke to MANEESHA V. We'd like to...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3331</th>\n",
       "      <td>I'm at home. Please call</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4409</th>\n",
       "      <td>I (Career Tel) have added u as a contact on IN...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3593</th>\n",
       "      <td>Please protect yourself from e-threats. SIB ne...</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                                        display_message\n",
       "152                           Ok... Ur typical reply...\n",
       "178   Hi! You just spoke to MANEESHA V. We'd like to...\n",
       "3331                           I'm at home. Please call\n",
       "4409  I (Career Tel) have added u as a contact on IN...\n",
       "3593  Please protect yourself from e-threats. SIB ne..."
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def redact_for_display(text):\n",
    "    \"\"\"Hide URLs and long number sequences in displayed error examples.\"\"\"\n",
    "    text = URL_PATTERN.sub(\"[URL]\", str(text))\n",
    "    text = re.sub(r\"\\b\\d{3,}\\b\", \"[NUMBER]\", text)\n",
    "    return text[:220] + (\"…\" if len(text) > 220 else \"\")\n",
    "\n",
    "\n",
    "errors = test_df[[\"Message\", \"label\"]].copy()\n",
    "errors[\"bilstm_pred\"] = bilstm_predictions\n",
    "errors[\"baseline_pred\"] = baseline_predictions\n",
    "errors[\"display_message\"] = errors[\"Message\"].map(redact_for_display)\n",
    "\n",
    "print(\"BiLSTM false negatives : real spam classified as ham:\")\n",
    "display(\n",
    "    errors[(errors.label == 1) & (errors.bilstm_pred == 0)][[\"display_message\"]].head(5)\n",
    ")\n",
    "\n",
    "print(\"BiLSTM false positives : real ham classified as spam:\")\n",
    "display(\n",
    "    errors[(errors.label == 0) & (errors.bilstm_pred == 1)][[\"display_message\"]].head(5)\n",
    ")\n",
    "\n",
    "print(\"Baseline false negatives:\")\n",
    "display(\n",
    "    errors[(errors.label == 1) & (errors.baseline_pred == 0)][[\"display_message\"]].head(5)\n",
    ")\n",
    "\n",
    "print(\"Baseline false positives:\")\n",
    "display(\n",
    "    errors[(errors.label == 0) & (errors.baseline_pred == 1)][[\"display_message\"]].head(5)\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1daed44d",
   "metadata": {},
   "source": [
    "## 17. Test the models on new messages\n",
    "\n",
    "This helper function shows how the two trained models classify a new SMS.\n",
    "\n",
    "It is included to demonstrate the inference flow from raw text to final prediction. It is not presented as a production messaging service.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "7c811244",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-18T18:30:46.309672Z",
     "iopub.status.busy": "2026-10-18T18:30:46.309563Z",
     "iopub.status.idle": "2026-10-18T18:30:46.503054Z",
     "shell.execute_reply": "2026-10-18T18:30:46.502448Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'BiLSTM': {'label': 'SPAM', 'spam_probability': 0.9502, 'threshold': 0.83}, 'TF-IDF + Logistic Regression': {'label': 'SPAM', 'spam_probability': 0.776, 'threshold': 0.56}}\n",
      "{'BiLSTM': {'label': 'HAM', 'spam_probability': 0.0012, 'threshold': 0.83}, 'TF-IDF + Logistic Regression': {'label': 'HAM', 'spam_probability': 0.0704, 'threshold': 0.56}}\n"
     ]
    }
   ],
   "source": [
    "def predict_message(message):\n",
    "    \"\"\"Return predictions from both final models for one new SMS.\"\"\"\n",
    "    cleaned = clean_text(message)\n",
    "\n",
    "    # ----- BiLSTM path -----\n",
    "    sequence = texts_to_sequences(pd.Series([cleaned]))\n",
    "    padded = keras.utils.pad_sequences(\n",
    "        sequence,\n",
    "        maxlen=MAX_SEQUENCE_LENGTH,\n",
    "        padding=\"post\",\n",
    "        truncating=\"post\",\n",
    "    )\n",
    "    bilstm_probability = float(\n",
    "        np.asarray(bilstm.predict(padded, verbose=0)).ravel()[0]\n",
    "    )\n",
    "\n",
    "    # ----- TF-IDF + Logistic Regression path -----\n",
    "    baseline_probability = float(\n",
    "        baseline.predict_proba(tfidf.transform([cleaned]))[0, 1]\n",
    "    )\n",
    "\n",
    "    return {\n",
    "        \"BiLSTM\": {\n",
    "            \"label\": \"SPAM\" if bilstm_probability >= BILSTM_THRESHOLD else \"HAM\",\n",
    "            \"spam_probability\": round(bilstm_probability, 4),\n",
    "            \"threshold\": round(BILSTM_THRESHOLD, 2),\n",
    "        },\n",
    "        \"TF-IDF + Logistic Regression\": {\n",
    "            \"label\": \"SPAM\" if baseline_probability >= BASELINE_THRESHOLD else \"HAM\",\n",
    "            \"spam_probability\": round(baseline_probability, 4),\n",
    "            \"threshold\": round(BASELINE_THRESHOLD, 2),\n",
    "        },\n",
    "    }\n",
    "\n",
    "\n",
    "print(predict_message(\"Congratulations! You've won a free prize. Click here now.\"))\n",
    "print(predict_message(\"Can we meet at the library at 5?\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "69dacbf4",
   "metadata": {},
   "source": [
    "## Results, limits and what I learned\n",
    "\n",
    "The BiLSTM achieved the best spam F1-score on the independent test set:\n",
    "\n",
    "- **98.32% accuracy**\n",
    "- **95.60% spam precision**\n",
    "- **90.62% spam recall**\n",
    "- **0.930 spam F1**\n",
    "\n",
    "TF-IDF + Logistic Regression stayed close at **0.915 spam F1**.\n",
    "\n",
    "That comparison was the most useful part of the project for me. The BiLSTM performed better, but the gain was not large. In a real system I would therefore compare model quality with inference cost, latency and maintenance before choosing the final solution.\n",
    "\n",
    "Main limits:\n",
    "- relatively small and old SMS corpus;\n",
    "- no multilingual evaluation;\n",
    "- no external test dataset;\n",
    "- no production latency or drift monitoring.\n",
    "\n",
    "A next version could test newer external data, character-level or Transformer models, and an API with measured inference latency.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7b834dc6",
   "metadata": {},
   "source": [
    "## Resources\n",
    "\n",
    "- Source dataset: `spam.csv`\n",
    "- Main technologies: Python, pandas, scikit-learn, Keras, TF-IDF, Logistic Regression, BiLSTM\n",
    "- Final notebook purpose: reproducible academic case study and portfolio evidence\n",
    "\n",
    "This public notebook documents the project workflow and the evaluation used in the portfolio case study.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "71812456",
   "metadata": {},
   "source": [
    "## 19. Save the key results\n",
    "\n",
    "The final cell exports the main metrics and settings in JSON format. This makes it easier to keep documentation and reported results consistent with the executed notebook.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "b4a1c82c",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-18T18:30:46.504711Z",
     "iopub.status.busy": "2026-10-18T18:30:46.504572Z",
     "iopub.status.idle": "2026-10-18T18:30:46.522191Z",
     "shell.execute_reply": "2026-10-18T18:30:46.521330Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Canonical conclusion: on the independent 774-message test set, BiLSTM achieved the higher spam F1 score.\n",
      "\n",
      "Final comparison:\n"
     ]
    },
    {
     "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>accuracy</th>\n",
       "      <th>spam_precision</th>\n",
       "      <th>spam_recall</th>\n",
       "      <th>spam_f1</th>\n",
       "      <th>roc_auc</th>\n",
       "      <th>pr_auc</th>\n",
       "      <th>threshold</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>BiLSTM</th>\n",
       "      <td>0.9832</td>\n",
       "      <td>0.9560</td>\n",
       "      <td>0.9062</td>\n",
       "      <td>0.9305</td>\n",
       "      <td>0.9937</td>\n",
       "      <td>0.9733</td>\n",
       "      <td>0.83</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>TF-IDF + Logistic Regression</th>\n",
       "      <td>0.9793</td>\n",
       "      <td>0.9348</td>\n",
       "      <td>0.8958</td>\n",
       "      <td>0.9149</td>\n",
       "      <td>0.9953</td>\n",
       "      <td>0.9749</td>\n",
       "      <td>0.56</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                              accuracy  spam_precision  ...  pr_auc  threshold\n",
       "BiLSTM                          0.9832          0.9560  ...  0.9733       0.83\n",
       "TF-IDF + Logistic Regression    0.9793          0.9348  ...  0.9749       0.56\n",
       "\n",
       "[2 rows x 7 columns]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "run_metadata = {\n",
    "    \"seed\": SEED,\n",
    "    \"keras_version\": keras.__version__,\n",
    "    \"keras_backend\": keras.backend.backend(),\n",
    "    \"raw_rows\": len(df_raw),\n",
    "    \"raw_ham\": int((df_raw.Category == \"ham\").sum()),\n",
    "    \"raw_spam\": int((df_raw.Category == \"spam\").sum()),\n",
    "    \"exact_duplicates_removed\": exact_duplicates,\n",
    "    \"unique_rows\": len(df),\n",
    "    \"unique_ham\": int((df.Category == \"ham\").sum()),\n",
    "    \"unique_spam\": int((df.Category == \"spam\").sum()),\n",
    "    \"train_rows\": len(train_df),\n",
    "    \"validation_rows\": len(validation_df),\n",
    "    \"test_rows\": len(test_df),\n",
    "    \"vocabulary_size\": len(word_index),\n",
    "    \"max_sequence_length\": MAX_SEQUENCE_LENGTH,\n",
    "    \"bilstm\": {key: float(value) for key, value in bilstm_metrics.items()},\n",
    "    \"baseline\": {key: float(value) for key, value in baseline_metrics.items()},\n",
    "    \"bilstm_confusion_matrix\": bilstm_cm.tolist(),\n",
    "    \"baseline_confusion_matrix\": baseline_cm.tolist(),\n",
    "}\n",
    "\n",
    "with open(ASSET_DIR / \"run_metadata.json\", \"w\", encoding=\"utf-8\") as file:\n",
    "    json.dump(run_metadata, file, indent=2)\n",
    "\n",
    "comparison.to_csv(ASSET_DIR / \"model_comparison.csv\")\n",
    "bilstm_thresholds.to_csv(\n",
    "    ASSET_DIR / \"bilstm_validation_thresholds.csv\",\n",
    "    index=False,\n",
    ")\n",
    "baseline_thresholds.to_csv(\n",
    "    ASSET_DIR / \"baseline_validation_thresholds.csv\",\n",
    "    index=False,\n",
    ")\n",
    "\n",
    "winner = comparison[\"spam_f1\"].idxmax()\n",
    "print(\n",
    "    f\"Canonical conclusion: on the independent {len(test_df)}-message test set, \"\n",
    "    f\"{winner} achieved the higher spam F1 score.\"\n",
    ")\n",
    "print()\n",
    "print(\"Final comparison:\")\n",
    "display(comparison.round(4))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "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.13.5"
  },
  "project": {
   "school": "ESAIP Engineering School, France",
   "program": "MSc Cybersecurity & Data Science",
   "program_period": "2024-2026",
   "author": "Fils Aboubakar Sidik MBOHOU",
   "project_type": "Individual academic project"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}