{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "dd93c4f2-d64a-4148-9673-cd749392b11d",
   "metadata": {},
   "source": [
    "# Practical-2b (Classification using Deep Neural Network - IMDB Dataset)\n",
    "\n",
    "---\n",
    "\n",
    "Problem Statement: Binary classification using Deep Neural Networks Example: Classify movie reviews into positive\" reviews and \"negative\" reviews, just based on the text content of the reviews. Use IMDB dataset\n",
    "\n",
    "- Dataset link: https://www.kaggle.com/datasets/lakshmi25npathi/imdb-dataset-of-50k-movie-reviews\n",
    "- Dataset available in [Datasets](https://git.kska.io/sppu-be-comp-content/DeepLearning/src/branch/main/Datasets/) directory.\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "0a8eeb31-1a70-45b4-93f1-2611c5d612d3",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING: All log messages before absl::InitializeLog() is called are written to STDERR\n",
      "I0000 00:00:1777813310.532586   61345 cudart_stub.cc:31] Could not find cuda drivers on your machine, GPU will not be used.\n",
      "I0000 00:00:1777813310.578090   61345 cpu_feature_guard.cc:227] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n",
      "To enable the following instructions: AVX2 FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.\n",
      "WARNING: All log messages before absl::InitializeLog() is called are written to STDERR\n",
      "I0000 00:00:1777813312.920697   61345 cudart_stub.cc:31] Could not find cuda drivers on your machine, GPU will not be used.\n"
     ]
    }
   ],
   "source": [
    "# 1. Import Libraries\n",
    "import re\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.preprocessing import LabelEncoder\n",
    "from sklearn.metrics import confusion_matrix, classification_report\n",
    "from tensorflow.keras.models import Sequential\n",
    "from tensorflow.keras.layers import Dense, Embedding, GlobalAveragePooling1D\n",
    "from tensorflow.keras.preprocessing.text import Tokenizer\n",
    "from tensorflow.keras.preprocessing.sequence import pad_sequences"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "2cec2b8a-0371-4884-b17b-cd909a4b1b72",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "                                              review sentiment\n",
      "0  One of the other reviewers has mentioned that ...  positive\n",
      "1  A wonderful little production. <br /><br />The...  positive\n",
      "2  I thought this was a wonderful way to spend ti...  positive\n",
      "3  Basically there's a family where a little boy ...  negative\n",
      "4  Petter Mattei's \"Love in the Time of Money\" is...  positive\n"
     ]
    }
   ],
   "source": [
    "# 2. Load Dataset\n",
    "data = pd.read_csv('IMDB Dataset.csv')\n",
    "print(data.head())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "dfed9c66",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Shape: (50000, 2)\n",
      "\n",
      "Missing Values:\n",
      " review       0\n",
      "sentiment    0\n",
      "dtype: int64\n",
      "\n",
      "Class Distribution:\n",
      " sentiment\n",
      "positive    25000\n",
      "negative    25000\n",
      "Name: count, dtype: int64\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 22656 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Sample positive review:\n",
      " One of the other reviewers has mentioned that after watching just 1 Oz episode you'll be hooked. They are right, as this is exactly what happened with me.<br /><br />The first thing that struck me about Oz was its brutality and unflinching scenes of violence, which set in right from the word GO. Tru\n",
      "\n",
      "Sample negative review:\n",
      " Basically there's a family where a little boy (Jake) thinks there's a zombie in his closet & his parents are fighting all the time.<br /><br />This movie is slower than a soap opera... and suddenly, Jake decides to become Rambo and kill the zombie.<br /><br />OK, first of all when you're going to ma\n"
     ]
    }
   ],
   "source": [
    "# 3. Exploratory Data Analysis (EDA)\n",
    "print(\"Shape:\", data.shape)\n",
    "print(\"\\nMissing Values:\\n\", data.isnull().sum())\n",
    "print(\"\\nClass Distribution:\\n\", data['sentiment'].value_counts())\n",
    "\n",
    "# Visualize class distribution\n",
    "sns.countplot(x='sentiment', data=data)\n",
    "plt.title('Sentiment Class Distribution')\n",
    "plt.show()\n",
    "\n",
    "# Sample reviews\n",
    "print(\"\\nSample positive review:\\n\", data[data['sentiment'] == 'positive']['review'].iloc[0][:300])\n",
    "print(\"\\nSample negative review:\\n\", data[data['sentiment'] == 'negative']['review'].iloc[0][:300])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "4ae3e31b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Sample cleaned review:\n",
      " one of the other reviewers has mentioned that after watching just 1 oz episode you'll be hooked. they are right, as this is exactly what happened with me.the first thing that struck me about oz was its brutality and unflinching scenes of violence, which set in right from the word go. trust me, this \n"
     ]
    }
   ],
   "source": [
    "# 4. Data Cleaning - Strip HTML Tags\n",
    "def clean_text(text):\n",
    "    text = re.sub(r'<.*?>', '', text)   # remove HTML tags like <br />\n",
    "    text = text.lower().strip()         # lowercase and trim whitespace\n",
    "    return text\n",
    "\n",
    "data['review'] = data['review'].apply(clean_text)\n",
    "print(\"Sample cleaned review:\\n\", data['review'].iloc[0][:300])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "9e041a03-e7a7-42ab-a691-f47ba275053e",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 5. Encode Labels and Separate Features\n",
    "label_encoder = LabelEncoder()\n",
    "data['sentiment'] = label_encoder.fit_transform(data['sentiment'])  # positive=1, negative=0\n",
    "\n",
    "X = data['review'].values    # input: review text\n",
    "y = data['sentiment'].values # output: 0 or 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "05290c03-55b1-4110-a43d-4a80d85afba8",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 6. Tokenize and Pad Text Sequences\n",
    "vocab_size = 10000   # keep only top 10,000 most frequent words\n",
    "max_length = 200     # truncate/pad all reviews to 200 words\n",
    "\n",
    "tokenizer = Tokenizer(num_words=vocab_size, oov_token='<OOV>')  # <OOV> handles unknown words\n",
    "tokenizer.fit_on_texts(X)                        # build word index from training text\n",
    "\n",
    "sequences = tokenizer.texts_to_sequences(X)      # convert each word to its integer index\n",
    "padded_sequences = pad_sequences(sequences, maxlen=max_length,\n",
    "                                 padding='post', truncating='post')  # pad/truncate to fixed length"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "bb7a6674-014b-4794-b379-1dcd86fa4372",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 7. Split into Training and Testing Sets\n",
    "X_train, X_test, y_train, y_test = train_test_split(padded_sequences, y, test_size=0.2, random_state=42)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "b17621cf-a2de-4547-ba38-abd75b0ac971",
   "metadata": {},
   "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: \"sequential\"</span>\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[1mModel: \"sequential\"\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",
       "│ global_average_pooling1d        │ ?                      │             <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │\n",
       "│ (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">GlobalAveragePooling1D</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",
       "│ 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",
       "│ global_average_pooling1d        │ ?                      │             \u001b[38;5;34m0\u001b[0m │\n",
       "│ (\u001b[38;5;33mGlobalAveragePooling1D\u001b[0m)        │                        │               │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ dense (\u001b[38;5;33mDense\u001b[0m)                   │ ?                      │   \u001b[38;5;34m0\u001b[0m (unbuilt) │\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": [
    "# 8. Build the Neural Network Model\n",
    "model = Sequential()\n",
    "model.add(Embedding(vocab_size, 16))        # maps each word index to a 16-dim vector\n",
    "model.add(GlobalAveragePooling1D())          # averages all word vectors into one vector\n",
    "model.add(Dense(24, activation='relu'))      # hidden layer: 24 neurons\n",
    "model.add(Dense(1, activation='sigmoid'))    # output: probability between 0 and 1 (binary)\n",
    "\n",
    "model.summary()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "66306231-6f10-4f8f-a7b9-eaee2755d0e2",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 9. Compile the Model\n",
    "# binary_crossentropy: standard loss for binary classification; sigmoid output\n",
    "model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "18ddd713-c2fc-4514-82ee-adc9efd5586d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/10\n",
      "\u001b[1m1000/1000\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m4s\u001b[0m 3ms/step - accuracy: 0.9491 - loss: 0.1434 - val_accuracy: 0.8649 - val_loss: 0.3963\n",
      "Epoch 2/10\n",
      "\u001b[1m1000/1000\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 3ms/step - accuracy: 0.9538 - loss: 0.1357 - val_accuracy: 0.8525 - val_loss: 0.4348\n",
      "Epoch 3/10\n",
      "\u001b[1m1000/1000\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 3ms/step - accuracy: 0.9557 - loss: 0.1311 - val_accuracy: 0.8566 - val_loss: 0.4351\n",
      "Epoch 4/10\n",
      "\u001b[1m1000/1000\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 3ms/step - accuracy: 0.9588 - loss: 0.1232 - val_accuracy: 0.8304 - val_loss: 0.4906\n",
      "Epoch 5/10\n",
      "\u001b[1m1000/1000\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 3ms/step - accuracy: 0.9587 - loss: 0.1214 - val_accuracy: 0.8580 - val_loss: 0.4798\n",
      "Epoch 6/10\n",
      "\u001b[1m1000/1000\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 3ms/step - accuracy: 0.9625 - loss: 0.1131 - val_accuracy: 0.8553 - val_loss: 0.5034\n",
      "Epoch 7/10\n",
      "\u001b[1m1000/1000\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 3ms/step - accuracy: 0.9643 - loss: 0.1104 - val_accuracy: 0.8559 - val_loss: 0.5165\n",
      "Epoch 8/10\n",
      "\u001b[1m1000/1000\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 3ms/step - accuracy: 0.9676 - loss: 0.1022 - val_accuracy: 0.8465 - val_loss: 0.5404\n",
      "Epoch 9/10\n",
      "\u001b[1m1000/1000\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 3ms/step - accuracy: 0.9701 - loss: 0.0982 - val_accuracy: 0.8549 - val_loss: 0.5504\n",
      "Epoch 10/10\n",
      "\u001b[1m1000/1000\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 3ms/step - accuracy: 0.9699 - loss: 0.0954 - val_accuracy: 0.8445 - val_loss: 0.6037\n"
     ]
    }
   ],
   "source": [
    "# 10. Train the Model\n",
    "history = model.fit(X_train, y_train, epochs=10, batch_size=32, validation_split=0.2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "9bd99de0-c460-4da1-8e15-62f20ec22c5c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[1m313/313\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 1ms/step - accuracy: 0.8494 - loss: 0.5875\n",
      "Test Loss: 0.5875\n",
      "Test Accuracy: 84.94%\n"
     ]
    }
   ],
   "source": [
    "# 11. Evaluate the Model on Test Data\n",
    "loss, accuracy = model.evaluate(X_test, y_test)\n",
    "print(f\"Test Loss: {loss:.4f}\")\n",
    "print(f\"Test Accuracy: {accuracy*100:.2f}%\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "f34119f9-0b0c-4c92-8777-f170ceb3aa77",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 41588 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 32668 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 12. Plot Training vs Validation Accuracy\n",
    "plt.plot(history.history['accuracy'], label='Training Accuracy')\n",
    "plt.plot(history.history['val_accuracy'], label='Validation Accuracy')\n",
    "plt.title('Model Accuracy Over Epochs')\n",
    "plt.ylabel('Accuracy')\n",
    "plt.xlabel('Epoch')\n",
    "plt.legend()\n",
    "plt.grid(True)\n",
    "plt.show()\n",
    "\n",
    "# 13. Plot Training vs Validation Loss\n",
    "plt.plot(history.history['loss'], label='Training Loss')\n",
    "plt.plot(history.history['val_loss'], label='Validation Loss')\n",
    "plt.title('Model Loss Over Epochs')\n",
    "plt.ylabel('Loss')\n",
    "plt.xlabel('Epoch')\n",
    "plt.legend()\n",
    "plt.grid(True)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "353c4724-fc92-4a86-8d88-dc9f4f95cd47",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[1m313/313\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 1ms/step\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 30128 characters]",
      "text/plain": [
       "<Figure size 640x480 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Classification Report:\n",
      "               precision    recall  f1-score   support\n",
      "\n",
      "    Negative       0.84      0.86      0.85      4961\n",
      "    Positive       0.86      0.84      0.85      5039\n",
      "\n",
      "    accuracy                           0.85     10000\n",
      "   macro avg       0.85      0.85      0.85     10000\n",
      "weighted avg       0.85      0.85      0.85     10000\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 14. Confusion Matrix and Classification Report\n",
    "y_pred = (model.predict(X_test) > 0.5).astype(int)  # threshold 0.5: prob > 0.5 = positive\n",
    "\n",
    "cm = confusion_matrix(y_test, y_pred)\n",
    "sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',\n",
    "            xticklabels=['Negative', 'Positive'],\n",
    "            yticklabels=['Negative', 'Positive'])\n",
    "plt.title('Confusion Matrix')\n",
    "plt.ylabel('Actual')\n",
    "plt.xlabel('Predicted')\n",
    "plt.show()\n",
    "\n",
    "print(\"\\nClassification Report:\\n\", classification_report(y_test, y_pred, target_names=['Negative', 'Positive']))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3a09416f-2a29-4769-9b8e-bbb6d6f29e67",
   "metadata": {},
   "source": [
    "---"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
