diff --git "a/midterm/midterm/take_at_home_(1).ipynb" "b/midterm/midterm/take_at_home_(1).ipynb" deleted file mode 100644--- "a/midterm/midterm/take_at_home_(1).ipynb" +++ /dev/null @@ -1,1335 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "id": "oZ6_2B0E1DAh" - }, - "source": [ - "# Midterm - Spring 2023\n", - "\n", - "## Problem 1: Take-at-home (45 points total)\n", - "\n", - "You are applying for a position at the data science team of USDA and you are given data associated with determining appropriate parasite treatment of canines. The suggested treatment options are determined based on a **logistic regression** model that predicts if the canine is infected with a parasite. \n", - "\n", - "The data is given in the site: https://data.world/ehales/grls-parasite-study/workspace/file?filename=CBC_data.csv and more specifically in the CBC_data.csv file. Login using you University Google account to access the data and the description that includes a paper on the study (**you dont need to read the paper to solve this problem**). Your target variable $y$ column is titled `parasite_status`. \n", - "\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "Aq8bln4u1DAo" - }, - "source": [ - "### Question 1 - Feature Engineering (5 points)\n", - "\n", - "Write the posterior probability expressions for logistic regression for the problem you are given to solve." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "_kd85pkA1DA3" - }, - "source": [ - "$$p(y=1| \\mathbf{x}, \\mathbf w)= \\frac{p(\\mathbf{x}| y=1)p(y=1)}{p(\\mathbf{x}|y=1)p(y=1)+p(\\mathbf{x}|y=0)}=\\frac{1}{1+\\exp(-\\alpha)}=\\sigma(\\alpha)$$\n", - "\n", - "$$p(y=0| \\mathbf{x}, \\mathbf w)=1-p(y=1|\\mathbf{x}^{T}\\mathbf{w})=1-\\sigma(\\alpha)=\\sigma(-\\alpha)$$" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "Gh6Fi5hz1DA6" - }, - "source": [ - "\n", - "\n", - "### Question 2 - Decision Boundary (5 points)\n", - "\n", - "Write the expression for the decision boundary assuming that $p(y=1)=p(y=0)$. The decision boundary is the line that separates the two classes.\n", - "\n", - "\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "HMr2tF_J1DA-" - }, - "source": [ - "$$p(y=1)=p(y=0)→\\sigma(\\alpha)=-\\sigma(\\alpha)→2\\sigma(\\alpha)=1→\\sigma(\\alpha)=0.5≡\\sigma(\\mathbf{w}^T\\mathbf{x})=0.5$$" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "750Hn0iC1DBA" - }, - "source": [ - "\n", - "\n", - "### Question 3 - Loss function (5 points)\n", - "\n", - "Write the expression of the loss as a function of $\\mathbf w$ that makes sense for you to use in this problem. \n", - "\n", - "NOTE: The loss will be a function that will include this function: \n", - "\n", - "$$\\sigma(a) = \\frac{1}{1+e^{-a}}$$\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "jxiR0jEh1DBD" - }, - "source": [ - "$$\n", - "\\begin{align}\n", - "L_{CE} = -[\\sum_{i=1}^m \\{y_i\\ln \\hat{y}_i + (1-y_i)\\ln(1-\\hat{y}_i)\\}]\\\\\n", - "= -[\\sum_{i=1}^m\\{y_i\\ln\\frac{1}{1+\\exp(-\\mathbf{w}^T\\mathbf{x})}+(1-y_i)\\ln(1-\\frac{1}{1+\\exp(-\\mathbf{w}^T\\mathbf{x})})\\}] \\\\\n", - "= -[\\sum_{i=1}^m\\{y_i[\\ln\\frac{1}{1+\\exp(-\\alpha)}-\\ln(1-\\frac{1}{1+\\exp(-\\alpha)})]+\\ln(1-\\frac{1}{1+\\exp(-\\alpha)})\\}] \\\\\n", - "= -[\\sum_{i=1}^m\\{y_i\\mathbf{w}^T\\mathbf{x}-\\ln(1+\\exp(\\mathbf{w}^T\\mathbf{x}))\\}]\n", - "\\end{align}\n", - "$$\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "AW4xA4221DBF" - }, - "source": [ - "\n", - "### Question 4 - Gradient (5 points)\n", - "\n", - "Write the expression of the gradient of the loss with respect to the parameters - show all your work.\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "bo0YDA0i1DBJ" - }, - "source": [ - "$$\n", - "\\begin{align}\n", - "\\nabla_\\mathbf w L_{CE} = \\nabla_\\mathbf{w}-[\\sum_{i=1}^m\\{y_i\\mathbf{w}^T\\mathbf{x}-ln(1+\\exp(\\mathbf{w}^T\\mathbf{x})\\}] \\\\\n", - "= [-\\sum_{i=1}^my_ix_i] + [\\sum_{i=1}^m\\frac{1}{1+\\exp(\\mathbf{w}^T\\mathbf{x})}\\exp(\\mathbf{w}^T\\mathbf{x})*x_i] \\\\\n", - "= [-\\sum_{i=1}^my_ix_i] + [\\sum_{i=1}^m(\\sigma(\\mathbf{w}^T\\mathbf{x}))*x_i] \\\\\n", - "= \\sum_{i=1}^m (\\sigma(\\mathbf{w}^T\\mathbf{x})-y_i)x_i= \\sum_{i=1}^m(\\hat{y}_i-y_i)x_i\n", - "\\end{align}\n", - "$$" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "BpUryvTT1DBM" - }, - "source": [ - "### Question 5 - Imbalanced dataset (10 points)\n", - "\n", - "You are now told that in the dataset \n", - "\n", - "$$p(y=0) >> p(y=1)$$\n", - "\n", - "Can you comment if the accuracy of Logistic Regression will be affected by such imbalance?\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "TqdImYQf1DBP" - }, - "source": [ - "We know that the loss function heavily penalizes confident wrong decisions. We expect then, that the model will be strongly incentivized to predict 0 more frequently than 1, regardless of the true outcome, as this minimizes loss. This will cause more false negatives, and will need to be considered with regards to our ROC curve. The accuracy will be affected, as there are so few positive examples that the model cannot accurately learn them." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "FK1Su76R1DBS" - }, - "source": [ - "\n", - "### Question 6 - SGD (15 points)\n", - "\n", - "The interviewer was impressed with your answers and wants to test your programming skills. \n", - "\n", - "1. Use the dataset to train a logistic regressor that will predict the target variable $y$. \n", - "\n", - " 2. Report the harmonic mean of precision (p) and recall (r) i.e the [metric called $F_1$ score](https://en.wikipedia.org/wiki/F-score) that is calculated as shown below using a test dataset that is 20% of each group. Plot the $F_1$ score vs the iteration number $t$. \n", - "\n", - "$$F_1 = \\frac{2}{r^{-1} + p^{-1}}$$\n", - "\n", - "Your code includes hyperparameter optimization of the learning rate and mini batch size. Please learn about cross validation which is a splitting strategy for tuning models [here](https://scikit-learn.org/stable/modules/cross_validation.html).\n", - "\n", - "You are allowed to use any library you want to code this problem.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "id": "cnxqYSvL1DBV" - }, - "outputs": [], - "source": [ - "# write your code here" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Preprocessing" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
IDSEXTYPEAREASEX.REPROREPRO.STATUSAGEPARASITE_STATUSRBCHGBWBCEOS.CNTMONO.CNTNUT.CNTPL.CNTLYMP.CNT
0grls5ZUT2BYYMaleSuburbanIntactMaleIntact9Negative6.416.614.2142.0852.06390.0210.06816.0
1grls8DCONYUUFemaleRuralNeuteredFemaleNeutered6Negative4.812.510.0400.0300.04800.0209.04500.0
2grlsUC5R4PTTMaleSuburbanIntactMaleIntact14Negative6.217.39.5190.0475.07315.0164.01520.0
3grlsXUR2PY88MaleRuralIntactMaleIntact6Negative5.413.814.11692.0423.07755.0254.04230.0
4grlsTBZUF3GGFemaleRuralIntactFemaleIntact18Negative5.914.46.5390.0130.02795.0213.03185.0
\n", - "
" - ], - "text/plain": [ - " ID SEX TYPEAREA SEX.REPRO REPRO.STATUS AGE \\\n", - "0 grls5ZUT2BYY Male Suburban IntactMale Intact 9 \n", - "1 grls8DCONYUU Female Rural NeuteredFemale Neutered 6 \n", - "2 grlsUC5R4PTT Male Suburban IntactMale Intact 14 \n", - "3 grlsXUR2PY88 Male Rural IntactMale Intact 6 \n", - "4 grlsTBZUF3GG Female Rural IntactFemale Intact 18 \n", - "\n", - " PARASITE_STATUS RBC HGB WBC EOS.CNT MONO.CNT NUT.CNT PL.CNT \\\n", - "0 Negative 6.4 16.6 14.2 142.0 852.0 6390.0 210.0 \n", - "1 Negative 4.8 12.5 10.0 400.0 300.0 4800.0 209.0 \n", - "2 Negative 6.2 17.3 9.5 190.0 475.0 7315.0 164.0 \n", - "3 Negative 5.4 13.8 14.1 1692.0 423.0 7755.0 254.0 \n", - "4 Negative 5.9 14.4 6.5 390.0 130.0 2795.0 213.0 \n", - "\n", - " LYMP.CNT \n", - "0 6816.0 \n", - "1 4500.0 \n", - "2 1520.0 \n", - "3 4230.0 \n", - "4 3185.0 " - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import pandas as pd\n", - "\n", - "df = pd.read_csv('../data/01_raw/CBC_data.csv')\n", - "df.head()" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/tmp/ipykernel_79816/1867621695.py:5: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame.\n", - "Try using .loc[row_indexer,col_indexer] = value instead\n", - "\n", - "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", - " df2[x] = LabelEncoder().fit_transform(df2[x])\n", - "/tmp/ipykernel_79816/1867621695.py:5: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame.\n", - "Try using .loc[row_indexer,col_indexer] = value instead\n", - "\n", - "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", - " df2[x] = LabelEncoder().fit_transform(df2[x])\n", - "/tmp/ipykernel_79816/1867621695.py:5: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame.\n", - "Try using .loc[row_indexer,col_indexer] = value instead\n", - "\n", - "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", - " df2[x] = LabelEncoder().fit_transform(df2[x])\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
SEXTYPEAREASEX.REPROREPRO.STATUSAGEPARASITE_STATUSRBCHGBWBCEOS.CNTMONO.CNTNUT.CNTPL.CNTLYMP.CNT
01SuburbanIntactMale0906.416.614.2142.0852.06390.0210.06816.0
10RuralNeuteredFemale1604.812.510.0400.0300.04800.0209.04500.0
21SuburbanIntactMale01406.217.39.5190.0475.07315.0164.01520.0
31RuralIntactMale0605.413.814.11692.0423.07755.0254.04230.0
40RuralIntactFemale01805.914.46.5390.0130.02795.0213.03185.0
\n", - "
" - ], - "text/plain": [ - " SEX TYPEAREA SEX.REPRO REPRO.STATUS AGE PARASITE_STATUS RBC \\\n", - "0 1 Suburban IntactMale 0 9 0 6.4 \n", - "1 0 Rural NeuteredFemale 1 6 0 4.8 \n", - "2 1 Suburban IntactMale 0 14 0 6.2 \n", - "3 1 Rural IntactMale 0 6 0 5.4 \n", - "4 0 Rural IntactFemale 0 18 0 5.9 \n", - "\n", - " HGB WBC EOS.CNT MONO.CNT NUT.CNT PL.CNT LYMP.CNT \n", - "0 16.6 14.2 142.0 852.0 6390.0 210.0 6816.0 \n", - "1 12.5 10.0 400.0 300.0 4800.0 209.0 4500.0 \n", - "2 17.3 9.5 190.0 475.0 7315.0 164.0 1520.0 \n", - "3 13.8 14.1 1692.0 423.0 7755.0 254.0 4230.0 \n", - "4 14.4 6.5 390.0 130.0 2795.0 213.0 3185.0 " - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from sklearn.preprocessing import LabelEncoder\n", - "le = LabelEncoder()\n", - "df2 = df.loc[:, df.columns != 'ID']\n", - "for x in ['SEX', 'REPRO.STATUS', 'PARASITE_STATUS']:\n", - " df2[x] = LabelEncoder().fit_transform(df2[x])\n", - "df2.head()" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "Index(['SEX', 'REPRO.STATUS', 'AGE', 'PARASITE_STATUS', 'TYPEAREA_Rural',\n", - " 'TYPEAREA_Suburban', 'TYPEAREA_Urban', 'SEX.REPRO_IntactFemale',\n", - " 'SEX.REPRO_IntactMale', 'SEX.REPRO_NeuteredFemale',\n", - " 'SEX.REPRO_NeuteredMale'],\n", - " dtype='object')" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df3 = pd.get_dummies(df2).dropna(how='any', axis=1)\n", - "df3.columns" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
SEXREPRO.STATUSAGEPARASITE_STATUSTYPEAREA_RuralTYPEAREA_SuburbanTYPEAREA_UrbanSEX.REPRO_IntactFemaleSEX.REPRO_IntactMaleSEX.REPRO_NeuteredFemaleSEX.REPRO_NeuteredMale
010900100100
101601000010
2101400100100
310601000100
4001801001000
\n", - "
" - ], - "text/plain": [ - " SEX REPRO.STATUS AGE PARASITE_STATUS TYPEAREA_Rural TYPEAREA_Suburban \\\n", - "0 1 0 9 0 0 1 \n", - "1 0 1 6 0 1 0 \n", - "2 1 0 14 0 0 1 \n", - "3 1 0 6 0 1 0 \n", - "4 0 0 18 0 1 0 \n", - "\n", - " TYPEAREA_Urban SEX.REPRO_IntactFemale SEX.REPRO_IntactMale \\\n", - "0 0 0 1 \n", - "1 0 0 0 \n", - "2 0 0 1 \n", - "3 0 0 1 \n", - "4 0 1 0 \n", - "\n", - " SEX.REPRO_NeuteredFemale SEX.REPRO_NeuteredMale \n", - "0 0 0 \n", - "1 1 0 \n", - "2 0 0 \n", - "3 0 0 \n", - "4 0 0 " - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df3.head()" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "from sklearn.model_selection import train_test_split\n", - "X = df3.drop(['PARASITE_STATUS'], axis=1)\n", - "y = df3['PARASITE_STATUS']\n", - "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Logreg Model" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "from sklearn.base import BaseEstimator, ClassifierMixin\n", - "from sklearn import metrics\n", - "\n", - "\n", - "class MyLogisticRegression(BaseEstimator, ClassifierMixin):\n", - " def __init__(self, lr=0.01, batch_size=None, max_iter=100, tol=1e-4):\n", - " self.lr = lr\n", - " self.batch_size = batch_size\n", - " self.max_iter = max_iter\n", - " self.tol = tol\n", - " self.f1_score_history = []\n", - "\n", - " def _sigmoid(self, z):\n", - " z = np.clip(z, -1e2, 1e2)\n", - " return 1 / (1 + np.exp(-z))\n", - "\n", - " def _add_intercept(self, X):\n", - " return np.concatenate((np.ones((X.shape[0], 1)), X), axis=1)\n", - "\n", - " def _compute_gradient(self, X, y):\n", - " y_pred = self._sigmoid(np.dot(X, self.coef_))\n", - " grad = np.dot(X.T, (y_pred - y)) / X.shape[0]\n", - " return grad\n", - "\n", - " def fit(self, X, y):\n", - " X = self._add_intercept(X)\n", - "\n", - " # Initialize weights to zeros\n", - " self.coef_ = np.zeros(X.shape[1])\n", - "\n", - " # Mini-batch gradient descent\n", - " for epoch in range(self.max_iter):\n", - " if self.batch_size is not None:\n", - " batch_indices = np.random.choice(X.shape[0], size=self.batch_size, replace=False)\n", - " X_batch = X[batch_indices]\n", - " y_batch = y[batch_indices]\n", - " else:\n", - " X_batch = X\n", - " y_batch = y\n", - "\n", - " # Compute gradient\n", - " grad = self._compute_gradient(X_batch, y_batch)\n", - "\n", - " # Update weights\n", - " self.coef_ -= self.lr * grad\n", - "\n", - " # Check for convergence\n", - " if np.abs(grad).max() < self.tol:\n", - " break\n", - " \n", - " # Compute f1 score\n", - " y_pred = self.predict(X_test)\n", - " f1_score = metrics.f1_score(y_test, y_pred, average='weighted')\n", - " self.f1_score_history.append({'epoch': epoch, 'f1 score': f1_score})\n", - "\n", - "\n", - " return self\n", - "\n", - " def predict(self, X):\n", - " X = self._add_intercept(X)\n", - " return np.round(self._sigmoid(np.dot(X, self.coef_)))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "tags": [] - }, - "source": [ - "## Test" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "0.9290780141843972" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import numpy as np\n", - "from sklearn.datasets import make_classification\n", - "from sklearn.model_selection import train_test_split\n", - "from sklearn.metrics import accuracy_score\n", - "from sklearn.utils import check_random_state\n", - "\n", - "\n", - "#def test_minibatch_logistic_regression():\n", - "# Generate some random classification data\n", - "X, y = make_classification(n_samples=1000, n_features=10, random_state=42)\n", - "\n", - "# Split data into training and test sets\n", - "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)\n", - "\n", - "# Instantiate the MyLogisticRegression model\n", - "model = MyLogisticRegression(lr=0.01, batch_size=32, max_iter=100)\n", - "\n", - "# Fit the model on the training data\n", - "model.fit(X_train, y_train)\n", - "\n", - "# Predict the labels for the test data\n", - "y_pred = model.predict(X_test)\n", - "\n", - "# Check that the predicted labels are binary\n", - "assert set(np.unique(y_pred)) == {0, 1}\n", - "\n", - "# Calculate the accuracy of the predictions\n", - "accuracy = accuracy_score(y_test, y_pred)\n", - "\n", - "# Check that the accuracy is greater than chance level\n", - "assert accuracy > 0.5\n", - "\n", - "\n", - "from sklearn.metrics import precision_score, recall_score, f1_score\n", - "from sklearn.metrics import confusion_matrix\n", - "\n", - "y_pred = model.predict(X_test)\n", - "precision = precision_score(y_test, y_pred)\n", - "precision" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "0.8533333333333334" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "accuracy" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[125, 10],\n", - " [ 34, 131]])" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "confusion_matrix(y_test, y_pred)" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
epochf1 score
000.830236
110.846667
220.846844
330.846762
440.850135
\n", - "
" - ], - "text/plain": [ - " epoch f1 score\n", - "0 0 0.830236\n", - "1 1 0.846667\n", - "2 2 0.846844\n", - "3 3 0.846762\n", - "4 4 0.850135" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "f1s = pd.DataFrame(model.f1_score_history)\n", - "f1s.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## plot F1 vs iteration number" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "image/png": "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9PfzggULBEGI7H29dOmSMGfOHCE1NVVIT08XFi5cKDQ2NsbdNo0g+CwFSkREREQcg0REREQUiAESERERUQAGSEREREQBGCARERERBWCARERERBSAARIRERFRAAZIRERERAEYIBEREREFYIBERCSD3bt3Q6PRdNiMl4h6JgZIRERERAEYIBEREREFYIBERL2C2+1GWVkZhg4diqSkJFx77bV45ZVXAHjLX2+++Sby8vKQmJiI7373u/j888/9rvHqq6/immuugdFoxJAhQ/Doo4/6PW6323H//fcjNzcXRqMRw4cPx7PPPut3TmVlJSZOnIjk5GRMnjwZJ06c6NoXTkRdggESEfUKZWVl+POf/4xt27bhiy++wMqVK3Hbbbdhz5490jm//vWv8eijj+LQoUPIzMxEUVERnE4nAE9g87Of/Qy33norPvvsMzz44IMoLS3F888/Lz1//vz5ePHFF/H444/j+PHjePrpp5GamurXjrVr1+LRRx/Fp59+Cr1ejzvvvLNbXj8RyUsjCIKgdCOIiOJht9vRt29fvPfeeygoKJCOL1q0CC0tLViyZAm+//3vY+fOnZg9ezYA4JtvvsEVV1yB559/Hj/72c8wb948XLx4Ef/7v/8rPf++++7Dm2++iS+++AInT57EyJEj8e6776KwsLBDG3bv3o3vf//7eO+99zBjxgwAwFtvvYWbb74Zra2tSExM7OJ3gYjkxAwSEfV4VVVVaGlpwQ9+8AOkpqZKX3/+859x+vRp6Tzf4Klv374YOXIkjh8/DgA4fvw4pkyZ4nfdKVOm4NSpU3C5XDh69Ch0Oh2mT58eti15eXnSv3NycgAAdXV1cb9GIupeeqUbQEQUr6amJgDAm2++iYEDB/o9ZjQa/YKkWCUlJUV0XkJCgvRvjUYDwDM+ioh6FmaQiKjHGz16NIxGI6qrqzF8+HC/r9zcXOm8Tz75RPr3t99+i5MnT+Lqq68GAFx99dX46KOP/K770Ucf4aqrroJOp8PYsWPhdrv9xjQRUe/FDBIR9XhpaWm49957sXLlSrjdbkydOhUWiwUfffQR0tPTMXjwYADAQw89hH79+iErKwtr166F2WzGT37yEwDAf/zHf+A73/kONmzYgNmzZ2P//v148sknsXXrVgDAkCFDsGDBAtx55514/PHHce211+Kf//wn6urq8LOf/Uypl05EXYQBEhH1Chs2bEBmZibKyspw5swZZGRk4LrrrsOaNWukEtemTZuwYsUKnDp1CuPGjcPrr78Og8EAALjuuuvw0ksv4YEHHsCGDRuQk5ODhx56CHfccYd0j6eeegpr1qzBL3/5S1y6dAmDBg3CmjVrlHi5RNTFOIuNiHo9cYbZt99+i4yMDKWbQ0Q9AMcgEREREQVggEREREQUgCU2IiIiogDMIBEREREFYIBEREREFIABEhEREVEABkhEREREARggEREREQVggEREREQUgAESERERUQAGSEREREQB/n/n1zNu0QvRAwAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import seaborn as sns\n", - "import matplotlib.pyplot as plt\n", - "\n", - "def plot_f1(f1s: pd.DataFrame):\n", - " sns.scatterplot(x=f1s['epoch'], y=f1s['f1 score'])\n", - " sns.lineplot(x=f1s['epoch'], y=f1s['f1 score'])\n", - " plt.show()\n", - "plot_f1(f1s)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Hyperparameter optimization" - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "from sklearn.pipeline import Pipeline #make_pipeline\n", - "from sklearn import preprocessing\n", - "from imblearn.over_sampling import RandomOverSampler\n", - "#from imblearn.pipeline import Pipeline\n", - "#from sklearn.linear_model import LogisticRegression, SGDClassifier\n", - "\n", - "#i = 20000\n", - "\n", - "pipe = Pipeline([\n", - "# ('oversampler', RandomOverSampler()),\n", - " ('preprocessor', preprocessing.StandardScaler()),\n", - "# ('classifier', LogisticRegression(max_iter=i, class_weight='balanced')),\n", - " ('classifier', MyLogisticRegression())\n", - "])\n", - "\n", - "\n", - "\n", - "#model = LogisticRegression(penalty='l1', solver='saga', max_iter=i)\n", - "#pipe.fit(X_train, y_train)" - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "metadata": { - "scrolled": true, - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "{'classifier__batch_size': 82, 'classifier__lr': 0.1}" - ] - }, - "execution_count": 42, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from sklearn.model_selection import GridSearchCV\n", - "import numpy as np\n", - "\n", - "# optimize hyperparameter batch size and learning rate\n", - "param_grid = {\n", - " #'classifier__penalty': ['l1', 'l2'],\n", - " #'classifier__C': [1e-4, 1e-3, 1e-2, 0.1, 1, 10],\n", - " #'classifier__solver': ['sag'],\n", - " #'classifier__class_weight': [None, 'balanced', *[{0: 1, 1:10**x} for x in range(-5, 5)]],\n", - " #'classifier__eta0': [10**x for x in range(-5, 5)],\n", - " 'classifier__batch_size': np.linspace(1, X_train.shape[0], 70, dtype=int)[:10],\n", - " 'classifier__lr': [10**x for x in range(-5, 5)],\n", - "}\n", - "\n", - "grid_search = GridSearchCV(pipe, param_grid, cv=5, scoring='f1', n_jobs=-1)\n", - "#grid_search = GridSearchCV(MyLogisticRegression(), param_grid, cv=5, scoring='f1', n_jobs=-1)\n", - "\n", - "grid_search.fit(X_train, y_train)\n", - "grid_search.best_params_" - ] - }, - { - "cell_type": "code", - "execution_count": 43, - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "0.9166666666666666" - ] - }, - "execution_count": 43, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from sklearn.metrics import precision_score, recall_score, f1_score\n", - "from sklearn.metrics import confusion_matrix\n", - "\n", - "y_pred = grid_search.predict(X_test)\n", - "precision = precision_score(y_test, y_pred)\n", - "precision" - ] - }, - { - "cell_type": "code", - "execution_count": 44, - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[ 33, 12],\n", - " [123, 132]])" - ] - }, - "execution_count": 44, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "confusion_matrix(y_pred == y_test, y_pred)" - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "#from sklearn.model_selection import cross_val_score\n", - "#\n", - "#scores = cross_val_score(grid_search, X, y, cv=5)\n", - "#scores" - ] - }, - { - "cell_type": "code", - "execution_count": 46, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
epochf1 score
000.813799
110.823768
220.833749
330.837076
440.837068
\n", - "
" - ], - "text/plain": [ - " epoch f1 score\n", - "0 0 0.813799\n", - "1 1 0.823768\n", - "2 2 0.833749\n", - "3 3 0.837076\n", - "4 4 0.837068" - ] - }, - "execution_count": 46, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "best_f1 = pd.DataFrame(grid_search.best_estimator_.named_steps['classifier'].f1_score_history)\n", - "best_f1.head()" - ] - }, - { - "cell_type": "code", - "execution_count": 47, - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "image/png": "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vhEJsTEwxWsYfoiISLFkC0AmkwlqtRrl5eVet5eXlyM1NdXnY1asWIHbb78dd999NwDgiiuuQG1tLe699148/vjjyMvLQ0VFBa688krpMU6nE7t378aLL76IhoYGqNXqNsfVarXQai+tvbGamve8GNBLhyHJ8QCAFIOcNSIiIoocso0B0mg0mDBhAnbs2CHd5nK5sGPHDkyePNnnY+x2O6KivKssBhpBEDB9+nR89913OHbsmPQ1ceJEzJ07F8eOHfMZfi5VNfVNADjImYiIyBdZu8CWLFmCefPmYeLEibj66quxbt061NbWYv78+QCAO+64A/3790dubi4AICcnB2vXrsX48eOlLrAVK1YgJycHarUaCQkJGDNmjNc54uLikJSU1Ob2S50YgAy6HtXLSUREFBayfjrOmjULFy5cwBNPPIGysjKMGzcOn332mTQw+uzZs14tPsuXL4dKpcLy5ctx7tw5JCcnIycnB6tXr5brKUQscT0gtgARERG1pRIEQZC7EpHGarXCaDTCYrHAYOiZA2fuefMwtv9YjtW/GYO5ky6TuzpERETdLpjPb9m3wqDuUcMWICIionYxAF2irHXiIGiOASIiImqNAegSVdPgbgEyMAARERG1wQB0ieI0eCIiovZ1KgB9/fXXuO222zB58mScO3cOAPCPf/wDe/bsCWnlqHMEQfAIQGwBIiIiai3oALR161bMmDEDOp0OR48eRUNDAwDAYrHg6aefDnkFKXh1jU44m1eCbr07PBEREXUiAP35z3/Ghg0b8OqrryImpuXDNTMzE0eOHAlp5ahzxNYfdZQKeo1yVr8mIiIKVNABqKCgAFlZWW1uNxqNqK6uDkWdqIvEKfDx2mioVCqZa0NERBR5gg5AqampKCoqanP7nj17MGTIkJBUirrGyvE/REREfgUdgO655x4sWrQIBw4cgEqlQmlpKd566y089NBDuP/++7ujjhQkzgAjIiLyL+gmgqVLl8LlcmH69Omw2+3IysqCVqvFQw89hAceeKA76khBalkFmi1AREREvgT1Cel0OrF3714sWLAADz/8MIqKimCz2TB69GjEx8d3Vx0pSOIq0FwEkYiIyLegPiHVajWuv/565OfnIzExEaNHj+6uelEzi90Bs80Ba30jDLoYmOI0ANDmNqNeIz2G+4ARERH5F3QTwZgxY3D69GkMHjy4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cDqdOHbsGNRqNaZNm+a3LhkZGdL/+/btCwCoqKjo8nMkovCKlrsCREQdsdlsAIBt27ahf//+XvdptVqvENRZOp0uoHIxMTHS/1UqFQD3+CQi6lnYAkREEW/06NHQarU4e/Yshg0b5vWVlpYmldu/f7/0/4sXL+LkyZMYNWoUAGDUqFHYu3ev13H37t2L4cOHQ61W44orroDL5fIaU0REly62ABFRxEtISMBDDz2ExYsXw+VyYerUqbBYLNi7dy8MBgMuu+wyAMBTTz2FpKQkpKSk4PHHH4fJZMLNN98MAPjv//5vXHXVVVi1ahVmzZqFffv24cUXX8RLL70EABg0aBDmzZuHu+66C88//zzGjh2Ln376CRUVFbjlllvkeupE1E0YgIioR1i1ahWSk5ORm5uL06dPIzExEVdeeSWWLVsmdUGtWbMGixYtQmFhIcaNG4ePPvoIGo0GAHDllVfinXfewRNPPIFVq1ahb9++eOqpp3DnnXdK53j55ZexbNky/OEPf0BlZSUGDhyIZcuWyfF0iaibcRYYEfV44gytixcvIjExUe7qEFEPwDFAREREpDgMQERERKQ47AIjIiIixWELEBERESkOAxAREREpDgMQERERKQ4DEBERESkOAxAREREpDgMQERERKQ4DEBERESkOAxAREREpzv8HD9A/g5mPbV4AAAAASUVORK5CYII=", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "plot_f1(best_f1)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "colab": { - "provenance": [] - }, - "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.10.4" - }, - "vscode": { - "interpreter": { - "hash": "62556f7a043365a66e0918c892755cfafede529a87e97207556f006a109bade4" - } - } - }, - "nbformat": 4, - "nbformat_minor": 4 -}