{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Machine Learning Exercise 2 - Logistic Regression" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This notebook covers a Python-based solution for the second programming exercise of the machine learning class on Coursera. Please refer to the [exercise text](https://github.com/jdwittenauer/ipython-notebooks/blob/master/exercises/ML/ex2.pdf) for detailed descriptions and equations.\n", "\n", "In this exercise we'll implement logistic regression and apply it to a classification task. We'll also improve the robustness of our implementation by adding regularization to the training algorithm. and testing it on a more difficult problem." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Logistic regression" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the first part of this exercise, we'll build a logistic regression model to predict whether a student gets admitted to a university. Suppose that you are the administrator of a university department and you want to determine each applicant's chance of admission based on their results on two exams. You have historical data from previous applicants that you can use as a training set for logistic regression. For each training example, you have the applicant's scores on two exams and the admissions decision. To accomplish this, we're going to build a classification model that estimates the probability of admission based on the exam scores." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's start by examining the data." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import numpy as np\n", "import pandas as pd\n", "import matplotlib.pyplot as plt\n", "%matplotlib inline" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "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", "
Exam 1Exam 2Admitted
0 34.623660 78.024693 0
1 30.286711 43.894998 0
2 35.847409 72.902198 0
3 60.182599 86.308552 1
4 79.032736 75.344376 1
\n", "
" ], "text/plain": [ " Exam 1 Exam 2 Admitted\n", "0 34.623660 78.024693 0\n", "1 30.286711 43.894998 0\n", "2 35.847409 72.902198 0\n", "3 60.182599 86.308552 1\n", "4 79.032736 75.344376 1" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import os\n", "path = os.getcwd() + '\\data\\ex2data1.txt'\n", "data = pd.read_csv(path, header=None, names=['Exam 1', 'Exam 2', 'Admitted'])\n", "data.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's create a scatter plot of the two scores and use color coding to visualize if the example is positive (admitted) or negative (not admitted)." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": [ "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\n", "AluSJEnq0f8ButxExp+t9tQAAAAASUVORK5CYII=\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "positive = data[data['Admitted'].isin([1])]\n", "negative = data[data['Admitted'].isin([0])]\n", "\n", "fig, ax = plt.subplots(figsize=(12,8))\n", "ax.scatter(positive['Exam 1'], positive['Exam 2'], s=50, c='b', marker='o', label='Admitted')\n", "ax.scatter(negative['Exam 1'], negative['Exam 2'], s=50, c='r', marker='x', label='Not Admitted')\n", "ax.legend()\n", "ax.set_xlabel('Exam 1 Score')\n", "ax.set_ylabel('Exam 2 Score')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It looks like there is a clear decision boundary between the two classes. Now we need to implement logistic regression so we can train a model to predict the outcome. The equations implemented in the following code samples are detailed in \"ex2.pdf\" in the \"exercises\" folder." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "First we need to create a sigmoid function. The code for this is pretty simple." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def sigmoid(z):\n", " return 1 / (1 + np.exp(-z))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's do a quick sanity check to make sure the function is working." ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[]" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": [ "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\n", "27ZdNQAMPIEYemn58uRnP3t24F28OPnFL5IXvejp0Dv5/nnPs30yAHSJQAzd8MADzwy7Kx/fcUfT\n", "1V1d6H3BC5JZs9quHABGjkAM6+qxx5qd31bX7V22bPWhd889k9mz264cAJik44G4lDI3yd8mmZXk\n", "1Frr51dzzN8nOTTJb5N8oNZ6w2qOEYjpjccfTx55JHn44eZ+8uPVvLZw8eKMPfBAcu+9yW67PTv0\n", "7r138vznG3GgFQsXLszY2FjbZcCz+N2kn3V02bVSyqwk/5jkoCR3J7m2lLKg1rpo0jGHJdmj1rpn\n", "KeW1Sb6U5HXrVD2jbdmyZwfYKcLsal9bvjzZaqtkyy2fvl/d4112SbbaKguTjM2b14ThjTZq998B\n", "rELooF/53WSYTLUO8f5JltRa70ySUsrXkxyVZNGkY45M8n+TpNZ6dSll61LK9rXWn3ehXlZVazIx\n", "8fT9dG/LlydPPvn07YknnnnfqcdTvf/oo0+H2cceezqwTg6wqwbZ7bdffdBdeb/ppjPr5i5Z0ow+\n", "AAAjaapAPCfJXZOeL03y2mkcs3OSZwfiQw5p7lcdnVjb85kcO52fXfnaysdtPF81vM40zE6+JU34\n", "22CDmd822qi5bbzx2h9P9f5GGyWbbTb9z5v8ePbsp8Ps7NnGEgCAnlvrDHEp5e1J5tZaP7zi+XuS\n", "vLbW+vFJx5yX5C9rrf++4vm3knyi1nr9Kp9lgBgAgJ7o5NbNdyfZZdLzXdJ0gNd2zM4rXlvnogAA\n", "oFem2hv2uiR7llJ2K6VsnOQ/JlmwyjELkrwvSUopr0vykPlhAAAGxVo7xLXWZaWUjyW5OM2ya6fV\n", "WheVUj6y4v2Ta60XllIOK6UsSfJokg92vWoAAOiQnm3MAQAA/WiqkYn1Ukp5RynlllLK8lLKfqu8\n", "d2Ip5fZSym2llIO7WQdMpZQyr5SytJRyw4rb3LZrYrSVUuauOD/eXkr5ZNv1wGSllDtLKTetOF9e\n", "03Y9jK5SypdLKT8vpfxw0mvPLaVcUkr5USnl30opW0/1OV0NxEl+mOSYJFdOfrGUsm+aeeR9k8xN\n", "8k+llG7XAmtTk/xNrfVVK24XtV0Qo2vSpkhz05wnjy+l7NNuVfAMNcnYivPl/m0Xw0g7Pc25crI/\n", "TXJJrXWvJJeueL5WXQ2htdbbaq0/Ws1bRyX5Wq31yRWbfixJswkItMlKKPSLpzZFqrU+mWTlpkjQ\n", "T5wzaV2t9dtJfrXKy09tGrfi/uipPqetruxOeebybUvTbPABbfp4KeUHpZTTpvPXK9BFq9vwyDmS\n", "flKTfKuUcl0p5cNtFwOrmLxj8s+TbD/VD0y1DvGUSimXJNlhNW/9Wa31vBl8lKv76Kq1/K5+KsmX\n", "knxmxfO/SPLXST7Uo9JgVc6H9Lvfq7XeW0rZLsklpZTbVnTqoK/UWut0Nodb70Bca33rOvzYtDbz\n", "gE6a7u9qKeXUJDP5nznotOlsigStqbXeu+L+/lLK2WnGfARi+sXPSyk71FrvK6XsmOQXU/1AL0cm\n", "Js8aLUjyB6WUjUspL0yyZxJXqdKaFf/BrHRMmgtCoS3T2RQJWlFK2byUssWKx7OTHBznTPrLgiTv\n", "X/H4/UnOmeoH1rtDvDallGOS/H2SbZNcUEq5odZ6aK311lLKN5LcmmRZko9WCyLTrs+XUl6Z5q+q\n", "f5LkIy3Xwwhb06ZILZcFK22f5OxSStLkiK/WWv+t3ZIYVaWUryV5U5JtSyl3JfnvSf4yyTdKKR9K\n", "cmeSd075OXIoAACjzNq/AACMNIEYAICRJhADADDSBGIAAEaaQAwAwEgTiAEAGGkCMQAAI+3/AzmO\n", "nhJtkQmYAAAAAElFTkSuQmCC\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "nums = np.arange(-10, 10, step=1)\n", "\n", "fig, ax = plt.subplots(figsize=(12,8))\n", "ax.plot(nums, sigmoid(nums), 'r')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Excellent! Now we need to write the cost function to evaluate a solution." ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def cost(theta, X, y):\n", " theta = np.matrix(theta)\n", " X = np.matrix(X)\n", " y = np.matrix(y)\n", " first = np.multiply(-y, np.log(sigmoid(X * theta.T)))\n", " second = np.multiply((1 - y), np.log(1 - sigmoid(X * theta.T)))\n", " return np.sum(first - second) / (len(X))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we need to do some setup, similar to what we did in exercise 1 for linear regression." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# add a ones column - this makes the matrix multiplication work out easier\n", "data.insert(0, 'Ones', 1)\n", "\n", "# set X (training data) and y (target variable)\n", "cols = data.shape[1]\n", "X = data.iloc[:,0:cols-1]\n", "y = data.iloc[:,cols-1:cols]\n", "\n", "# convert to numpy arrays and initalize the parameter array theta\n", "X = np.array(X.values)\n", "y = np.array(y.values)\n", "theta = np.zeros(3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's quickly check the shape of our arrays to make sure everything looks good." ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "((100L, 3L), (3L,), (100L, 1L))" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X.shape, theta.shape, y.shape" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let's compute the cost for our initial solution (0 values for theta)." ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "0.69314718055994529" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cost(theta, X, y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Looks good. Next we need a function to compute the gradient (parameter updates) given our training data, labels, and some parameters theta." ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def gradient(theta, X, y):\n", " theta = np.matrix(theta)\n", " X = np.matrix(X)\n", " y = np.matrix(y)\n", " \n", " parameters = int(theta.ravel().shape[1])\n", " grad = np.zeros(parameters)\n", " \n", " error = sigmoid(X * theta.T) - y\n", " \n", " for i in range(parameters):\n", " term = np.multiply(error, X[:,i])\n", " grad[i] = np.sum(term) / len(X)\n", " \n", " return grad" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that we don't actually perform gradient descent in this function - we just compute a single gradient step. In the exercise, an Octave function called \"fminunc\" is used to optimize the parameters given functions to compute the cost and the gradients. Since we're using Python, we can use SciPy's \"optimize\" namespace to do the same thing." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's look at a single call to the gradient method using our data and initial paramter values of 0." ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([ -0.1 , -12.00921659, -11.26284221])" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "gradient(theta, X, y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we can use SciPy's truncated newton (TNC) implementation to find the optimal parameters." ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(array([-25.87355624, 0.21193682, 0.20722586]), 51, 1)" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import scipy.optimize as opt\n", "result = opt.fmin_tnc(func=cost, x0=theta, fprime=gradient, args=(X, y))\n", "result" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's see what the our cost looks like with this solution." ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "0.20357134412164668" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cost(result[0], X, y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next we need to write a function that will output predictions for a dataset X using our learned parameters theta. We can then use this function to score the training accuracy of our classifier." ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def predict(theta, X):\n", " probability = sigmoid(X * theta.T)\n", " return [1 if x >= 0.5 else 0 for x in probability]" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "accuracy = 89%\n" ] } ], "source": [ "theta_min = np.matrix(result[0])\n", "predictions = predict(theta_min, X)\n", "correct = [1 if ((a == 1 and b == 1) or (a == 0 and b == 0)) else 0 for (a, b) in zip(predictions, y)]\n", "accuracy = (sum(map(int, correct)) % len(correct))\n", "print 'accuracy = {0}%'.format(accuracy)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Our logistic regression classifer correctly predicted if a student was admitted or not 89% of the time. Not bad! Keep in mind that this is training set accuracy though. We didn't keep a hold-out set or use cross-validation to get a true approximation of the accuracy so this number is likely higher than its true perfomance (this topic is covered in a later exercise)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Regularized logistic regression" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the second part of this exercise, we'll improve our logistic regression algorithm from part one by adding a regularization term. If you're not familiar with regularization, or would like some background on the equations used in this section, refer to \"ex2.pdf\" in the \"exercises\" folder. In a nutshell, regularization is a term in the cost function that causes the algorithm to prefer \"simpler\" models (in this case, models will smaller coefficients). The theory is that this helps to minimize overfitting and improve the model's ability to generalize. With that, let's get started." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Suppose you are the product manager of the factory and you have the test results for some microchips on two different tests. From these two tests, you would like to determine whether the microchips should be accepted or rejected. To help you make the decision, you have a dataset of test results on past microchips, from which you can build a logistic regression model." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Similar to part 1, let's start by visualizing the data." ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "collapsed": false }, "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", "
Test 1Test 2Accepted
0 0.051267 0.69956 1
1-0.092742 0.68494 1
2-0.213710 0.69225 1
3-0.375000 0.50219 1
4-0.513250 0.46564 1
\n", "
" ], "text/plain": [ " Test 1 Test 2 Accepted\n", "0 0.051267 0.69956 1\n", "1 -0.092742 0.68494 1\n", "2 -0.213710 0.69225 1\n", "3 -0.375000 0.50219 1\n", "4 -0.513250 0.46564 1" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "path = os.getcwd() + '\\data\\ex2data2.txt'\n", "data2 = pd.read_csv(path, header=None, names=['Test 1', 'Test 2', 'Accepted'])\n", "data2.head()" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": [ "iVBORw0KGgoAAAANSUhEUgAAAtwAAAHuCAYAAACs89tSAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\n", "AAALEgAACxIB0t1+/AAAIABJREFUeJzs3Xt4W9Wd7//PsoIJcUIICZcACZdMaYdOae1yuNa2NE5D\n", "LoShhbRwfiTMnJaSmVN6IW7pzRMH95RecNppZ4ZAL3PI0KdApoWGkpBQ29umnR+kRIYyLZSmlISE\n", "W2lTk3FwnMjr/CHJkWU5lmRt7Yver+fRE1l7W1pb2pG+XvqstYy1VgAAAADcUeV1AwAAAIAwo+AG\n", "AAAAXETBDQAAALiIghsAAABwEQU3AAAA4CIKbgAAAMBFnhbcxpjvGWNeNcY8Pcb2qDGmzxjTm7p8\n", "odxtBAAAACZikseP/2+SviVp/RH26bbWXl6m9gAAAAAl5WkPt7X2UUl7x9nNlKMtAAAAgBv8nuG2\n", "ki42xjxljNlkjDnH6wYBAAAAhfA6UjKeuKQ51tr9xphFkh6QdHb2TsYY1qcHAACA66y1BacvfF1w\n", "W2v3ZVzfbIz5V2PM8dbaP+XYt7yNg++1traqtbXV62bAZzgvkI1zArlwXiAXY4pLOvs6UmKMOcmk\n", "jswYc74kk6vYBgAAAPzK0x5uY8wPJDVKmmWMeVHSaklHSZK19g5JV0n6e2PMIUn7JV3tVVsBAACA\n", "YnhacFtrrxln+79I+pcyNQchE41GvW4CfIjzAtk4J5AL5wVKyYQh+2yMsWE4DgAAAPiXMSZ8gyYB\n", "AAAqTbED81BapezMpeAGAADwGb6591ap/+jx9SwlAAAAQNBRcAMAAAAuouAGAAAAXETBDQAAALiI\n", "ghsAACAkrLUaHBz0uhmB0NraquXLl5flsSi4AQAAAu6///u/9bGPfUrTpp2gyZOn6LTT3qbbb7/D\n", "tdlOotGojj/+eE+L+zPOOEOdnZ1F/345p1+k4AYAAPC5p59+WkuWfEBHHz1VkycfqyuvXK7nnntO\n", "knTw4EE1NCzSnXe+rP7+bbL2oPbs+a6am+/Qpz/9heH7sNbqscce09q1a/W9731Pe/fuLaotL7zw\n", "grZt26YTTzxRGzduLMnxFSO1CI1nj18ICm4AAAAf6+3t1UUXNWnz5os1OLhTBw7s0AMPnKP/8T8a\n", "9Jvf/EYPPPCAfvvbIR04sF7SWZKMpEu0f/8W/fM//6teeeUV/fnPf9aFFzZp/vzl+uxnd+pjH9ui\n", "U045S9/97r8V3J7169dr/vz5Wr58ue66667h21988UW9//3v14knnqhZs2bpxhtvHN727W9/W+ec\n", "c46OPfZYvf3tb1dvb68k6aWXXtKVV16pE088UWeddZa+9a1vDf9Oa2urrrrqKl199dU69thj9e53\n", "v1u//OUvJUnLly/Xrl27tHTpUk2bNk233XabJOmxxx7TxRdfrBkzZuhd73qXuru7h+/v97//vRob\n", "G3XsscdqwYIFev311ws+9qJZawN/SR4GAABA8GXXNfX1i6y0zkp2xMWYL9srrvif9sorV+TcLlk7\n", "deoye9ddd9lFi66y1dV/b6VExvbf2ClTZtvHHnusoPbNmzfP3n333fa5556zRx11lH3ttdfsoUOH\n", "7Lnnnmtvuukmu3//fjswMGB/9rOfWWutve++++ypp55qn3jiCWuttTt27LA7d+60iUTC1tXV2ba2\n", "Nnvw4EH7/PPP27POOstu2bLFWmvt6tWr7VFHHWV/+MMf2kOHDtnbbrvNnnnmmfbQoUPWWmvPOOMM\n", "29HRMdyu3bt325kzZ9rNmzdba6195JFH7MyZM+3rr79urbX2wgsvtKtWrbKDg4O2p6fHTps2zS5f\n", "vjyv1yDr9oJrVXq4AQAAfGpgYED/+Z+dklaM2mbth/XQQ/ePex9/+tOf1NXVqcHBr2lkuOFsvfnm\n", "p/S1r/1L3u352c9+pj179ujyyy/XW97yFp1zzjn6/ve/r23btunll1/W1772NR1zzDE6+uijdckl\n", "l0iSvvOd7+jmm2/Wu9/9bknSvHnzNHfuXP3iF7/Q66+/ri984QuaNGmSzjzzTH34wx/WPffcM/x4\n", "5513nt7//vcrEonopptu0sDAgB577LGcbbv77ru1ePFiLVy4UJI0f/58nXfeeXrooYe0a9cuPfHE\n", "E2pra9NRRx2l+vp6LV26tGyRFApuAAAAnxoaGkpdm5Rja7WGhhL6wAeWaOrU9ZKGsrb/QYcOPaI5\n", "c+bo6KP/SlLNqHuw9mI9/fSzebfnrrvu0oIFCzRt2jRJ0rJly3TXXXdp9+7dOv3001VVNbq03L17\n", "t+bNmzfq9p07d+qll17SjBkzhi+33nqrXnvtteF9TjvttOHrxhiddtppeumll3K2befOndqwYcOI\n", "+/v5z3+uV155ZfhxjjnmmOH9Tz/99LyPe6JyvXoAAADwgSlTpuid77xQ8fh/SLoma+vdisUW633v\n", "e5++/OVv6de/XqEDB26RdKakn2vKlI/pH/7hH3TuuedqcPA5SQclHZV1H7/S6aefpny8+eabuu++\n", "+zQ0NKTZs2dLkg4cOKC+vj6ddNJJ2rVrlxKJhCKRyIjfmzNnjnbs2DHq/ubOnaszzzxzePBnLi++\n", "+OLw9aGhIe3evVunnHKKpNGzjMydO1fLly/XnXfeOep+du7cqb1792r//v2aMmXK8G3ZbXULPdwA\n", "AAA+9vWv36Jjjvm4pHslHZJ0QNL/1ZQp/6ivfKVFRx11lHp6NuuGG2arpuZ8GXOUTj31w7rtthv0\n", "1a9+UW95y1v09re/TZHI17Pu+Y+qqfmybrrpI3m144EHHtCkSZP0zDPP6KmnntJTTz2lZ555Ru95\n", "z3t0//33a/bs2frMZz6j/fv3p6Iw/ylJ+vCHP6zbbrtN8Xhc1lrt2LFDu3bt0vnnn69p06bpq1/9\n", "qt58800lEgn913/9l5544onhx9y+fbvuv/9+HTp0SN/4xjc0efJkXXjhhZKkk046Sb/73e+G9732\n", "2mv14IMPauvWrUokEhoYGJDjONqzZ49OP/10nXfeeVq9erUOHjyon/3sZ/rJT35S/ItSqGKC3367\n", "iEGTAAAgJHLVNY7j2He9q94eddQUO2nSMfb885vs448/Pmq/oaEhOzg4OOr23//+93b27Hl26tRL\n", "rfQtG4l83h5zzGzb3Py5vNu1cOFC29zcPOr2++67z86ePdu++OKL9oorrrAzZ860s2bNsh//+MeH\n", "91m3bp1961vfaqdOnWrf8Y532CeffNJaa+1LL71kr7nmGnvyySfbGTNm2Isuumh4IGRra6u96qqr\n", "7Ac/+EE7bdo0W1dXZ3t7e4fv88c//rGdO3euPe6442x7e7u11trHH3/cNjY22uOPP96ecMIJ9rLL\n", "LrO7du2y1lr7/PPP2/r6ejt16lT73ve+1954441lGzRpbJnC4m4yxtgwHAcAAMCR5pd+4403ZIwZ\n", "zlAXYmBgQPfee6+6uh7TzJnTdd11/1PnnnvuRJvrmjVr1mjHjh3693//97I/9livQer2glfMIcMN\n", "AAAQEMcee2zRvzt58mRdd911uu6660rYIveEqTOVDDcAAAB8xxhT1uXX3USkBAAAwEeCtGR5WJU6\n", "UkIPNwAAAOAiCm4AAADARRTcAAAAgIsouAEAAAAXUXADAAAALqLgBgAAgGsWL17syeI1mV544QVV\n", "VVVpaGjIk8en4AYAAAiyxx+XPvUpKXsau74+6dprpb17S/IwZ5xxhqZMmaJp06bp5JNP1vLly/XG\n", "G2+M+3ubNm3S8uXLJ/TYra2tE74PL1FwAwAA+NmaNVI8Pvr2nh7pttukt70tef1jHztcdPf1SQsW\n", "SDNmSMcdJ738cu773rtXevPNvJphjNFPfvIT7du3T0899ZSefvppffGLXyzyoCoLBTcAAICfvfOd\n", "0qJFI4vunh7pqquk2lpp+nRp61Zp27Zk0f3nPyeL7fPPl775TSmRkGIxad26kfe7d680f75URNzj\n", "pJNO0oIFC/SrX/1KkvTYY4/p4osv1owZM/Sud71L3d3dw/tGo1F997vfHf75e9/7ns455xwdf/zx\n", "WrhwoXbt2jW87Ve/+pXe+973aubMmTr55JN16623asuWLbr11lt17733atq0aaqtrZUk9fX16UMf\n", "+pBOOeUUnXbaaWppaRmOjAwNDam5uVknnHCC5s2bp4ceeqjgYywlCm4AAAA/u+IK6Y47Dhfd6WL7\n", "Bz+QmpqS+6SL7p/+NNmrnS62jZEmTZIeeki69dbDRXe62I5Gpeuvz7sp6dUXd+/erYcfflgXXHCB\n", "9uzZo8suu0z/+I//qL179+q2227TlVdeqT/+8Y+SRi7R/uMf/1i33nqr7r//fr3++uuqr6/XNddc\n", "I0nat2+f5s+fr8WLF+vll1/Wjh071NTUpEsvvVSf+9zndPXVV2vfvn3q7e2VJP3t3/6tqqur9bvf\n", "/U69vb3aunWrvvOd70iS7rzzTj300EN68skn9cQTT+g//uM/PF0mnoIbAADA79JF97vfLTU2jiy2\n", "8zFvntTZmSy6b731cLF9223JojwP1lpdccUVOvbYYzV37lzNmzdPn//853X33Xdr8eLFWrhwoSRp\n", "/vz5Ou+883L2Kq9bt06f/exn9da3vlVVVVX67Gc/qyeffFK7du3ST37yE51yyin65Cc/qerqak2d\n", "OlXnn3/+8GNnLrX+6quvavPmzfr617+uY445RieccII+8YlP6J577pEk3XffffrkJz+pU089VTNm\n", "zNDnPve5nEu1lwsFNwAAQBAcf/zh6zNmjNyWzmzPn5/svU7HSzKLzHnzpB/9SPrc56Tf/KagYltK\n", "9lT/+Mc/1htvvCHHcdTZ2ant27dr586d2rBhg2bMmDF8+fnPf65XXnll1H3s3LlTH//4x4f3mzlz\n", "piRpz5492r17t84666y82rJz504dPHhQs2fPHr6vlStX6g9/+IMk6eWXX9acOXOG9587d27ex+kG\n", "Cm4AAAC/S8dIfvpT6f77R2a608V2OkZy3HEjM93ponvvXukjH0n2ls+cmewxL1JDQ4NuvPFG3Xzz\n", "zZo7d66WL1+uvXv3Dl/27dunT3/606N+b+7cubrzzjtH7Nvf36+LLrpIc+bM0fPPP5/z8aqqRpas\n", "c+bM0dFHH60//vGPw/fT19enp59+WpI0e/bsEdnwzOteoOAGAADws+zMdnam+9lnpYaGw5lt6XCm\n", "e+/e5CDKzMz2j350OF6SPZCyAJ/4xCe0bds2vec979GDDz6orVu3KpFIaGBgQI7jaM+ePaN+Z+XK\n", "lfrSl76kX//615KSAx83bNggSbrsssv08ssv65/+6Z904MAB7du3T9u2bZOUHKT5wgsvDMdCZs+e\n", "rQULFuimm27Svn37NDQ0pN/97nfq6emRJH3gAx/QN7/5Te3Zs0d79+7Vl7/85aKPsxQouAEAAPzs\n", "hz8cndlOF90//KF0wQXS1742Oh4yfbp0993StGnJHvDMzHZmpvsHPyiqWbNmzdJ1112ntWvXauPG\n", "jfrSl76kE088UXPnzlV7e3vOzPQVV1yhm2++WVdffbWmT5+ud7zjHdqyZYskaerUqXrkkUf04IMP\n", "avbs2Tr77LPlOI4kadmyZZKkmTNn6rzzzpMkrV+/XoODg8Mznixbtmw4xnL99dfr0ksv1Tvf+U6d\n", "d955uvLKKz0dNGm8DJCXijHGhuE4AAAAjDGlH+D3+OPJyEl20fn889LUqdKJJ5b28TI0Njbq+uuv\n", "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\n", "JUmSpA79A109nxJVGE9DAAAAAElFTkSuQmCC\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "positive = data2[data2['Accepted'].isin([1])]\n", "negative = data2[data2['Accepted'].isin([0])]\n", "\n", "fig, ax = plt.subplots(figsize=(12,8))\n", "ax.scatter(positive['Test 1'], positive['Test 2'], s=50, c='b', marker='o', label='Accepted')\n", "ax.scatter(negative['Test 1'], negative['Test 2'], s=50, c='r', marker='x', label='Rejected')\n", "ax.legend()\n", "ax.set_xlabel('Test 1 Score')\n", "ax.set_ylabel('Test 2 Score')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This data looks a bit more complicated than the previous example. In particular, you'll notice that there is no linear decision boundary that will perform well on this data. One way to deal with this using a linear technique like logistic regression is to construct features that are derived from polynomials of the original features. Let's start by creating a bunch of polynomial features." ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "collapsed": false }, "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", "
AcceptedOnesF10F20F21F30F31F32F40F41F42F43
0 1 1 0.051267 0.002628 0.035864 0.000135 0.001839 0.025089 0.000007 0.000094 0.001286 0.017551
1 1 1-0.092742 0.008601-0.063523-0.000798 0.005891-0.043509 0.000074-0.000546 0.004035-0.029801
2 1 1-0.213710 0.045672-0.147941-0.009761 0.031616-0.102412 0.002086-0.006757 0.021886-0.070895
3 1 1-0.375000 0.140625-0.188321-0.052734 0.070620-0.094573 0.019775-0.026483 0.035465-0.047494
4 1 1-0.513250 0.263426-0.238990-0.135203 0.122661-0.111283 0.069393-0.062956 0.057116-0.051818
\n", "
" ], "text/plain": [ " Accepted Ones F10 F20 F21 F30 F31 F32 \\\n", "0 1 1 0.051267 0.002628 0.035864 0.000135 0.001839 0.025089 \n", "1 1 1 -0.092742 0.008601 -0.063523 -0.000798 0.005891 -0.043509 \n", "2 1 1 -0.213710 0.045672 -0.147941 -0.009761 0.031616 -0.102412 \n", "3 1 1 -0.375000 0.140625 -0.188321 -0.052734 0.070620 -0.094573 \n", "4 1 1 -0.513250 0.263426 -0.238990 -0.135203 0.122661 -0.111283 \n", "\n", " F40 F41 F42 F43 \n", "0 0.000007 0.000094 0.001286 0.017551 \n", "1 0.000074 -0.000546 0.004035 -0.029801 \n", "2 0.002086 -0.006757 0.021886 -0.070895 \n", "3 0.019775 -0.026483 0.035465 -0.047494 \n", "4 0.069393 -0.062956 0.057116 -0.051818 " ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "degree = 5\n", "x1 = data2['Test 1']\n", "x2 = data2['Test 2']\n", "\n", "data2.insert(3, 'Ones', 1)\n", "\n", "for i in range(1, degree):\n", " for j in range(0, i):\n", " data2['F' + str(i) + str(j)] = np.power(x1, i-j) * np.power(x2, j)\n", "\n", "data2.drop('Test 1', axis=1, inplace=True)\n", "data2.drop('Test 2', axis=1, inplace=True)\n", "\n", "data2.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we need to modify the cost and gradient functions from part 1 to include the regularization term. First the cost function:" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def costReg(theta, X, y, learningRate):\n", " theta = np.matrix(theta)\n", " X = np.matrix(X)\n", " y = np.matrix(y)\n", " first = np.multiply(-y, np.log(sigmoid(X * theta.T)))\n", " second = np.multiply((1 - y), np.log(1 - sigmoid(X * theta.T)))\n", " reg = (learningRate / 2 * len(X)) * np.sum(np.power(theta[:,1:theta.shape[1]], 2))\n", " return np.sum(first - second) / (len(X)) + reg" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice the \"reg\" term in the equation. Also note the addition of a \"learning rate\" parameter. This is a hyperparameter that controls the effectiveness of the regularization term. Now we need to add regularization to the gradient function:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def gradientReg(theta, X, y, learningRate):\n", " theta = np.matrix(theta)\n", " X = np.matrix(X)\n", " y = np.matrix(y)\n", " \n", " parameters = int(theta.ravel().shape[1])\n", " grad = np.zeros(parameters)\n", " \n", " error = sigmoid(X * theta.T) - y\n", " \n", " for i in range(parameters):\n", " term = np.multiply(error, X[:,i])\n", " \n", " if (i == 0):\n", " grad[i] = np.sum(term) / len(X)\n", " else:\n", " grad[i] = (np.sum(term) / len(X)) + ((learningRate / len(X)) * theta[:,i])\n", " \n", " return grad" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Initialize variables like we did in part 1." ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# set X and y (remember from above that we moved the label to column 0)\n", "cols = data2.shape[1]\n", "X2 = data2.iloc[:,1:cols]\n", "y2 = data2.iloc[:,0:1]\n", "\n", "# convert to numpy arrays and initalize the parameter array theta\n", "X2 = np.array(X2.values)\n", "y2 = np.array(y2.values)\n", "theta2 = np.zeros(11)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's initialize our learning rate to a sensible value. We can play with this later if necessary (i.e. if the penalization is too strong or not strong enough)." ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "collapsed": false }, "outputs": [], "source": [ "learningRate = 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let's try calling our new regularized functions with the default (0) values for theta to make sure the calculations are working." ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "0.6931471805599454" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "costReg(theta2, X2, y2, learningRate)" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([ 0.00847458, 0.01878809, 0.05034464, 0.01150133, 0.01835599,\n", " 0.00732393, 0.00819244, 0.03934862, 0.00223924, 0.01286005,\n", " 0.00309594])" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "gradientReg(theta2, X2, y2, learningRate)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we can use the same optimization function from part 1 to compute the optimal solution." ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(array([ 0.35872309, -3.22200653, 18.97106363, -4.25297831,\n", " 18.23053189, 20.36386672, 8.94114455, -43.77439015,\n", " -17.93440473, -50.75071857, -2.84162964]), 110, 1)" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "result2 = opt.fmin_tnc(func=costReg, x0=theta2, fprime=gradientReg, args=(X2, y2, learningRate))\n", "result2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finally, we can use the prediction function from part 1 to see how accurate our solution is on the training data." ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "accuracy = 91%\n" ] } ], "source": [ "theta_min = np.matrix(result2[0])\n", "predictions = predict(theta_min, X2)\n", "correct = [1 if ((a == 1 and b == 1) or (a == 0 and b == 0)) else 0 for (a, b) in zip(predictions, y2)]\n", "accuracy = (sum(map(int, correct)) % len(correct))\n", "print 'accuracy = {0}%'.format(accuracy)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Although we implemented these algorithms from scratch, it's worth noting that we could also use a high-level python library like scikit-learn to solve this problem." ] }, { "cell_type": "code", "execution_count": 27, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,\n", " intercept_scaling=1, penalty='l2', random_state=None, tol=0.0001)" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from sklearn import linear_model\n", "model = linear_model.LogisticRegression(penalty='l2', C=1.0)\n", "model.fit(X2, y2.ravel())" ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "0.66101694915254239" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model.score(X2, y2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The accuracy is much lower than what we just computed, but keep in mind this result is using the default parameters provided by scikit-learn. We'd likely need to do some parameter tuning to get the same accuracy that we obtained with our earlier result." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "That's all for Exercise 2! Stay tuned for the next exercise where we'll tackle multi-class image classification." ] } ], "metadata": { "kernelspec": { "display_name": "Python 2", "language": "python", "name": "python2" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.9" } }, "nbformat": 4, "nbformat_minor": 0 }