diff --git a/.ipynb_checkpoints/lab-hyper-tuning-checkpoint.ipynb b/.ipynb_checkpoints/lab-hyper-tuning-checkpoint.ipynb
new file mode 100644
index 0000000..5b4a1c0
--- /dev/null
+++ b/.ipynb_checkpoints/lab-hyper-tuning-checkpoint.ipynb
@@ -0,0 +1,2327 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# LAB | Hyperparameter Tuning"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Load the data**\n",
+ "\n",
+ "Finally step in order to maximize the performance on your Spaceship Titanic model.\n",
+ "\n",
+ "The data can be found here:\n",
+ "\n",
+ "https://raw.githubusercontent.com/data-bootcamp-v4/data/main/spaceship_titanic.csv\n",
+ "\n",
+ "Metadata\n",
+ "\n",
+ "https://github.com/data-bootcamp-v4/data/blob/main/spaceship_titanic.md"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "So far we've been training and evaluating models with default values for hyperparameters.\n",
+ "\n",
+ "Today we will perform the same feature engineering as before, and then compare the best working models you got so far, but now fine tuning it's hyperparameters."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import pandas as pd\n",
+ "import numpy as np\n",
+ "\n",
+ "from sklearn.model_selection import train_test_split\n",
+ "from sklearn.preprocessing import StandardScaler\n",
+ "from sklearn.feature_selection import SelectKBest, f_classif\n",
+ "from sklearn.linear_model import LogisticRegression\n",
+ "from sklearn.metrics import accuracy_score\n",
+ "from sklearn.model_selection import GridSearchCV"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " PassengerId \n",
+ " HomePlanet \n",
+ " CryoSleep \n",
+ " Cabin \n",
+ " Destination \n",
+ " Age \n",
+ " VIP \n",
+ " RoomService \n",
+ " FoodCourt \n",
+ " ShoppingMall \n",
+ " Spa \n",
+ " VRDeck \n",
+ " Name \n",
+ " Transported \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 0001_01 \n",
+ " Europa \n",
+ " False \n",
+ " B/0/P \n",
+ " TRAPPIST-1e \n",
+ " 39.0 \n",
+ " False \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " Maham Ofracculy \n",
+ " False \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " 0002_01 \n",
+ " Earth \n",
+ " False \n",
+ " F/0/S \n",
+ " TRAPPIST-1e \n",
+ " 24.0 \n",
+ " False \n",
+ " 109.0 \n",
+ " 9.0 \n",
+ " 25.0 \n",
+ " 549.0 \n",
+ " 44.0 \n",
+ " Juanna Vines \n",
+ " True \n",
+ " \n",
+ " \n",
+ " 2 \n",
+ " 0003_01 \n",
+ " Europa \n",
+ " False \n",
+ " A/0/S \n",
+ " TRAPPIST-1e \n",
+ " 58.0 \n",
+ " True \n",
+ " 43.0 \n",
+ " 3576.0 \n",
+ " 0.0 \n",
+ " 6715.0 \n",
+ " 49.0 \n",
+ " Altark Susent \n",
+ " False \n",
+ " \n",
+ " \n",
+ " 3 \n",
+ " 0003_02 \n",
+ " Europa \n",
+ " False \n",
+ " A/0/S \n",
+ " TRAPPIST-1e \n",
+ " 33.0 \n",
+ " False \n",
+ " 0.0 \n",
+ " 1283.0 \n",
+ " 371.0 \n",
+ " 3329.0 \n",
+ " 193.0 \n",
+ " Solam Susent \n",
+ " False \n",
+ " \n",
+ " \n",
+ " 4 \n",
+ " 0004_01 \n",
+ " Earth \n",
+ " False \n",
+ " F/1/S \n",
+ " TRAPPIST-1e \n",
+ " 16.0 \n",
+ " False \n",
+ " 303.0 \n",
+ " 70.0 \n",
+ " 151.0 \n",
+ " 565.0 \n",
+ " 2.0 \n",
+ " Willy Santantines \n",
+ " True \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " PassengerId HomePlanet CryoSleep Cabin Destination Age VIP \\\n",
+ "0 0001_01 Europa False B/0/P TRAPPIST-1e 39.0 False \n",
+ "1 0002_01 Earth False F/0/S TRAPPIST-1e 24.0 False \n",
+ "2 0003_01 Europa False A/0/S TRAPPIST-1e 58.0 True \n",
+ "3 0003_02 Europa False A/0/S TRAPPIST-1e 33.0 False \n",
+ "4 0004_01 Earth False F/1/S TRAPPIST-1e 16.0 False \n",
+ "\n",
+ " RoomService FoodCourt ShoppingMall Spa VRDeck Name \\\n",
+ "0 0.0 0.0 0.0 0.0 0.0 Maham Ofracculy \n",
+ "1 109.0 9.0 25.0 549.0 44.0 Juanna Vines \n",
+ "2 43.0 3576.0 0.0 6715.0 49.0 Altark Susent \n",
+ "3 0.0 1283.0 371.0 3329.0 193.0 Solam Susent \n",
+ "4 303.0 70.0 151.0 565.0 2.0 Willy Santantines \n",
+ "\n",
+ " Transported \n",
+ "0 False \n",
+ "1 True \n",
+ "2 False \n",
+ "3 False \n",
+ "4 True "
+ ]
+ },
+ "execution_count": 13,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spaceship = pd.read_csv(\"https://raw.githubusercontent.com/data-bootcamp-v4/data/main/spaceship_titanic.csv\")\n",
+ "df = pd.read_csv(\"https://raw.githubusercontent.com/data-bootcamp-v4/data/main/spaceship_titanic.csv\")\n",
+ "spaceship.head()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "RangeIndex: 8693 entries, 0 to 8692\n",
+ "Data columns (total 14 columns):\n",
+ " # Column Non-Null Count Dtype \n",
+ "--- ------ -------------- ----- \n",
+ " 0 PassengerId 8693 non-null str \n",
+ " 1 HomePlanet 8492 non-null str \n",
+ " 2 CryoSleep 8476 non-null object \n",
+ " 3 Cabin 8494 non-null str \n",
+ " 4 Destination 8511 non-null str \n",
+ " 5 Age 8514 non-null float64\n",
+ " 6 VIP 8490 non-null object \n",
+ " 7 RoomService 8512 non-null float64\n",
+ " 8 FoodCourt 8510 non-null float64\n",
+ " 9 ShoppingMall 8485 non-null float64\n",
+ " 10 Spa 8510 non-null float64\n",
+ " 11 VRDeck 8505 non-null float64\n",
+ " 12 Name 8493 non-null str \n",
+ " 13 Transported 8693 non-null bool \n",
+ "dtypes: bool(1), float64(6), object(2), str(5)\n",
+ "memory usage: 891.5+ KB\n"
+ ]
+ }
+ ],
+ "source": [
+ "df.info()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "PassengerId 0\n",
+ "HomePlanet 201\n",
+ "CryoSleep 217\n",
+ "Cabin 199\n",
+ "Destination 182\n",
+ "Age 179\n",
+ "VIP 203\n",
+ "RoomService 181\n",
+ "FoodCourt 183\n",
+ "ShoppingMall 208\n",
+ "Spa 183\n",
+ "VRDeck 188\n",
+ "Name 200\n",
+ "Transported 0\n",
+ "dtype: int64"
+ ]
+ },
+ "execution_count": 15,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "df.isnull().sum()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " HomePlanet \n",
+ " CryoSleep \n",
+ " Destination \n",
+ " Age \n",
+ " VIP \n",
+ " RoomService \n",
+ " FoodCourt \n",
+ " ShoppingMall \n",
+ " Spa \n",
+ " VRDeck \n",
+ " Transported \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " Europa \n",
+ " False \n",
+ " TRAPPIST-1e \n",
+ " 39.0 \n",
+ " False \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " False \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " Earth \n",
+ " False \n",
+ " TRAPPIST-1e \n",
+ " 24.0 \n",
+ " False \n",
+ " 109.0 \n",
+ " 9.0 \n",
+ " 25.0 \n",
+ " 549.0 \n",
+ " 44.0 \n",
+ " True \n",
+ " \n",
+ " \n",
+ " 2 \n",
+ " Europa \n",
+ " False \n",
+ " TRAPPIST-1e \n",
+ " 58.0 \n",
+ " True \n",
+ " 43.0 \n",
+ " 3576.0 \n",
+ " 0.0 \n",
+ " 6715.0 \n",
+ " 49.0 \n",
+ " False \n",
+ " \n",
+ " \n",
+ " 3 \n",
+ " Europa \n",
+ " False \n",
+ " TRAPPIST-1e \n",
+ " 33.0 \n",
+ " False \n",
+ " 0.0 \n",
+ " 1283.0 \n",
+ " 371.0 \n",
+ " 3329.0 \n",
+ " 193.0 \n",
+ " False \n",
+ " \n",
+ " \n",
+ " 4 \n",
+ " Earth \n",
+ " False \n",
+ " TRAPPIST-1e \n",
+ " 16.0 \n",
+ " False \n",
+ " 303.0 \n",
+ " 70.0 \n",
+ " 151.0 \n",
+ " 565.0 \n",
+ " 2.0 \n",
+ " True \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " HomePlanet CryoSleep Destination Age VIP RoomService FoodCourt \\\n",
+ "0 Europa False TRAPPIST-1e 39.0 False 0.0 0.0 \n",
+ "1 Earth False TRAPPIST-1e 24.0 False 109.0 9.0 \n",
+ "2 Europa False TRAPPIST-1e 58.0 True 43.0 3576.0 \n",
+ "3 Europa False TRAPPIST-1e 33.0 False 0.0 1283.0 \n",
+ "4 Earth False TRAPPIST-1e 16.0 False 303.0 70.0 \n",
+ "\n",
+ " ShoppingMall Spa VRDeck Transported \n",
+ "0 0.0 0.0 0.0 False \n",
+ "1 25.0 549.0 44.0 True \n",
+ "2 0.0 6715.0 49.0 False \n",
+ "3 371.0 3329.0 193.0 False \n",
+ "4 151.0 565.0 2.0 True "
+ ]
+ },
+ "execution_count": 16,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "df = df.drop(\n",
+ " columns=[\n",
+ " \"PassengerId\",\n",
+ " \"Cabin\",\n",
+ " \"Name\"\n",
+ " ]\n",
+ ")\n",
+ "\n",
+ "df.head()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "HomePlanet 0\n",
+ "CryoSleep 0\n",
+ "Destination 0\n",
+ "Age 0\n",
+ "VIP 0\n",
+ "RoomService 0\n",
+ "FoodCourt 0\n",
+ "ShoppingMall 0\n",
+ "Spa 0\n",
+ "VRDeck 0\n",
+ "Transported 0\n",
+ "dtype: int64"
+ ]
+ },
+ "execution_count": 17,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# Define numerical and categorical columns\n",
+ "numerical_columns = [\n",
+ " \"Age\",\n",
+ " \"RoomService\",\n",
+ " \"FoodCourt\",\n",
+ " \"ShoppingMall\",\n",
+ " \"Spa\",\n",
+ " \"VRDeck\"\n",
+ "]\n",
+ "\n",
+ "categorical_columns = [\n",
+ " \"HomePlanet\",\n",
+ " \"CryoSleep\",\n",
+ " \"Destination\",\n",
+ " \"VIP\"\n",
+ "]\n",
+ "\n",
+ "# Fill missing numerical values with the median\n",
+ "for column in numerical_columns:\n",
+ " df[column] = df[column].fillna(df[column].median())\n",
+ "\n",
+ "# Fill missing categorical values with the mode\n",
+ "for column in categorical_columns:\n",
+ " df[column] = df[column].fillna(df[column].mode()[0])\n",
+ "\n",
+ "# Verify missing values\n",
+ "df.isnull().sum()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "X shape: (8693, 10)\n",
+ "y shape: (8693,)\n"
+ ]
+ }
+ ],
+ "source": [
+ "X = df.drop(columns=[\"Transported\"])\n",
+ "y = df[\"Transported\"]\n",
+ "\n",
+ "print(\"X shape:\", X.shape)\n",
+ "print(\"y shape:\", y.shape)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "X shape after encoding: (8693, 12)\n",
+ "\n",
+ "Columns:\n",
+ "['Age', 'RoomService', 'FoodCourt', 'ShoppingMall', 'Spa', 'VRDeck', 'HomePlanet_Europa', 'HomePlanet_Mars', 'CryoSleep_True', 'Destination_PSO J318.5-22', 'Destination_TRAPPIST-1e', 'VIP_True']\n"
+ ]
+ }
+ ],
+ "source": [
+ "X = pd.get_dummies(\n",
+ " X,\n",
+ " columns=[\n",
+ " \"HomePlanet\",\n",
+ " \"CryoSleep\",\n",
+ " \"Destination\",\n",
+ " \"VIP\"\n",
+ " ],\n",
+ " drop_first=True\n",
+ ")\n",
+ "\n",
+ "print(\"X shape after encoding:\", X.shape)\n",
+ "print(\"\\nColumns:\")\n",
+ "print(X.columns.tolist())"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Training set: (6954, 12)\n",
+ "Test set: (1739, 12)\n"
+ ]
+ }
+ ],
+ "source": [
+ "X_train, X_test, y_train, y_test = train_test_split(\n",
+ " X,\n",
+ " y,\n",
+ " test_size=0.20,\n",
+ " random_state=42,\n",
+ " stratify=y\n",
+ ")\n",
+ "\n",
+ "print(\"Training set:\", X_train.shape)\n",
+ "print(\"Test set:\", X_test.shape)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Now perform the same as before:\n",
+ "- Feature Scaling\n",
+ "- Feature Selection\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Feature Scaling"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " Age \n",
+ " RoomService \n",
+ " FoodCourt \n",
+ " ShoppingMall \n",
+ " Spa \n",
+ " VRDeck \n",
+ " HomePlanet_Europa \n",
+ " HomePlanet_Mars \n",
+ " CryoSleep_True \n",
+ " Destination_PSO J318.5-22 \n",
+ " Destination_TRAPPIST-1e \n",
+ " VIP_True \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 3600 \n",
+ " -1.996149 \n",
+ " -0.33634 \n",
+ " -0.279076 \n",
+ " -0.305732 \n",
+ " -0.267311 \n",
+ " -0.264632 \n",
+ " False \n",
+ " False \n",
+ " False \n",
+ " False \n",
+ " True \n",
+ " False \n",
+ " \n",
+ " \n",
+ " 1262 \n",
+ " -0.811703 \n",
+ " -0.33634 \n",
+ " -0.279076 \n",
+ " -0.305732 \n",
+ " -0.267311 \n",
+ " -0.264632 \n",
+ " False \n",
+ " False \n",
+ " True \n",
+ " False \n",
+ " True \n",
+ " False \n",
+ " \n",
+ " \n",
+ " 8612 \n",
+ " 0.442416 \n",
+ " -0.33634 \n",
+ " -0.279076 \n",
+ " -0.305732 \n",
+ " -0.267311 \n",
+ " -0.264632 \n",
+ " False \n",
+ " False \n",
+ " False \n",
+ " True \n",
+ " False \n",
+ " False \n",
+ " \n",
+ " \n",
+ " 5075 \n",
+ " -0.184643 \n",
+ " -0.33634 \n",
+ " -0.279076 \n",
+ " -0.305732 \n",
+ " -0.267311 \n",
+ " -0.264632 \n",
+ " True \n",
+ " False \n",
+ " True \n",
+ " False \n",
+ " False \n",
+ " False \n",
+ " \n",
+ " \n",
+ " 4758 \n",
+ " -1.090396 \n",
+ " -0.33634 \n",
+ " -0.279076 \n",
+ " -0.195161 \n",
+ " -0.266427 \n",
+ " 4.423937 \n",
+ " False \n",
+ " False \n",
+ " False \n",
+ " False \n",
+ " True \n",
+ " False \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " Age RoomService FoodCourt ShoppingMall Spa VRDeck \\\n",
+ "3600 -1.996149 -0.33634 -0.279076 -0.305732 -0.267311 -0.264632 \n",
+ "1262 -0.811703 -0.33634 -0.279076 -0.305732 -0.267311 -0.264632 \n",
+ "8612 0.442416 -0.33634 -0.279076 -0.305732 -0.267311 -0.264632 \n",
+ "5075 -0.184643 -0.33634 -0.279076 -0.305732 -0.267311 -0.264632 \n",
+ "4758 -1.090396 -0.33634 -0.279076 -0.195161 -0.266427 4.423937 \n",
+ "\n",
+ " HomePlanet_Europa HomePlanet_Mars CryoSleep_True \\\n",
+ "3600 False False False \n",
+ "1262 False False True \n",
+ "8612 False False False \n",
+ "5075 True False True \n",
+ "4758 False False False \n",
+ "\n",
+ " Destination_PSO J318.5-22 Destination_TRAPPIST-1e VIP_True \n",
+ "3600 False True False \n",
+ "1262 False True False \n",
+ "8612 True False False \n",
+ "5075 False False False \n",
+ "4758 False True False "
+ ]
+ },
+ "execution_count": 21,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "scaler = StandardScaler()\n",
+ "\n",
+ "X_train_scaled = X_train.copy()\n",
+ "X_test_scaled = X_test.copy()\n",
+ "\n",
+ "X_train_scaled[numerical_columns] = scaler.fit_transform(\n",
+ " X_train[numerical_columns]\n",
+ ")\n",
+ "\n",
+ "X_test_scaled[numerical_columns] = scaler.transform(\n",
+ " X_test[numerical_columns]\n",
+ ")\n",
+ "\n",
+ "X_train_scaled.head()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Feature Selection"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Selected features:\n",
+ "['Age', 'RoomService', 'FoodCourt', 'Spa', 'VRDeck', 'HomePlanet_Europa', 'CryoSleep_True', 'Destination_TRAPPIST-1e']\n",
+ "\n",
+ "Training shape: (6954, 8)\n",
+ "Test shape: (1739, 8)\n"
+ ]
+ }
+ ],
+ "source": [
+ "selector = SelectKBest(\n",
+ " score_func=f_classif,\n",
+ " k=8\n",
+ ")\n",
+ "\n",
+ "X_train_selected = selector.fit_transform(\n",
+ " X_train_scaled,\n",
+ " y_train\n",
+ ")\n",
+ "\n",
+ "X_test_selected = selector.transform(\n",
+ " X_test_scaled\n",
+ ")\n",
+ "\n",
+ "selected_features = X_train_scaled.columns[\n",
+ " selector.get_support()\n",
+ "]\n",
+ "\n",
+ "print(\"Selected features:\")\n",
+ "print(selected_features.tolist())\n",
+ "\n",
+ "print(\"\\nTraining shape:\", X_train_selected.shape)\n",
+ "print(\"Test shape:\", X_test_selected.shape)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "- Now let's use the best model we got so far in order to see how it can improve when we fine tune it's hyperparameters."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "LogisticRegression(max_iter=1000, random_state=42) In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org. \n",
+ "
\n",
+ "
\n",
+ " Parameters \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " random_state\n",
+ " \n",
+ " random_state: int, RandomState instance, default=None Used when ``solver`` == 'sag', 'saga' or 'liblinear' to shuffle the data. See :term:`Glossary <random_state>` for details. \n",
+ " \n",
+ " \n",
+ " 42 \n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " max_iter\n",
+ " \n",
+ " max_iter: int, default=100 Maximum number of iterations taken for the solvers to converge. \n",
+ " \n",
+ " \n",
+ " 1000 \n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " penalty\n",
+ " \n",
+ " penalty: {'l1', 'l2', 'elasticnet', None}, default='l2' Specify the norm of the penalty: - `None`: no penalty is added; - `'l2'`: add an L2 penalty term and it is the default choice; - `'l1'`: add an L1 penalty term; - `'elasticnet'`: both L1 and L2 penalty terms are added. .. warning:: Some penalties may not work with some solvers. See the parameter `solver` below, to know the compatibility between the penalty and solver. .. versionadded:: 0.19 l1 penalty with SAGA solver (allowing 'multinomial' + L1) .. deprecated:: 1.8 `penalty` was deprecated in version 1.8 and will be removed in 1.10. Use `l1_ratio` and `C` instead. `l1_ratio=0` for `penalty='l2'`, `l1_ratio=1` for `penalty='l1'`, `l1_ratio` set to any float between 0 and 1 for `penalty='elasticnet'`, and `C=np.inf` for `penalty=None`. \n",
+ " \n",
+ " \n",
+ " 'deprecated' \n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " C\n",
+ " \n",
+ " C: float, default=1.0 Inverse of regularization strength; must be a positive float. Like in support vector machines, smaller values specify stronger regularization. `C=np.inf` results in unpenalized logistic regression. For a visual example on the effect of tuning the `C` parameter with an L1 penalty, see: :ref:`sphx_glr_auto_examples_linear_model_plot_logistic_path.py`. \n",
+ " \n",
+ " \n",
+ " 1.0 \n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " l1_ratio\n",
+ " \n",
+ " l1_ratio: float, default=0.0 The Elastic-Net mixing parameter, with `0 <= l1_ratio <= 1`. Setting `l1_ratio=1` gives a pure L1-penalty, setting `l1_ratio=0` a pure L2-penalty. Any value between 0 and 1 gives an Elastic-Net penalty of the form `l1_ratio * L1 + (1 - l1_ratio) * L2`. .. warning:: Certain values of `l1_ratio`, i.e. some penalties, may not work with some solvers. See the parameter `solver` below, to know the compatibility between the penalty and solver. .. versionchanged:: 1.8 Default value changed from None to 0.0. .. deprecated:: 1.8 `None` is deprecated and will be removed in version 1.10. Always use `l1_ratio` to specify the penalty type. \n",
+ " \n",
+ " \n",
+ " 0.0 \n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " dual\n",
+ " \n",
+ " dual: bool, default=False Dual (constrained) or primal (regularized, see also :ref:`this equation <regularized-logistic-loss>`) formulation. Dual formulation is only implemented for l2 penalty with liblinear solver. Prefer `dual=False` when n_samples > n_features. \n",
+ " \n",
+ " \n",
+ " False \n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " tol\n",
+ " \n",
+ " tol: float, default=1e-4 Tolerance for stopping criteria. \n",
+ " \n",
+ " \n",
+ " 0.0001 \n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " fit_intercept\n",
+ " \n",
+ " fit_intercept: bool, default=True Specifies if a constant (a.k.a. bias or intercept) should be added to the decision function. \n",
+ " \n",
+ " \n",
+ " True \n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " intercept_scaling\n",
+ " \n",
+ " intercept_scaling: float, default=1 Useful only when the solver `liblinear` is used and `self.fit_intercept` is set to `True`. In this case, `x` becomes `[x, self.intercept_scaling]`, i.e. a "synthetic" feature with constant value equal to `intercept_scaling` is appended to the instance vector. The intercept becomes ``intercept_scaling * synthetic_feature_weight``. .. note:: The synthetic feature weight is subject to L1 or L2 regularization as all other features. To lessen the effect of regularization on synthetic feature weight (and therefore on the intercept) `intercept_scaling` has to be increased. \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " class_weight\n",
+ " \n",
+ " class_weight: dict or 'balanced', default=None Weights associated with classes in the form ``{class_label: weight}``. If not given, all classes are supposed to have weight one. The "balanced" mode uses the values of y to automatically adjust weights inversely proportional to class frequencies in the input data as ``n_samples / (n_classes * np.bincount(y))``. Note that these weights will be multiplied with sample_weight (passed through the fit method) if sample_weight is specified. .. versionadded:: 0.17 *class_weight='balanced'* \n",
+ " \n",
+ " \n",
+ " None \n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " solver\n",
+ " \n",
+ " solver: {'lbfgs', 'liblinear', 'newton-cg', 'newton-cholesky', 'sag', 'saga'}, default='lbfgs' Algorithm to use in the optimization problem. Default is 'lbfgs'. To choose a solver, you might want to consider the following aspects: - 'lbfgs' is a good default solver because it works reasonably well for a wide class of problems. - For :term:`multiclass` problems (`n_classes >= 3`), all solvers except 'liblinear' minimize the full multinomial loss, 'liblinear' will raise an error. - 'newton-cholesky' is a good choice for `n_samples` >> `n_features * n_classes`, especially with one-hot encoded categorical features with rare categories. Be aware that the memory usage of this solver has a quadratic dependency on `n_features * n_classes` because it explicitly computes the full Hessian matrix. - For small datasets, 'liblinear' is a good choice, whereas 'sag' and 'saga' are faster for large ones; - 'liblinear' can only handle binary classification by default. To apply a one-versus-rest scheme for the multiclass setting one can wrap it with the :class:`~sklearn.multiclass.OneVsRestClassifier`. .. warning:: The choice of the algorithm depends on the penalty chosen (`l1_ratio=0` for L2-penalty, `l1_ratio=1` for L1-penalty and `0 < l1_ratio < 1` for Elastic-Net) and on (multinomial) multiclass support: ================= ======================== ====================== solver l1_ratio multinomial multiclass ================= ======================== ====================== 'lbfgs' l1_ratio=0 yes 'liblinear' l1_ratio=1 or l1_ratio=0 no 'newton-cg' l1_ratio=0 yes 'newton-cholesky' l1_ratio=0 yes 'sag' l1_ratio=0 yes 'saga' 0<=l1_ratio<=1 yes ================= ======================== ====================== .. note:: 'sag' and 'saga' fast convergence is only guaranteed on features with approximately the same scale. You can preprocess the data with a scaler from :mod:`sklearn.preprocessing`. .. seealso:: Refer to the :ref:`User Guide <Logistic_regression>` for more information regarding :class:`LogisticRegression` and more specifically the :ref:`Table <logistic_regression_solvers>` summarizing solver/penalty supports. .. versionadded:: 0.17 Stochastic Average Gradient (SAG) descent solver. Multinomial support in version 0.18. .. versionadded:: 0.19 SAGA solver. .. versionchanged:: 0.22 The default solver changed from 'liblinear' to 'lbfgs' in 0.22. .. versionadded:: 1.2 newton-cholesky solver. Multinomial support in version 1.6. \n",
+ " \n",
+ " \n",
+ " 'lbfgs' \n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " verbose\n",
+ " \n",
+ " verbose: int, default=0 For the liblinear and lbfgs solvers set verbose to any positive number for verbosity. \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " warm_start\n",
+ " \n",
+ " warm_start: bool, default=False When set to True, reuse the solution of the previous call to fit as initialization, otherwise, just erase the previous solution. Useless for liblinear solver. See :term:`the Glossary <warm_start>`. .. versionadded:: 0.17 *warm_start* to support *lbfgs*, *newton-cg*, *sag*, *saga* solvers. \n",
+ " \n",
+ " \n",
+ " False \n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " n_jobs\n",
+ " \n",
+ " n_jobs: int, default=None Does not have any effect. .. deprecated:: 1.8 `n_jobs` is deprecated in version 1.8 and will be removed in 1.10. \n",
+ " \n",
+ " \n",
+ " None \n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ " \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
\n",
+ " Fitted attributes \n",
+ " \n",
+ " \n",
+ " \n",
+ " Name \n",
+ " Type \n",
+ " Value \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " classes_\n",
+ " \n",
+ " classes_: ndarray of shape (n_classes, ) A list of class labels known to the classifier. \n",
+ " \n",
+ " \n",
+ " ndarray[bool](2,) \n",
+ " [False, True] \n",
+ "\n",
+ "\n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " coef_\n",
+ " \n",
+ " coef_: ndarray or CSR matrix of shape (1, n_features) or (n_classes, n_features) Coefficients of the features in the decision function. `coef_` is of shape (1, n_features) when the given problem is binary. By default, it will be created as a dense array, but can be turned to sparse (CSR format) through :meth:`sparsify` (which can be beneficial under L1 regularization when many coefficients are zero), and back to dense through :meth:`densify`. \n",
+ " \n",
+ " \n",
+ " ndarray[float64](1, 8) \n",
+ " [[-0.09,-0.84, 0.74,..., 2.01, 1.19,-0.13]] \n",
+ "\n",
+ "\n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " intercept_\n",
+ " \n",
+ " intercept_: ndarray of shape (1,) or (n_classes,) Intercept (a.k.a. bias) added to the decision function. If `fit_intercept` is set to False, the intercept is set to zero. `intercept_` is of shape (1,) when the given problem is binary. \n",
+ " \n",
+ " \n",
+ " ndarray[float64](1,) \n",
+ " [-1.15] \n",
+ "\n",
+ "\n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " n_features_in_\n",
+ " \n",
+ " n_features_in_: int Number of features seen during :term:`fit`. .. versionadded:: 0.24 \n",
+ " \n",
+ " \n",
+ " int \n",
+ " 8 \n",
+ "\n",
+ "\n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " n_iter_\n",
+ " \n",
+ " n_iter_: ndarray of shape (1, ) Actual number of iterations for all classes. .. versionchanged:: 0.20 In SciPy <= 1.0.0 the number of lbfgs iterations may exceed ``max_iter``. ``n_iter_`` will now report at most ``max_iter``. \n",
+ " \n",
+ " \n",
+ " ndarray[int32](1,) \n",
+ " [12] \n",
+ "\n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ "LogisticRegression(max_iter=1000, random_state=42)"
+ ]
+ },
+ "execution_count": 24,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "model = LogisticRegression(\n",
+ " max_iter=1000,\n",
+ " random_state=42\n",
+ ")\n",
+ "\n",
+ "model.fit(\n",
+ " X_train_selected,\n",
+ " y_train\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "- Evaluate your model"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 25,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Baseline Accuracy: 0.7838\n"
+ ]
+ }
+ ],
+ "source": [
+ "y_pred = model.predict(\n",
+ " X_test_selected\n",
+ ")\n",
+ "\n",
+ "baseline_accuracy = accuracy_score(\n",
+ " y_test,\n",
+ " y_pred\n",
+ ")\n",
+ "\n",
+ "print(\n",
+ " \"Baseline Accuracy:\",\n",
+ " round(baseline_accuracy, 4)\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Grid/Random Search**"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "For this lab we will use Grid Search."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "- Define hyperparameters to fine tune."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 29,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'C': [0.01, 0.1, 1, 10, 100], 'solver': ['liblinear', 'lbfgs']}"
+ ]
+ },
+ "execution_count": 29,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "param_grid = {\n",
+ " \"C\": [0.01, 0.1, 1, 10, 100],\n",
+ " \"solver\": [\"liblinear\", \"lbfgs\"]\n",
+ "}\n",
+ "\n",
+ "param_grid"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "- Run Grid Search"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 28,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Best parameters: {'C': 100, 'solver': 'liblinear'}\n",
+ "Best CV accuracy: 0.786\n"
+ ]
+ }
+ ],
+ "source": [
+ "grid_search = GridSearchCV(\n",
+ " estimator=LogisticRegression(\n",
+ " max_iter=1000,\n",
+ " random_state=42\n",
+ " ),\n",
+ " param_grid=param_grid,\n",
+ " cv=5,\n",
+ " scoring=\"accuracy\",\n",
+ " n_jobs=-1\n",
+ ")\n",
+ "\n",
+ "grid_search.fit(\n",
+ " X_train_selected,\n",
+ " y_train\n",
+ ")\n",
+ "\n",
+ "print(\"Best parameters:\", grid_search.best_params_)\n",
+ "print(\"Best CV accuracy:\", round(grid_search.best_score_, 4))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "- Evaluate your model"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 30,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Baseline Accuracy: 0.7838\n",
+ "Tuned Accuracy: 0.7844\n"
+ ]
+ }
+ ],
+ "source": [
+ "best_model = grid_search.best_estimator_\n",
+ "\n",
+ "y_pred_tuned = best_model.predict(\n",
+ " X_test_selected\n",
+ ")\n",
+ "\n",
+ "tuned_accuracy = accuracy_score(\n",
+ " y_test,\n",
+ " y_pred_tuned\n",
+ ")\n",
+ "\n",
+ "print(\n",
+ " \"Baseline Accuracy:\",\n",
+ " round(baseline_accuracy, 4)\n",
+ ")\n",
+ "\n",
+ "print(\n",
+ " \"Tuned Accuracy:\",\n",
+ " round(tuned_accuracy, 4)\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Model Evaluation\n",
+ "\n",
+ "Grid Search identified the best Logistic Regression hyperparameters as `C = 100` and `solver = 'liblinear'`.\n",
+ "\n",
+ "The baseline model achieved an accuracy of 0.7838, while the tuned model achieved an accuracy of 0.7844.\n",
+ "\n",
+ "Hyperparameter tuning therefore produced a small improvement of 0.0006, equivalent to 0.06 percentage points. This indicates that the baseline Logistic Regression model was already performing close to its optimal configuration for the selected features.\n",
+ "\n",
+ "Although the improvement is small, Grid Search provides a systematic method for selecting hyperparameters using cross validation rather than relying on manually chosen settings."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python (lab-hyperparameter-tuning)",
+ "language": "python",
+ "name": "lab-hyperparameter-tuning"
+ },
+ "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.11"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/.virtual_documents/lab-hyper-tuning.ipynb b/.virtual_documents/lab-hyper-tuning.ipynb
new file mode 100644
index 0000000..e435909
--- /dev/null
+++ b/.virtual_documents/lab-hyper-tuning.ipynb
@@ -0,0 +1,302 @@
+
+
+
+
+
+
+
+
+
+#Libraries
+import pandas as pd
+import numpy as np
+from sklearn.model_selection import train_test_split
+
+
+spaceship = pd.read_csv("https://raw.githubusercontent.com/data-bootcamp-v4/data/main/spaceship_titanic.csv")
+df = pd.read_csv("https://raw.githubusercontent.com/data-bootcamp-v4/data/main/spaceship_titanic.csv")
+spaceship.head()
+
+
+df.info()
+
+
+df.isnull().sum()
+
+
+# Remove identifier and high-cardinality text columns
+df = df.drop(columns=["PassengerId", "Cabin", "Name"])
+
+df.head()
+
+
+from sklearn.preprocessing import StandardScaler
+
+numerical_columns = [
+ "Age",
+ "RoomService",
+ "FoodCourt",
+ "ShoppingMall",
+ "Spa",
+ "VRDeck"
+]
+
+scaler = StandardScaler()
+
+X_train_scaled = X_train.copy()
+X_test_scaled = X_test.copy()
+
+X_train_scaled[numerical_columns] = scaler.fit_transform(
+ X_train[numerical_columns]
+)
+
+X_test_scaled[numerical_columns] = scaler.transform(
+ X_test[numerical_columns]
+)
+
+X_train_scaled.head()
+
+
+# Fill numerical missing values with the median
+for column in numerical_columns:
+ df[column] = df[column].fillna(df[column].median())
+
+# Fill categorical missing values with the mode
+for column in categorical_columns:
+ df[column] = df[column].fillna(df[column].mode()[0])
+
+
+df.isnull().sum()
+
+
+X = df.drop(columns=["Transported"])
+y = df["Transported"]
+
+print("X shape:", X.shape)
+print("y shape:", y.shape)
+
+
+X = pd.get_dummies(
+ X,
+ columns=["HomePlanet", "CryoSleep", "Destination", "VIP"],
+ drop_first=True
+)
+
+X.head()
+
+
+from sklearn.preprocessing import StandardScaler
+from sklearn.feature_selection import SelectKBest, f_classif
+
+# Numerical columns to scale
+numerical_columns = [
+ "Age",
+ "RoomService",
+ "FoodCourt",
+ "ShoppingMall",
+ "Spa",
+ "VRDeck"
+]
+
+# Feature Scaling
+scaler = StandardScaler()
+
+X_train_scaled = X_train.copy()
+X_test_scaled = X_test.copy()
+
+X_train_scaled[numerical_columns] = scaler.fit_transform(
+ X_train[numerical_columns]
+)
+
+X_test_scaled[numerical_columns] = scaler.transform(
+ X_test[numerical_columns]
+)
+
+# Feature Selection
+selector = SelectKBest(
+ score_func=f_classif,
+ k=8
+)
+
+X_train_selected = selector.fit_transform(
+ X_train_scaled,
+ y_train
+)
+
+X_test_selected = selector.transform(
+ X_test_scaled
+)
+
+selected_features = X_train_scaled.columns[
+ selector.get_support()
+]
+
+print("Selected features:")
+print(selected_features.tolist())
+
+print("\nTraining shape:", X_train_selected.shape)
+print("Test shape:", X_test_selected.shape)
+
+
+
+
+
+from sklearn.model_selection import train_test_split
+
+X_train, X_test, y_train, y_test = train_test_split(
+ X,
+ y,
+ test_size=0.20,
+ random_state=42,
+ stratify=y
+)
+
+print("Training set:", X_train.shape)
+print("Test set:", X_test.shape)
+
+
+from sklearn.linear_model import LogisticRegression
+from sklearn.metrics import accuracy_score
+
+log_model = LogisticRegression(
+ max_iter=1000,
+ random_state=42
+)
+
+log_model.fit(X_train_scaled, y_train)
+
+y_pred = log_model.predict(X_test_scaled)
+
+accuracy = accuracy_score(y_test, y_pred)
+
+print("Scaled Logistic Regression Accuracy:", round(accuracy, 4))
+
+
+X_train_scaled.head()
+
+
+from sklearn.feature_selection import SelectKBest, f_classif
+
+selector = SelectKBest(
+ score_func=f_classif,
+ k=8
+)
+
+X_train_selected = selector.fit_transform(
+ X_train_scaled,
+ y_train
+)
+
+X_test_selected = selector.transform(
+ X_test_scaled
+)
+
+selected_features = X_train_scaled.columns[
+ selector.get_support()
+]
+
+print("Selected features:")
+print(selected_features.tolist())
+
+print("\nTraining shape:", X_train_selected.shape)
+print("Test shape:", X_test_selected.shape)
+
+
+
+
+
+from sklearn.linear_model import LogisticRegression
+
+model = LogisticRegression(
+ max_iter=1000,
+ random_state=42
+)
+
+model.fit(X_train_selected, y_train)
+
+
+
+
+
+from sklearn.metrics import accuracy_score
+
+y_pred = model.predict(X_test_selected)
+
+accuracy = accuracy_score(y_test, y_pred)
+
+print("Baseline Accuracy:", round(accuracy, 4))
+
+
+
+
+
+
+
+
+
+
+
+param_grid = {
+ "C": [0.01, 0.1, 1, 10, 100],
+ "solver": ["liblinear", "lbfgs"]
+}
+
+param_grid
+
+
+
+
+
+from sklearn.model_selection import GridSearchCV
+
+grid_search = GridSearchCV(
+ estimator=LogisticRegression(
+ max_iter=1000,
+ random_state=42
+ ),
+ param_grid=param_grid,
+ cv=5,
+ scoring="accuracy",
+ n_jobs=-1
+)
+
+grid_search.fit(
+ X_train_selected,
+ y_train
+)
+
+print("Best parameters:", grid_search.best_params_)
+print("Best CV accuracy:", round(grid_search.best_score_, 4))
+
+
+
+
+
+best_model = grid_search.best_estimator_
+
+y_pred_tuned = best_model.predict(
+ X_test_selected
+)
+
+tuned_accuracy = accuracy_score(
+ y_test,
+ y_pred_tuned
+)
+
+print("Baseline Accuracy:", round(accuracy, 4))
+print("Tuned Accuracy:", round(tuned_accuracy, 4))
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/anaconda_projects/db/project_filebrowser.db b/anaconda_projects/db/project_filebrowser.db
new file mode 100644
index 0000000..ffdfcb3
Binary files /dev/null and b/anaconda_projects/db/project_filebrowser.db differ
diff --git a/lab-hyper-tuning.ipynb b/lab-hyper-tuning.ipynb
index 847d487..5b4a1c0 100644
--- a/lab-hyper-tuning.ipynb
+++ b/lab-hyper-tuning.ipynb
@@ -35,19 +35,24 @@
},
{
"cell_type": "code",
- "execution_count": 1,
+ "execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
- "#Libraries\n",
"import pandas as pd\n",
"import numpy as np\n",
- "from sklearn.model_selection import train_test_split"
+ "\n",
+ "from sklearn.model_selection import train_test_split\n",
+ "from sklearn.preprocessing import StandardScaler\n",
+ "from sklearn.feature_selection import SelectKBest, f_classif\n",
+ "from sklearn.linear_model import LogisticRegression\n",
+ "from sklearn.metrics import accuracy_score\n",
+ "from sklearn.model_selection import GridSearchCV"
]
},
{
"cell_type": "code",
- "execution_count": 2,
+ "execution_count": 13,
"metadata": {},
"outputs": [
{
@@ -200,116 +205,2095 @@
"4 True "
]
},
- "execution_count": 2,
+ "execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"spaceship = pd.read_csv(\"https://raw.githubusercontent.com/data-bootcamp-v4/data/main/spaceship_titanic.csv\")\n",
+ "df = pd.read_csv(\"https://raw.githubusercontent.com/data-bootcamp-v4/data/main/spaceship_titanic.csv\")\n",
"spaceship.head()"
]
},
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Now perform the same as before:\n",
- "- Feature Scaling\n",
- "- Feature Selection\n"
- ]
- },
{
"cell_type": "code",
- "execution_count": 9,
+ "execution_count": 14,
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "RangeIndex: 8693 entries, 0 to 8692\n",
+ "Data columns (total 14 columns):\n",
+ " # Column Non-Null Count Dtype \n",
+ "--- ------ -------------- ----- \n",
+ " 0 PassengerId 8693 non-null str \n",
+ " 1 HomePlanet 8492 non-null str \n",
+ " 2 CryoSleep 8476 non-null object \n",
+ " 3 Cabin 8494 non-null str \n",
+ " 4 Destination 8511 non-null str \n",
+ " 5 Age 8514 non-null float64\n",
+ " 6 VIP 8490 non-null object \n",
+ " 7 RoomService 8512 non-null float64\n",
+ " 8 FoodCourt 8510 non-null float64\n",
+ " 9 ShoppingMall 8485 non-null float64\n",
+ " 10 Spa 8510 non-null float64\n",
+ " 11 VRDeck 8505 non-null float64\n",
+ " 12 Name 8493 non-null str \n",
+ " 13 Transported 8693 non-null bool \n",
+ "dtypes: bool(1), float64(6), object(2), str(5)\n",
+ "memory usage: 891.5+ KB\n"
+ ]
+ }
+ ],
"source": [
- "#your code here"
+ "df.info()"
]
},
{
- "cell_type": "markdown",
+ "cell_type": "code",
+ "execution_count": 15,
"metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "PassengerId 0\n",
+ "HomePlanet 201\n",
+ "CryoSleep 217\n",
+ "Cabin 199\n",
+ "Destination 182\n",
+ "Age 179\n",
+ "VIP 203\n",
+ "RoomService 181\n",
+ "FoodCourt 183\n",
+ "ShoppingMall 208\n",
+ "Spa 183\n",
+ "VRDeck 188\n",
+ "Name 200\n",
+ "Transported 0\n",
+ "dtype: int64"
+ ]
+ },
+ "execution_count": 15,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "- Now let's use the best model we got so far in order to see how it can improve when we fine tune it's hyperparameters."
+ "df.isnull().sum()"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 16,
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " HomePlanet \n",
+ " CryoSleep \n",
+ " Destination \n",
+ " Age \n",
+ " VIP \n",
+ " RoomService \n",
+ " FoodCourt \n",
+ " ShoppingMall \n",
+ " Spa \n",
+ " VRDeck \n",
+ " Transported \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " Europa \n",
+ " False \n",
+ " TRAPPIST-1e \n",
+ " 39.0 \n",
+ " False \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " False \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " Earth \n",
+ " False \n",
+ " TRAPPIST-1e \n",
+ " 24.0 \n",
+ " False \n",
+ " 109.0 \n",
+ " 9.0 \n",
+ " 25.0 \n",
+ " 549.0 \n",
+ " 44.0 \n",
+ " True \n",
+ " \n",
+ " \n",
+ " 2 \n",
+ " Europa \n",
+ " False \n",
+ " TRAPPIST-1e \n",
+ " 58.0 \n",
+ " True \n",
+ " 43.0 \n",
+ " 3576.0 \n",
+ " 0.0 \n",
+ " 6715.0 \n",
+ " 49.0 \n",
+ " False \n",
+ " \n",
+ " \n",
+ " 3 \n",
+ " Europa \n",
+ " False \n",
+ " TRAPPIST-1e \n",
+ " 33.0 \n",
+ " False \n",
+ " 0.0 \n",
+ " 1283.0 \n",
+ " 371.0 \n",
+ " 3329.0 \n",
+ " 193.0 \n",
+ " False \n",
+ " \n",
+ " \n",
+ " 4 \n",
+ " Earth \n",
+ " False \n",
+ " TRAPPIST-1e \n",
+ " 16.0 \n",
+ " False \n",
+ " 303.0 \n",
+ " 70.0 \n",
+ " 151.0 \n",
+ " 565.0 \n",
+ " 2.0 \n",
+ " True \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " HomePlanet CryoSleep Destination Age VIP RoomService FoodCourt \\\n",
+ "0 Europa False TRAPPIST-1e 39.0 False 0.0 0.0 \n",
+ "1 Earth False TRAPPIST-1e 24.0 False 109.0 9.0 \n",
+ "2 Europa False TRAPPIST-1e 58.0 True 43.0 3576.0 \n",
+ "3 Europa False TRAPPIST-1e 33.0 False 0.0 1283.0 \n",
+ "4 Earth False TRAPPIST-1e 16.0 False 303.0 70.0 \n",
+ "\n",
+ " ShoppingMall Spa VRDeck Transported \n",
+ "0 0.0 0.0 0.0 False \n",
+ "1 25.0 549.0 44.0 True \n",
+ "2 0.0 6715.0 49.0 False \n",
+ "3 371.0 3329.0 193.0 False \n",
+ "4 151.0 565.0 2.0 True "
+ ]
+ },
+ "execution_count": 16,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "#your code here"
+ "df = df.drop(\n",
+ " columns=[\n",
+ " \"PassengerId\",\n",
+ " \"Cabin\",\n",
+ " \"Name\"\n",
+ " ]\n",
+ ")\n",
+ "\n",
+ "df.head()"
]
},
{
- "cell_type": "markdown",
+ "cell_type": "code",
+ "execution_count": 17,
"metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "HomePlanet 0\n",
+ "CryoSleep 0\n",
+ "Destination 0\n",
+ "Age 0\n",
+ "VIP 0\n",
+ "RoomService 0\n",
+ "FoodCourt 0\n",
+ "ShoppingMall 0\n",
+ "Spa 0\n",
+ "VRDeck 0\n",
+ "Transported 0\n",
+ "dtype: int64"
+ ]
+ },
+ "execution_count": 17,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "- Evaluate your model"
+ "# Define numerical and categorical columns\n",
+ "numerical_columns = [\n",
+ " \"Age\",\n",
+ " \"RoomService\",\n",
+ " \"FoodCourt\",\n",
+ " \"ShoppingMall\",\n",
+ " \"Spa\",\n",
+ " \"VRDeck\"\n",
+ "]\n",
+ "\n",
+ "categorical_columns = [\n",
+ " \"HomePlanet\",\n",
+ " \"CryoSleep\",\n",
+ " \"Destination\",\n",
+ " \"VIP\"\n",
+ "]\n",
+ "\n",
+ "# Fill missing numerical values with the median\n",
+ "for column in numerical_columns:\n",
+ " df[column] = df[column].fillna(df[column].median())\n",
+ "\n",
+ "# Fill missing categorical values with the mode\n",
+ "for column in categorical_columns:\n",
+ " df[column] = df[column].fillna(df[column].mode()[0])\n",
+ "\n",
+ "# Verify missing values\n",
+ "df.isnull().sum()"
]
},
{
"cell_type": "code",
- "execution_count": 1,
+ "execution_count": 18,
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "X shape: (8693, 10)\n",
+ "y shape: (8693,)\n"
+ ]
+ }
+ ],
"source": [
- "#your code here"
+ "X = df.drop(columns=[\"Transported\"])\n",
+ "y = df[\"Transported\"]\n",
+ "\n",
+ "print(\"X shape:\", X.shape)\n",
+ "print(\"y shape:\", y.shape)"
]
},
{
- "cell_type": "markdown",
+ "cell_type": "code",
+ "execution_count": 19,
"metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "X shape after encoding: (8693, 12)\n",
+ "\n",
+ "Columns:\n",
+ "['Age', 'RoomService', 'FoodCourt', 'ShoppingMall', 'Spa', 'VRDeck', 'HomePlanet_Europa', 'HomePlanet_Mars', 'CryoSleep_True', 'Destination_PSO J318.5-22', 'Destination_TRAPPIST-1e', 'VIP_True']\n"
+ ]
+ }
+ ],
"source": [
- "**Grid/Random Search**"
+ "X = pd.get_dummies(\n",
+ " X,\n",
+ " columns=[\n",
+ " \"HomePlanet\",\n",
+ " \"CryoSleep\",\n",
+ " \"Destination\",\n",
+ " \"VIP\"\n",
+ " ],\n",
+ " drop_first=True\n",
+ ")\n",
+ "\n",
+ "print(\"X shape after encoding:\", X.shape)\n",
+ "print(\"\\nColumns:\")\n",
+ "print(X.columns.tolist())"
]
},
{
- "cell_type": "markdown",
+ "cell_type": "code",
+ "execution_count": 20,
"metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Training set: (6954, 12)\n",
+ "Test set: (1739, 12)\n"
+ ]
+ }
+ ],
"source": [
- "For this lab we will use Grid Search."
+ "X_train, X_test, y_train, y_test = train_test_split(\n",
+ " X,\n",
+ " y,\n",
+ " test_size=0.20,\n",
+ " random_state=42,\n",
+ " stratify=y\n",
+ ")\n",
+ "\n",
+ "print(\"Training set:\", X_train.shape)\n",
+ "print(\"Test set:\", X_test.shape)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "- Define hyperparameters to fine tune."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "#your code here"
+ "Now perform the same as before:\n",
+ "- Feature Scaling\n",
+ "- Feature Selection\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "- Run Grid Search"
+ "## Feature Scaling"
]
},
{
"cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": []
- },
- {
- "cell_type": "markdown",
+ "execution_count": 21,
"metadata": {},
- "source": [
- "- Evaluate your model"
- ]
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " Age \n",
+ " RoomService \n",
+ " FoodCourt \n",
+ " ShoppingMall \n",
+ " Spa \n",
+ " VRDeck \n",
+ " HomePlanet_Europa \n",
+ " HomePlanet_Mars \n",
+ " CryoSleep_True \n",
+ " Destination_PSO J318.5-22 \n",
+ " Destination_TRAPPIST-1e \n",
+ " VIP_True \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 3600 \n",
+ " -1.996149 \n",
+ " -0.33634 \n",
+ " -0.279076 \n",
+ " -0.305732 \n",
+ " -0.267311 \n",
+ " -0.264632 \n",
+ " False \n",
+ " False \n",
+ " False \n",
+ " False \n",
+ " True \n",
+ " False \n",
+ " \n",
+ " \n",
+ " 1262 \n",
+ " -0.811703 \n",
+ " -0.33634 \n",
+ " -0.279076 \n",
+ " -0.305732 \n",
+ " -0.267311 \n",
+ " -0.264632 \n",
+ " False \n",
+ " False \n",
+ " True \n",
+ " False \n",
+ " True \n",
+ " False \n",
+ " \n",
+ " \n",
+ " 8612 \n",
+ " 0.442416 \n",
+ " -0.33634 \n",
+ " -0.279076 \n",
+ " -0.305732 \n",
+ " -0.267311 \n",
+ " -0.264632 \n",
+ " False \n",
+ " False \n",
+ " False \n",
+ " True \n",
+ " False \n",
+ " False \n",
+ " \n",
+ " \n",
+ " 5075 \n",
+ " -0.184643 \n",
+ " -0.33634 \n",
+ " -0.279076 \n",
+ " -0.305732 \n",
+ " -0.267311 \n",
+ " -0.264632 \n",
+ " True \n",
+ " False \n",
+ " True \n",
+ " False \n",
+ " False \n",
+ " False \n",
+ " \n",
+ " \n",
+ " 4758 \n",
+ " -1.090396 \n",
+ " -0.33634 \n",
+ " -0.279076 \n",
+ " -0.195161 \n",
+ " -0.266427 \n",
+ " 4.423937 \n",
+ " False \n",
+ " False \n",
+ " False \n",
+ " False \n",
+ " True \n",
+ " False \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " Age RoomService FoodCourt ShoppingMall Spa VRDeck \\\n",
+ "3600 -1.996149 -0.33634 -0.279076 -0.305732 -0.267311 -0.264632 \n",
+ "1262 -0.811703 -0.33634 -0.279076 -0.305732 -0.267311 -0.264632 \n",
+ "8612 0.442416 -0.33634 -0.279076 -0.305732 -0.267311 -0.264632 \n",
+ "5075 -0.184643 -0.33634 -0.279076 -0.305732 -0.267311 -0.264632 \n",
+ "4758 -1.090396 -0.33634 -0.279076 -0.195161 -0.266427 4.423937 \n",
+ "\n",
+ " HomePlanet_Europa HomePlanet_Mars CryoSleep_True \\\n",
+ "3600 False False False \n",
+ "1262 False False True \n",
+ "8612 False False False \n",
+ "5075 True False True \n",
+ "4758 False False False \n",
+ "\n",
+ " Destination_PSO J318.5-22 Destination_TRAPPIST-1e VIP_True \n",
+ "3600 False True False \n",
+ "1262 False True False \n",
+ "8612 True False False \n",
+ "5075 False False False \n",
+ "4758 False True False "
+ ]
+ },
+ "execution_count": 21,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "scaler = StandardScaler()\n",
+ "\n",
+ "X_train_scaled = X_train.copy()\n",
+ "X_test_scaled = X_test.copy()\n",
+ "\n",
+ "X_train_scaled[numerical_columns] = scaler.fit_transform(\n",
+ " X_train[numerical_columns]\n",
+ ")\n",
+ "\n",
+ "X_test_scaled[numerical_columns] = scaler.transform(\n",
+ " X_test[numerical_columns]\n",
+ ")\n",
+ "\n",
+ "X_train_scaled.head()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Feature Selection"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Selected features:\n",
+ "['Age', 'RoomService', 'FoodCourt', 'Spa', 'VRDeck', 'HomePlanet_Europa', 'CryoSleep_True', 'Destination_TRAPPIST-1e']\n",
+ "\n",
+ "Training shape: (6954, 8)\n",
+ "Test shape: (1739, 8)\n"
+ ]
+ }
+ ],
+ "source": [
+ "selector = SelectKBest(\n",
+ " score_func=f_classif,\n",
+ " k=8\n",
+ ")\n",
+ "\n",
+ "X_train_selected = selector.fit_transform(\n",
+ " X_train_scaled,\n",
+ " y_train\n",
+ ")\n",
+ "\n",
+ "X_test_selected = selector.transform(\n",
+ " X_test_scaled\n",
+ ")\n",
+ "\n",
+ "selected_features = X_train_scaled.columns[\n",
+ " selector.get_support()\n",
+ "]\n",
+ "\n",
+ "print(\"Selected features:\")\n",
+ "print(selected_features.tolist())\n",
+ "\n",
+ "print(\"\\nTraining shape:\", X_train_selected.shape)\n",
+ "print(\"Test shape:\", X_test_selected.shape)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "- Now let's use the best model we got so far in order to see how it can improve when we fine tune it's hyperparameters."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "LogisticRegression(max_iter=1000, random_state=42) In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org. \n",
+ "
\n",
+ "
\n",
+ " Parameters \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " random_state\n",
+ " \n",
+ " random_state: int, RandomState instance, default=None Used when ``solver`` == 'sag', 'saga' or 'liblinear' to shuffle the data. See :term:`Glossary <random_state>` for details. \n",
+ " \n",
+ " \n",
+ " 42 \n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " max_iter\n",
+ " \n",
+ " max_iter: int, default=100 Maximum number of iterations taken for the solvers to converge. \n",
+ " \n",
+ " \n",
+ " 1000 \n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " penalty\n",
+ " \n",
+ " penalty: {'l1', 'l2', 'elasticnet', None}, default='l2' Specify the norm of the penalty: - `None`: no penalty is added; - `'l2'`: add an L2 penalty term and it is the default choice; - `'l1'`: add an L1 penalty term; - `'elasticnet'`: both L1 and L2 penalty terms are added. .. warning:: Some penalties may not work with some solvers. See the parameter `solver` below, to know the compatibility between the penalty and solver. .. versionadded:: 0.19 l1 penalty with SAGA solver (allowing 'multinomial' + L1) .. deprecated:: 1.8 `penalty` was deprecated in version 1.8 and will be removed in 1.10. Use `l1_ratio` and `C` instead. `l1_ratio=0` for `penalty='l2'`, `l1_ratio=1` for `penalty='l1'`, `l1_ratio` set to any float between 0 and 1 for `penalty='elasticnet'`, and `C=np.inf` for `penalty=None`. \n",
+ " \n",
+ " \n",
+ " 'deprecated' \n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " C\n",
+ " \n",
+ " C: float, default=1.0 Inverse of regularization strength; must be a positive float. Like in support vector machines, smaller values specify stronger regularization. `C=np.inf` results in unpenalized logistic regression. For a visual example on the effect of tuning the `C` parameter with an L1 penalty, see: :ref:`sphx_glr_auto_examples_linear_model_plot_logistic_path.py`. \n",
+ " \n",
+ " \n",
+ " 1.0 \n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " l1_ratio\n",
+ " \n",
+ " l1_ratio: float, default=0.0 The Elastic-Net mixing parameter, with `0 <= l1_ratio <= 1`. Setting `l1_ratio=1` gives a pure L1-penalty, setting `l1_ratio=0` a pure L2-penalty. Any value between 0 and 1 gives an Elastic-Net penalty of the form `l1_ratio * L1 + (1 - l1_ratio) * L2`. .. warning:: Certain values of `l1_ratio`, i.e. some penalties, may not work with some solvers. See the parameter `solver` below, to know the compatibility between the penalty and solver. .. versionchanged:: 1.8 Default value changed from None to 0.0. .. deprecated:: 1.8 `None` is deprecated and will be removed in version 1.10. Always use `l1_ratio` to specify the penalty type. \n",
+ " \n",
+ " \n",
+ " 0.0 \n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " dual\n",
+ " \n",
+ " dual: bool, default=False Dual (constrained) or primal (regularized, see also :ref:`this equation <regularized-logistic-loss>`) formulation. Dual formulation is only implemented for l2 penalty with liblinear solver. Prefer `dual=False` when n_samples > n_features. \n",
+ " \n",
+ " \n",
+ " False \n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " tol\n",
+ " \n",
+ " tol: float, default=1e-4 Tolerance for stopping criteria. \n",
+ " \n",
+ " \n",
+ " 0.0001 \n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " fit_intercept\n",
+ " \n",
+ " fit_intercept: bool, default=True Specifies if a constant (a.k.a. bias or intercept) should be added to the decision function. \n",
+ " \n",
+ " \n",
+ " True \n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " intercept_scaling\n",
+ " \n",
+ " intercept_scaling: float, default=1 Useful only when the solver `liblinear` is used and `self.fit_intercept` is set to `True`. In this case, `x` becomes `[x, self.intercept_scaling]`, i.e. a "synthetic" feature with constant value equal to `intercept_scaling` is appended to the instance vector. The intercept becomes ``intercept_scaling * synthetic_feature_weight``. .. note:: The synthetic feature weight is subject to L1 or L2 regularization as all other features. To lessen the effect of regularization on synthetic feature weight (and therefore on the intercept) `intercept_scaling` has to be increased. \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " class_weight\n",
+ " \n",
+ " class_weight: dict or 'balanced', default=None Weights associated with classes in the form ``{class_label: weight}``. If not given, all classes are supposed to have weight one. The "balanced" mode uses the values of y to automatically adjust weights inversely proportional to class frequencies in the input data as ``n_samples / (n_classes * np.bincount(y))``. Note that these weights will be multiplied with sample_weight (passed through the fit method) if sample_weight is specified. .. versionadded:: 0.17 *class_weight='balanced'* \n",
+ " \n",
+ " \n",
+ " None \n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " solver\n",
+ " \n",
+ " solver: {'lbfgs', 'liblinear', 'newton-cg', 'newton-cholesky', 'sag', 'saga'}, default='lbfgs' Algorithm to use in the optimization problem. Default is 'lbfgs'. To choose a solver, you might want to consider the following aspects: - 'lbfgs' is a good default solver because it works reasonably well for a wide class of problems. - For :term:`multiclass` problems (`n_classes >= 3`), all solvers except 'liblinear' minimize the full multinomial loss, 'liblinear' will raise an error. - 'newton-cholesky' is a good choice for `n_samples` >> `n_features * n_classes`, especially with one-hot encoded categorical features with rare categories. Be aware that the memory usage of this solver has a quadratic dependency on `n_features * n_classes` because it explicitly computes the full Hessian matrix. - For small datasets, 'liblinear' is a good choice, whereas 'sag' and 'saga' are faster for large ones; - 'liblinear' can only handle binary classification by default. To apply a one-versus-rest scheme for the multiclass setting one can wrap it with the :class:`~sklearn.multiclass.OneVsRestClassifier`. .. warning:: The choice of the algorithm depends on the penalty chosen (`l1_ratio=0` for L2-penalty, `l1_ratio=1` for L1-penalty and `0 < l1_ratio < 1` for Elastic-Net) and on (multinomial) multiclass support: ================= ======================== ====================== solver l1_ratio multinomial multiclass ================= ======================== ====================== 'lbfgs' l1_ratio=0 yes 'liblinear' l1_ratio=1 or l1_ratio=0 no 'newton-cg' l1_ratio=0 yes 'newton-cholesky' l1_ratio=0 yes 'sag' l1_ratio=0 yes 'saga' 0<=l1_ratio<=1 yes ================= ======================== ====================== .. note:: 'sag' and 'saga' fast convergence is only guaranteed on features with approximately the same scale. You can preprocess the data with a scaler from :mod:`sklearn.preprocessing`. .. seealso:: Refer to the :ref:`User Guide <Logistic_regression>` for more information regarding :class:`LogisticRegression` and more specifically the :ref:`Table <logistic_regression_solvers>` summarizing solver/penalty supports. .. versionadded:: 0.17 Stochastic Average Gradient (SAG) descent solver. Multinomial support in version 0.18. .. versionadded:: 0.19 SAGA solver. .. versionchanged:: 0.22 The default solver changed from 'liblinear' to 'lbfgs' in 0.22. .. versionadded:: 1.2 newton-cholesky solver. Multinomial support in version 1.6. \n",
+ " \n",
+ " \n",
+ " 'lbfgs' \n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " verbose\n",
+ " \n",
+ " verbose: int, default=0 For the liblinear and lbfgs solvers set verbose to any positive number for verbosity. \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " warm_start\n",
+ " \n",
+ " warm_start: bool, default=False When set to True, reuse the solution of the previous call to fit as initialization, otherwise, just erase the previous solution. Useless for liblinear solver. See :term:`the Glossary <warm_start>`. .. versionadded:: 0.17 *warm_start* to support *lbfgs*, *newton-cg*, *sag*, *saga* solvers. \n",
+ " \n",
+ " \n",
+ " False \n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " n_jobs\n",
+ " \n",
+ " n_jobs: int, default=None Does not have any effect. .. deprecated:: 1.8 `n_jobs` is deprecated in version 1.8 and will be removed in 1.10. \n",
+ " \n",
+ " \n",
+ " None \n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ " \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
\n",
+ " Fitted attributes \n",
+ " \n",
+ " \n",
+ " \n",
+ " Name \n",
+ " Type \n",
+ " Value \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " classes_\n",
+ " \n",
+ " classes_: ndarray of shape (n_classes, ) A list of class labels known to the classifier. \n",
+ " \n",
+ " \n",
+ " ndarray[bool](2,) \n",
+ " [False, True] \n",
+ "\n",
+ "\n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " coef_\n",
+ " \n",
+ " coef_: ndarray or CSR matrix of shape (1, n_features) or (n_classes, n_features) Coefficients of the features in the decision function. `coef_` is of shape (1, n_features) when the given problem is binary. By default, it will be created as a dense array, but can be turned to sparse (CSR format) through :meth:`sparsify` (which can be beneficial under L1 regularization when many coefficients are zero), and back to dense through :meth:`densify`. \n",
+ " \n",
+ " \n",
+ " ndarray[float64](1, 8) \n",
+ " [[-0.09,-0.84, 0.74,..., 2.01, 1.19,-0.13]] \n",
+ "\n",
+ "\n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " intercept_\n",
+ " \n",
+ " intercept_: ndarray of shape (1,) or (n_classes,) Intercept (a.k.a. bias) added to the decision function. If `fit_intercept` is set to False, the intercept is set to zero. `intercept_` is of shape (1,) when the given problem is binary. \n",
+ " \n",
+ " \n",
+ " ndarray[float64](1,) \n",
+ " [-1.15] \n",
+ "\n",
+ "\n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " n_features_in_\n",
+ " \n",
+ " n_features_in_: int Number of features seen during :term:`fit`. .. versionadded:: 0.24 \n",
+ " \n",
+ " \n",
+ " int \n",
+ " 8 \n",
+ "\n",
+ "\n",
+ " \n",
+ " \n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " n_iter_\n",
+ " \n",
+ " n_iter_: ndarray of shape (1, ) Actual number of iterations for all classes. .. versionchanged:: 0.20 In SciPy <= 1.0.0 the number of lbfgs iterations may exceed ``max_iter``. ``n_iter_`` will now report at most ``max_iter``. \n",
+ " \n",
+ " \n",
+ " ndarray[int32](1,) \n",
+ " [12] \n",
+ "\n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ "LogisticRegression(max_iter=1000, random_state=42)"
+ ]
+ },
+ "execution_count": 24,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "model = LogisticRegression(\n",
+ " max_iter=1000,\n",
+ " random_state=42\n",
+ ")\n",
+ "\n",
+ "model.fit(\n",
+ " X_train_selected,\n",
+ " y_train\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "- Evaluate your model"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 25,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Baseline Accuracy: 0.7838\n"
+ ]
+ }
+ ],
+ "source": [
+ "y_pred = model.predict(\n",
+ " X_test_selected\n",
+ ")\n",
+ "\n",
+ "baseline_accuracy = accuracy_score(\n",
+ " y_test,\n",
+ " y_pred\n",
+ ")\n",
+ "\n",
+ "print(\n",
+ " \"Baseline Accuracy:\",\n",
+ " round(baseline_accuracy, 4)\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Grid/Random Search**"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "For this lab we will use Grid Search."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "- Define hyperparameters to fine tune."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 29,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'C': [0.01, 0.1, 1, 10, 100], 'solver': ['liblinear', 'lbfgs']}"
+ ]
+ },
+ "execution_count": 29,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "param_grid = {\n",
+ " \"C\": [0.01, 0.1, 1, 10, 100],\n",
+ " \"solver\": [\"liblinear\", \"lbfgs\"]\n",
+ "}\n",
+ "\n",
+ "param_grid"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "- Run Grid Search"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 28,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Best parameters: {'C': 100, 'solver': 'liblinear'}\n",
+ "Best CV accuracy: 0.786\n"
+ ]
+ }
+ ],
+ "source": [
+ "grid_search = GridSearchCV(\n",
+ " estimator=LogisticRegression(\n",
+ " max_iter=1000,\n",
+ " random_state=42\n",
+ " ),\n",
+ " param_grid=param_grid,\n",
+ " cv=5,\n",
+ " scoring=\"accuracy\",\n",
+ " n_jobs=-1\n",
+ ")\n",
+ "\n",
+ "grid_search.fit(\n",
+ " X_train_selected,\n",
+ " y_train\n",
+ ")\n",
+ "\n",
+ "print(\"Best parameters:\", grid_search.best_params_)\n",
+ "print(\"Best CV accuracy:\", round(grid_search.best_score_, 4))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "- Evaluate your model"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 30,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Baseline Accuracy: 0.7838\n",
+ "Tuned Accuracy: 0.7844\n"
+ ]
+ }
+ ],
+ "source": [
+ "best_model = grid_search.best_estimator_\n",
+ "\n",
+ "y_pred_tuned = best_model.predict(\n",
+ " X_test_selected\n",
+ ")\n",
+ "\n",
+ "tuned_accuracy = accuracy_score(\n",
+ " y_test,\n",
+ " y_pred_tuned\n",
+ ")\n",
+ "\n",
+ "print(\n",
+ " \"Baseline Accuracy:\",\n",
+ " round(baseline_accuracy, 4)\n",
+ ")\n",
+ "\n",
+ "print(\n",
+ " \"Tuned Accuracy:\",\n",
+ " round(tuned_accuracy, 4)\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Model Evaluation\n",
+ "\n",
+ "Grid Search identified the best Logistic Regression hyperparameters as `C = 100` and `solver = 'liblinear'`.\n",
+ "\n",
+ "The baseline model achieved an accuracy of 0.7838, while the tuned model achieved an accuracy of 0.7844.\n",
+ "\n",
+ "Hyperparameter tuning therefore produced a small improvement of 0.0006, equivalent to 0.06 percentage points. This indicates that the baseline Logistic Regression model was already performing close to its optimal configuration for the selected features.\n",
+ "\n",
+ "Although the improvement is small, Grid Search provides a systematic method for selecting hyperparameters using cross validation rather than relying on manually chosen settings."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
},
{
"cell_type": "code",
@@ -321,9 +2305,9 @@
],
"metadata": {
"kernelspec": {
- "display_name": "Python 3",
+ "display_name": "Python (lab-hyperparameter-tuning)",
"language": "python",
- "name": "python3"
+ "name": "lab-hyperparameter-tuning"
},
"language_info": {
"codemirror_mode": {
@@ -335,9 +2319,9 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.10.9"
+ "version": "3.13.11"
}
},
"nbformat": 4,
- "nbformat_minor": 2
+ "nbformat_minor": 4
}