diff --git a/README.md b/README.md index 49902d7..3266b32 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ jupyter notebook ,numpy,pandas,matplotlib - [数据归一化和标准化](machinelearning/knn/07-FeatureScaling/FeatureScaling.ipynb) - [sklearn中的标准化](machinelearning/knn/08-ScalerinScikitLearn/ScalerInScikitLearn.ipynb) -- 线性回归 +- 线性回归法 - [线性回归理论、公式](machinelearning/02线性回归.md) - [简单线性回归实现](machinelearning/linearRegression/01-SimpleLinearRegressionImplementation/SimpleLinearRegressionImplementation.ipynb) - [向量化运算效率高](machinelearning/linearRegression/02-Vectorization/Vectorization.ipynb) @@ -45,7 +45,9 @@ jupyter notebook ,numpy,pandas,matplotlib - [最好的衡量线性回归法的指标:R Squared ](machinelearning/linearRegression/04-R-Squared/R-Squared.ipynb) - [正规方程法实现多元线性回归](machinelearning/linearRegression/05-OurLinearRegression/OurLinearRegression.ipynb) - [sklearn中解决线性回归](machinelearning/linearRegression/06-RegressionInScikitLlearn/RegressionInScikitlearn.ipynb) - +- 梯度下降法 + - [模拟实现梯度下降法(单变量)](machinelearning/gradientDescent/01-GradientDescentSimulations/01-GradientDescentSimulations.ipynb) + - [在线性回归中实现梯度下降法](machinelearning/gradientDescent/02-ImplementGradientDescentInLinearRegression/02-ImplementGradientDescentInLinearRegression.ipynb) diff --git "a/machinelearning/03\346\242\257\345\272\246\344\270\213\351\231\215\346\263\225.md" "b/machinelearning/03\346\242\257\345\272\246\344\270\213\351\231\215\346\263\225.md" new file mode 100644 index 0000000..31153a7 --- /dev/null +++ "b/machinelearning/03\346\242\257\345\272\246\344\270\213\351\231\215\346\263\225.md" @@ -0,0 +1,114 @@ +## 梯度下降法 + +梯度下降法是一种基于搜索的最优化方法,作用:最小化一个损失函数。 + +梯度上升法: 最大化一个效用函数。 + +![](images/ml_11.png) + +移动步长 : -η + +- η 称为学习率 +- η的取值影响获得最优解的速度 +- η的取值不合适,甚至得不到最优解 +- η是梯度下降法的一个超参数 + + + 调参 ,就是调η 。 + +- 局部最优解、全局最优解。 +- 并不是所有函数都有唯一的极值点 (一会下降一会上升再下降上升等) + - 解决方案 + - 多次运行,随机初始化点 + - 梯度下降法的初始点也是个超参数。 + + +线性回归法的损失函数具有唯一的最优解。 + + + + +![](images/ml_13.png) +![](images/ml_14.png) + + +#### 模拟梯度下降法 +[代码](gradientDescent/01-GradientDescentSimulations/01-GradientDescentSimulations.ipynb) + + + +![](images/ml_15.png) + + +![](images/ml_16.png) + +![](images/ml_12.png) + +### 线性回归中的梯度下降法 + + + +![](images/ml_17.png) + + +![](images/ml_18.png) +ps:**给 theta0 凑了个x0, 下图xb(i) * theata 是 简化,向量化方式** + + + +这么看m如果越大,损失就越大。 在梯度中是不合理的。 我们统一除以m,排除这个因素 + + +![](images/ml_19.png) + + +#### 梯度下降法实现 + +```python +# 求均方差,mes , theta 是一个数组,X_b 是一个矩阵 ,n行i列, n=len(X_b) +def J(theta, X_b, y): + try: + return np.sum((y - X_b.dot(theta))**2) / len(X_b) + except: + # 异常则给 浮点数中的最大值 + return float('inf') + +# 求导 (也就是损失值、梯度), 就是上图中的三角形J(theta) +def dJ(theta, X_b, y): + res = np.empty(len(theta)) + # 上图第0行有点特殊 + res[0] = np.sum(X_b.dot(theta) - y) + for i in range(1, len(theta)): + # X_b[:,i] 代表, 第几列 + res[i] = (X_b.dot(theta) - y).dot(X_b[:,i]) + return res * 2 / len(X_b) + + +# 求梯度下降中的 最优theta +# initial_theta 初始化theta +# n_iters 迭代次数控制 +# eta 学习率 +# X_b 矩阵 +# y 结果值 +# epsilon 接受的误差值 +def gradient_descent(X_b, y, initial_theta, eta, n_iters = 1e4, epsilon=1e-8): + + theta = initial_theta + cur_iter = 0 + + while cur_iter < n_iters: + # 下降梯度 + gradient = dJ(theta, X_b, y) + last_theta = theta + theta = theta - eta * gradient + if(abs(J(theta, X_b, y) - J(last_theta, X_b, y)) < epsilon): + break + + cur_iter += 1 + + return theta +``` + + + + diff --git a/machinelearning/gradientDescent/01-GradientDescentSimulations/01-GradientDescentSimulations.ipynb b/machinelearning/gradientDescent/01-GradientDescentSimulations/01-GradientDescentSimulations.ipynb new file mode 100644 index 0000000..73fa656 --- /dev/null +++ b/machinelearning/gradientDescent/01-GradientDescentSimulations/01-GradientDescentSimulations.ipynb @@ -0,0 +1,489 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 模拟梯度下降法" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([-1. , -0.95, -0.9 , -0.85, -0.8 , -0.75, -0.7 , -0.65, -0.6 ,\n", + " -0.55, -0.5 , -0.45, -0.4 , -0.35, -0.3 , -0.25, -0.2 , -0.15,\n", + " -0.1 , -0.05, 0. , 0.05, 0.1 , 0.15, 0.2 , 0.25, 0.3 ,\n", + " 0.35, 0.4 , 0.45, 0.5 , 0.55, 0.6 , 0.65, 0.7 , 0.75,\n", + " 0.8 , 0.85, 0.9 , 0.95, 1. , 1.05, 1.1 , 1.15, 1.2 ,\n", + " 1.25, 1.3 , 1.35, 1.4 , 1.45, 1.5 , 1.55, 1.6 , 1.65,\n", + " 1.7 , 1.75, 1.8 , 1.85, 1.9 , 1.95, 2. , 2.05, 2.1 ,\n", + " 2.15, 2.2 , 2.25, 2.3 , 2.35, 2.4 , 2.45, 2.5 , 2.55,\n", + " 2.6 , 2.65, 2.7 , 2.75, 2.8 , 2.85, 2.9 , 2.95, 3. ,\n", + " 3.05, 3.1 , 3.15, 3.2 , 3.25, 3.3 , 3.35, 3.4 , 3.45,\n", + " 3.5 , 3.55, 3.6 , 3.65, 3.7 , 3.75, 3.8 , 3.85, 3.9 ,\n", + " 3.95, 4. , 4.05, 4.1 , 4.15, 4.2 , 4.25, 4.3 , 4.35,\n", + " 4.4 , 4.45, 4.5 , 4.55, 4.6 , 4.65, 4.7 , 4.75, 4.8 ,\n", + " 4.85, 4.9 , 4.95, 5. , 5.05, 5.1 , 5.15, 5.2 , 5.25,\n", + " 5.3 , 5.35, 5.4 , 5.45, 5.5 , 5.55, 5.6 , 5.65, 5.7 ,\n", + " 5.75, 5.8 , 5.85, 5.9 , 5.95, 6. ])" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# linspace线性增大 \n", + "plot_x = np.linspace(-1., 6., 141)\n", + "plot_x" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# 抛物线函数。\n", + "plot_y = (plot_x-2.5)**2 - 1." + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(plot_x, plot_y)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# 接受误差\n", + "epsilon = 1e-8\n", + "# 学习率\n", + "eta = 0.1" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2.499891109642585\n", + "-0.99999998814289\n" + ] + } + ], + "source": [ + "# theta对应的 值\n", + "def J(theta):\n", + " return (theta-2.5)**2 - 1.\n", + "\n", + "# 函数求导 \n", + "def dJ(theta):\n", + " return 2*(theta-2.5)\n", + "\n", + "theta = 0.0\n", + "while True:\n", + " gradient = dJ(theta)\n", + " last_theta = theta\n", + " theta = theta - eta * gradient\n", + " \n", + " if(abs(J(theta) - J(last_theta)) < epsilon):\n", + " break\n", + " \n", + "print(theta)\n", + "print(J(theta))" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXQAAAD8CAYAAABn919SAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3Xd8leX9//HXJ3uRhJAwQkIS9p5hiQgoorhQXCDgQtSq\nbV3YOlpi/bbWn62jFQcgQ1FAKW6tgqLsEfZeIZCwMsgig4xz/f5IsIgQAjnJfe5zPs/HgwdJOOF+\nG8Obi+u+7usSYwxKKaXsz8vqAEoppZxDC10ppdyEFrpSSrkJLXSllHITWuhKKeUmtNCVUspNaKEr\npZSb0EJXSik3oYWulFJuwqc+LxYZGWni4+Pr85JKKWV769atyzLGRJ3vdfVa6PHx8SQnJ9fnJZVS\nyvZE5EBNXqdTLkop5Sa00JVSyk1ooSullJvQQldKKTehha6UUm5CC10ppdyEFrpSSrkJWxT60j2Z\nvPnjXqtjKKXUBSsqLef5L7ZxILuwzq9li0JftieLV77bTUZBidVRlFLqgny5+QgzlqeSUXCyzq9l\ni0K/rXcs5Q7D/HXpVkdRSqkLMnfNQVpFBZMY17DOr2WLQm8VFUKfhAjmrU3DGGN1HKWUqpHdxwpY\nfzCXUb1bICJ1fj1bFDrA6D6xHMguYmVKttVRlFKqRuauScPXWxjZs3m9XM82hT68czNCA3yYuybN\n6ihKKXVeJWUVLNiQzrCOTWkU4l8v17RNoQf4enNTj+b8d+tRcgpLrY6jlFLV+m77MXKLyhjVJ7be\nrmmbQgcY1acFpRUOPtlwyOooSilVrblrDhLTMJABrSLr7Zq2KvQOzULpFhvO3LUH9eaoUsplHcgu\nZMW+bG5PjMXLq+5vhp5iq0IHGNU7lt3HTrD+YK7VUZRS6qzmrk3DS+DWxPqbbgEbFvr13aIJ8vNm\n3tqDVkdRSqlfKatwMH9dOpe3b0zTsIB6vbbtCj3E34cbukXzxaYjFJSUWR1HKaV+4YedGWQWnOT2\n3i3q/dq2K3SovDlaXFbB55sOWx1FKaV+Ye6agzQJ9WdIu/Oe6ex0tiz0bjFhtG/aQNekK6VcyuHc\nYn7ancmtvWLx8a7/erVloYsIo3rHsuVQHlsP5VkdRymlAPg4OR2Hgdvq+WboKbYsdICbesTg5+PF\nvLU6SldKWa/CYfgoOY1LW0fSolGQJRlsW+hhQb5c07kpn248RHFphdVxlFIebumeTA7lFtfrk6Fn\nsm2hQ+XN0YKScr7crDdHlVLWmrsmjYZBvlzZsYllGc5b6CIyXUQyRGTraR+LEJGFIrKn6ue63+j3\nLPomRNAqKpgPVuuadKWUdY7mlbBwxzFu6RWDv4+3ZTlqMkKfCVx9xsf+CHxvjGkDfF/1fr0TEcb0\njWNjWq7eHFVKWWbu2oNUOAxj+sZZmuO8hW6MWQIcP+PDI4BZVW/PAm50cq4au7lXDAG+Xnyw+oBV\nEZRSHqy8wsHcNWkMbBNJfGSwpVkudg69iTHmSNXbR4FzThqJyP0ikiwiyZmZmRd5uXMLC/Tlhm7R\nfLrhMPn65KhSqp4t2pHB0fwSxvWzdnQOTrgpaiq3PTzn1ofGmCnGmERjTGJUVN08OTWuXzzFZRUs\n0DNHlVL1bPaqAzQLC+Dy9o2tjnLRhX5MRJoBVP2c4bxIF65LTBjdYsKYvVq31VVK1Z/9WYUs25vF\n6D4tLHky9EwXm+Bz4K6qt+8CPnNOnIs3pl8cezNOsHr/mdP9SilVNz5YdQAfr8on111BTZYtzgFW\nAu1EJF1ExgN/B64UkT3A0Kr3LXV912jCAn15f5XeHFVK1b2Ssgo+XpfOVZ2a0ji0frfJPRef873A\nGDP6HL90hZOz1Eqgnze39Iph1opUMgpKaNzANb7ASin39MWmw+QVlzGmX/1vk3su1k/6ONGYvi0o\ndxg+0v1dlFJ1bPbqg7SKCqZ/y0ZWR/mZWxV6y6gQBrRuxIerKxf5K6VUXdiSnsemtFzG9otDpP7O\nDD0ftyp0gHH94jicV8IPOy1deKOUcmOzVx0g0NebkT1jrI7yC25X6EM7NKFJqD+z9eaoUqoO5BWX\n8dmmQ4zoXrkQw5W4XaH7eHsxqncLluzJ5EB2odVxlFJuZsH6dErKHIx1gSdDz+R2hQ4wuk8LvET4\nUHdhVEo5kTGG2asO0C02nM7Nw6yO8ytuWehNwwK4skMTPkpOo6RMD79QSjnHyn3Z7MssZGxf11mq\neDq3LHSAOy+JI6eojM836uEXSinnmLEilYhgP67vFm11lLNy20Lv37IR7Zo0YMaKVN3fRSlVa2nH\ni1i04xij+8QS4GvdIRbVcdtCFxHuGRDPjiP5rNH9XZRStfTeylS8RBjXL97qKOfktoUOMKJ7c8KD\nfJmxPNXqKEopGys8Wc7ctWkM79yUpmGuu62IWxd6oJ83o3q34LvtR0nPKbI6jlLKphZsOERBSTn3\nDIi3Okq13LrQAcb1r3w09/2V+qCRUurCGWOYuXw/XWPC6NmiodVxquX2hd48PJCrOjVhzpqDFJWW\nWx1HKWUzS/dksS+zkLsviXepfVvOxu0LHeCeAQnkl5Tz6QZdwqiUujAzV6QSGeLPtV2bWR3lvDyi\n0BPjGtIpOpSZK/brEkalVI3tzyrkh50ZjOnbAn8f11yqeDqPKHQR4e5L4tl97AQr9mVbHUcpZROz\nVqTi6y0udYhFdTyi0AGu7xZNo2A/Zizfb3UUpZQNFJSUMX9dOtd1jbbNCWgeU+gBvt7c0bcF3+/M\n0F0YlVLn9Z916Zw4Wc7dl8RbHaXGPKbQAcb2i8NbhPd0CaNSqhoOh2HWygP0aBFOt9hwq+PUmEcV\nepPQAK7p0oyP1qZx4qQuYVRKnd1PuzPZn1XIPQMSrI5yQTyq0AHuHhBPwcly5ifrQdJKqbObvnw/\nTUL9Gd65qdVRLojHFXqP2HB6tAhn+vJUPUhaKfUrO47ks3RPFnf2j8fX214VWau0IvKYiGwTka0i\nMkdEXP5WsIhw/8CWHDxexHfbjlodRynlYqYt3U+QnzdjXPQQi+pcdKGLSHPgd0CiMaYz4A2Mclaw\nujSsU1NaRATxzpIUfdBIKfWzo3klfL7pELclxhIe5Gd1nAtW239P+ACBIuIDBAG2eLbe20u4b2AC\nG9NyWXcgx+o4SikXMXNF5VTs+EvtdTP0lIsudGPMIeAfwEHgCJBnjPnOWcHq2i29YggP8mXKkhSr\noyilXMCJk+V8sPoAwzs3IzYiyOo4F6U2Uy4NgRFAAhANBIvI2LO87n4RSRaR5MzMzItP6mRBfj6M\n6xfHwh3HSMk8YXUcpZTF5q1No6CknPsG2nN0DrWbchkK7DfGZBpjyoAFwCVnvsgYM8UYk2iMSYyK\niqrF5Zzvzv7x+Hp58e4y3Q5AKU9WXuFg+rL99ImPoIeL73lendoU+kGgn4gESeUmwVcAO5wTq35E\nNfBnZM/mzF+XTvaJk1bHUUpZ5OutRzmUW8yEy1paHaVWajOHvhqYD6wHtlT9XlOclKve3DcwgZPl\nDt5fpdsBKOWJjDFMWbKPlpHBXNG+sdVxaqVWq1yMMZOMMe2NMZ2NMeOMMbYb5rZu3IAr2jfm/ZUH\nKCmrsDqOUqqerUo5ztZD+dw3sCVeXq59ItH52OsxqDoy4bKWZBeWsmD9IaujKKXq2dSlKTQK9mNk\nz+ZWR6k1LXSgb0IEXWPCmLY0BYduB6CUx9hzrIAfdmZwZ/94Anxd/0Si89FCp3I7gAkDW5KSVcj3\nOzOsjqOUqifTlu7H38eLcf3jrI7iFFroVYZ3bkrz8ECmLNlndRSlVD3IKCjhkw2HuDUxhohg+z3m\nfzZa6FV8vL0Yf2kCa1NzSE49bnUcpVQdm74slTKHg/GX2nup4um00E8zqk8sEcF+vPmjjtKVcmd5\nRWXMXnWAa7s0IyEy2Oo4TqOFfpogPx/uHRDPDzsz2HY4z+o4Sqk68t7KVE6cLOehwa2tjuJUWuhn\nGNc/nhB/H97SUbpSbqmotJzpy/dzefvGdIwOtTqOU2mhnyEs0Jdx/eP4assR3bRLKTc0Z00aOUVl\nPDykldVRnE4L/SzuHZCAn7cX7/ykW+sq5U5OllcwdUkKfRMi6BUXYXUcp9NCP4uoBv6M6h3Lgg3p\nHM4ttjqOUspJPll/iKP5JTw8xL3mzk/RQj+HCZe1xJjKx4KVUvZXXuHgrZ/20aV5GAPbRFodp05o\noZ9DTMMgbuzRnDlrDpKlW+sqZXtfbz3KgewiHh7Smsodv92PFno1HhzUipPlDmYs1wMwlLIzh8Pw\n5uK9tG4cwrCOTayOU2e00KvRunEIwzs35b0VB8gvKbM6jlLqIv2wM4OdRwt4aHAr22+RWx0t9PN4\naHBrCk6W8/5KPQBDKTsyxvDG4r3ENAzk+m7RVsepU1ro59G5eRiD2kYxfdl+ikv1AAyl7GZlSjYb\n03J5YFArfL3du/Lc+7/OSR4e0prswlLmrj1odRSl1AWavHgvkSH+3NorxuoodU4LvQb6JETQJyGC\nt37cp8fUKWUja1OPs3xvNg9c1tItDrA4Hy30GnpsaFsyCk7y4WodpStlF68u3E1kiD9j+7nHARbn\no4VeQ/1bNaJfywje+klH6UrZweqUbFbsy+bBQS0J9HP/0TlooV+Qx4a2JbPgJLNX6YoXpVzda4v2\nENXAc0bnoIV+Qfq2bMQlrRrx9k8puuJFKRe2KiWblSnZ/GZQK4+YOz+lVoUuIuEiMl9EdorIDhHp\n76xgrurRoW3JOqGjdKVc2asLd9O4gT939G1hdZR6VdsR+uvAf40x7YFuwI7aR3JtfRIiGNC6EW//\ntI+i0nKr4yilzrBiXxar9x/nN4M9a3QOtSh0EQkDLgPeBTDGlBpjcp0VzJU9NrQt2YWl+vSoUi7G\nGMNrC/fQJNSf0X08a3QOtRuhJwCZwAwR2SAi00TEfU5brUZifAQD20TyzpIUCk/qKF0pV7FiXzZr\nUo/z0ODWHjc6h9oVug/QE3jLGNMDKAT+eOaLROR+EUkWkeTMzMxaXM61PDq0LccLS3lPR+lKuQRj\nDK8u3E3T0ABu7x1rdRxL1KbQ04F0Y8zqqvfnU1nwv2CMmWKMSTTGJEZFRdXicq6lV1xDLmsbxZQl\n+ziho3SlLLdsbxbJB3J4eIjnzZ2fctGFbow5CqSJSLuqD10BbHdKKpt4bGgbcorKmLUi1eooSnm0\nU6Pz6LAAbvPQ0TnUfpXLb4EPRGQz0B34W+0j2UePFg0Z3C6KqUtTKND90pWyzJI9Waw/mMtDQ1rj\n7+OZo3OoZaEbYzZWTad0NcbcaIzJcVYwu3j8yrbkFpUxdameaqSUFRwOw8vf7iSmYSC3JXru6Bz0\nSdFa6xoTzvDOTXl3aQrZevaoUvXum61H2Xoon8eGtsXPx7MrzbP/653kiWHtKC6rYPLifVZHUcqj\nlFc4+Od3u2jbJIQbezS3Oo7ltNCdoHXjEG7pFcPsVQc4lFtsdRylPMb8demkZBXy5LB2eLvxWaE1\npYXuJL8f2haA1xfttjiJUp6hpKyC17/fQ48W4VzZsYnVcVyCFrqTNA8PZGy/OOavS2dvRgEkJVkd\nSSm3NnvVAY7klTDxqnaI6OgctNCd6uEhrQj09eaf3+2G55+3Oo5SbqugpIzJi/cysE0kl7SKtDqO\ny/CxOoA7aRTiz6Ptg2jz3ANWR1HKrU1dup+cojKeuqq91VFcio7QnSkpiQljBjF4/7rK90Uqf+j0\ni1JOk5FfwrSlKVzbpRldYsKsjuNStNCdKSkJjGHpc/8AYMf/vQLGaKEr5USvLtpDWYWDiVe1O/+L\nPYwWeh3oN+lRAJq9+DzlWdkWp1HKfew5VsC8tQcZ0zeO+EiP2K37gmih1wFfH28O3jqOBkUFpPzm\ncavjKOU2/v7NToL9fPjdFW2sjuKStNDrSOy8WXw7aCSt/jOb4tVrrY6jlO2t3JfN9zszeGhIayKC\n/ayO45K00OuIiBD9+sscDwwl594HwOGwOpJStuVwGF78ZgfRYQHcMyDe6jguSwu9DnXvGs83Y39P\n9PYN5E951+o4StnWF5sPszk9jyevauexh1fUhBZ6HRv4whOsa94Brz/8AXI94gxtpZyqpKyCl7/d\nRcdmodzYXTfgqo4Weh1LaNyAtRNfILAgj+OP/8HqOErZzvTl+0nPKebZazvgpRtwVUsLvR6MmnA9\nH/e+lvCZ0zAbNlgdRynbyMgvYfIPe7myYxMGtNZH/M9HC70ehAf5wV9e4HhgA3LH6w1SpWrqH9/t\norTCwTPXdLA6ii1oodeTW4Z2Yeb1D9Jww1rKZs6yOo5SLm/roTw+XpfOPQMSSNCHiGpEC72e+Hh7\n0SfpMdZHt6PsyYl6g1SpahhjeP6LbUQE+fHI5a2tjmMbWuj16LL2TfhiwrP45+ZQ9PRzVsdRymV9\nteUIa1NzeGJYO0IDfK2OYxta6PVs3MM3MafHcAKmvAWbNlkdRymXU1JWwYtf76RDs1Bu7x1rdRxb\n0UKvZy2jQjgy8Vly/EMonPCbyt0YlVI/e+enFA7lFvOn6zroOaEXSAvdAg/cmMibV91H8NqVON57\n3+o4SrmMtONFvPnjXq7t0kxPIroItS50EfEWkQ0i8qUzAnmC0ABfOj7zezY0a8fJx5+EvDyrIynl\nEv7y5Xa8RHj2Wl2meDGcMUL/PbDDCb+PRxmZGMvcu57CPyeLk8/oDVKlFu/MYOH2Y/zuijZEhwda\nHceWalXoIhIDXAtMc04czyEi3PXbW5jT/Wp83n4LtmyxOpJSlikpqyDpi220jApm/KUJVsexrdqO\n0F8DngLO+eijiNwvIskikpyZmVnLy7mXjtGhpD/xHHn+wRROeEBvkCqPNXVJCgeyi3j+hk74+eit\nvYt10V85EbkOyDDGrKvudcaYKcaYRGNMYlRU1MVezm09OLI3k4eNJ3j1ShyzP7A6jlL1Lu14EZN/\n3Mvwzk0Z2EY7ojZq81fhAOAGEUkF5gKXi8hsp6TyIGGBvnR49lE2NmvLycceh/x8qyMpVa/+8uV2\nBOG56zpaHcX2LrrQjTFPG2NijDHxwCjgB2PMWKcl8yAje8Uy964/4H88i+Jn/mR1HKXqzbfbjv58\nI7S53gitNZ2scgFeXsL4R29lXver8XtrMmzdanUkperciZPlTPpsG+2bNuC+gXoj1BmcUujGmB+N\nMdc54/fyVG2aNOD4M38m3y+IvHvv1xukyu3987tdHCso4W8ju+DrrWNLZ9CvogsZP6I3714zgbC1\nKyl9X2+QKve1OT2XWStSGds3jp4tGlodx21oobuQAF9v+v/tKTY2a0Op3iBVbqq8wsHTC7YQGeLP\nxKvbWR3HrWihu5gB7Zqw+JFJBB3PIucP+gSpcj8zV6Sy7XA+STd00q1xnUwL3QXd+btb+KTX1YRO\neRPHFr1BqtxH2vEiXlm4m8vbN2Z456ZWx3E7WuguqFGIP34v/Z18vyCO3TVBb5Aqt2CM4ekFWxDg\nLyM6IaJb4zqbFrqLuu7yLnx220M027CKrGnvWR1HqVqbtzaNZXuzePqaDsQ0DLI6jlvSQndRIsKw\nV55jW7M2eD31JEZvkCobO5JXzF+/2kG/lhHc0aeF1XHclha6C4tuFEL6Cy8TkZvFjocmQlKS1ZGU\numDGGJ5ZsIUyh4OXbu6Kl55CVGe00F3csHtv4IdLb6DNnHfh+eetjqPUBftkwyEW78pk4lXtiWsU\nbHUct6aF7uJEhHbT/02hX+U+F8Zxzp2KlXI5GQUlPP/FdnrFNeTuS+KtjuP2tNBdXVISzdvGEV5y\nAgDx9gYRnX5RLu/UVEtxWQUv3dxVD3yuB1rori4pCYzBUVYOQKm3D0cWLdNCVy7vo+Q0Fu3I4Kmr\n2tG6cYjVcTyCFrpNePl4A5Ad3BAZdRsVObkWJ1Lq3A5mF/GXL7bTv2Uj7h2gOynWFy10O5k0iV2v\nTSEy+yipI+/QB46US6pwGJ78eBNeIvzjtm66qqUeaaHbSVISg+4ewee3PUyrH7/h6N9fsTqRUr8y\nbWkKa1KPk3RDJz20op5poduMiDB46v9jWds+RPzpaUrXrLU6klI/23Ekn39+t5urOjVhZM/mVsfx\nOFroNhTRIAAzcwZZQWGcuPFm3WZXuYSSsgoem7eR0EBf/nZTF92rxQJa6DY1sH9Hvnz6n4QePUTG\nqDt1Pl1Z7sWvd7DzaAEv39qVRiH+VsfxSFroNnbnk2OYdc0EGn/zGfmvv2F1HOXBvtt2lFkrD3Df\npQkMadfY6jgeSwvdxgJ8vRk49SV+apVIwMQncaxbb3Uk5YGO5BXz1H8207l5qJ5AZDEtdJtr2yyM\nrDemkB3QgIIRI3U+XdWrCofh0bkbKS138O/RPfGvel5CWUML3Q2MvKo7Hzz6EsGH08gZe7fOp6t6\nM3nxXlbvP84LIzqTEKkbb1lNC90NiAgTnr6TacPuoeEXn1D8xltWR1IeYFVKNq8t2s1NPZpzc68Y\nq+MoalHoIhIrIotFZLuIbBOR3zszmLowYUG+9Hn7JZYk9MTn8cdwbNhodSTlxjLyS3jkww3ERwbz\nwo2drY6jqtRmhF4OPGGM6Qj0Ax4WkY7OiaUuRs/4RqT/6x2yA0LIv+EmKCiwOpJyQ+UVDh6Zs4HC\nk+W8PbYXIf4+VkdSVS660I0xR4wx66veLgB2APpomMVGX9uLOY++RINDB8kcc7fOpyune/nbXazZ\nf5wXR3ahbZMGVsdRp3HKHLqIxAM9gNXO+P3UxRMRJjx3NzOvvoeoLxaQ/2+dT1fO89+tR3lnSQpj\n+7Xgxh46fnM1tS50EQkB/gM8aoz51Zo5EblfRJJFJDkzM7O2l1M1EOLvw8B3/8mylj0JePIxynQ+\nXTlBalYhEz/eRLeYMP50nc6uuqJaFbqI+FJZ5h8YYxac7TXGmCnGmERjTGJUVFRtLqcuQNtmYRRM\nnU6Ofwh51+l8uqqdgpIyJryXjLe3MHmMrjd3VbVZ5SLAu8AOY4zu4+qChl/ejYXPvUrDIwdJvXWc\nzqeri+JwGB6bt5GUrELevKMnMQ2DrI6kzqE2I/QBwDjgchHZWPXjGiflUk4yeuI4Ph0xgfhvP2P/\nS/+yOo6yoVcW7mbRjgz+fF1HLmkdaXUcVY2LXm9kjFkG6P6YLs7bSxj6/msk91xH5z89xbGBl9Bk\n4Vd6JqmqkS83H+aNxXsZ1TuWO/vHWR1HnYc+KeoBwkICiPxkHgUBwZSOvAWef97qSMoGth7K48mP\nN5EY15C/jOis+5vbgBa6h4jv1JL0N6YRnZkOgONkqcWJlCs7ll/ChPeSiQjy462xvfDz0aqwA/2/\n5CmSkuhx9814GwcAXgH+IKJTL+pXTpws554Za8kvLmPqXYlENdDDKuxCC91TJCWBMRiH4+cP7Rw5\nDiZNsi6TcjnlFQ4e+XA9u44VMHlMTzpFh1kdSV0ALXQPc2oe9L9Xj6X9gvdJ+c0TFidSrsIYw58/\n38aPuzJ5YURnBuvJQ7ajhe6JJk3isk+n823/62j5zqscfu4FqxMpF/DOkhQ+XH2Q3wxuxR19W1gd\nR10ELXRPlJREkL8vPb+ex/ddBxP91z+T+epkq1MpC32yIZ2/f7OT67tFM3GYHiNnV1roHiwqPIj4\nr//D8taJNHrit+TOnG11JGWBRduP8eTHm7mkVSNevqUrXl66PNGutNA9XKvmEYR9/TkbYjoSfN89\nFHz6hdWRVD1auS+bhz5cT+foUKbcmUiAr+7RYmda6IrObZrh+OILdkfG4XfbrRT98KPVkVQ92JKe\nx4T3komLCGLmPX30oAo3oIWuAOjdLYGsjz/lUINIuPY6Tq5JtjqSqkN7M05w14w1hAX68v74vjQM\n9rM6knICLXT1s0EDO7N79gJy/II4OXQYJ7dutzqSqgP7Mk9wx9RVeIkw+76+NA0LsDqSchItdPUL\nVw/vw6Z3P6a0wnBi0OWU7NtvdSTlRPsyTzB6yiocxjBnQl8SIoOtjqScSAtd/co1twxi/ZQ5+Bae\nIHfAIErSD1f+gm4TYGspvyjzfrTR80Ddjha6OqthY65m7RuzCMvO4NglgynJzNZdGm0sJfMEo6as\nosJh+FDL3G1poatzuuK+m1n9z6k0O7Sfg/2HWB1HXaSdR/O5varM59zfj7Za5m5LC11Va/Dxffg5\nymm7b0vlB0R0l0YbWXcgh9veXomXwFwtc7enha6qV7VL4/p/zQDgWMMmZK1M1kK3gSW7Mxk7bTUR\nwX7Mf/ASnWbxAFroqkZ6/vZuAKSsjIDBgzg2/3NrA6lqfbX5CONnrSUhMpiPH7yE2Ag92NkTaKGr\nmps0iaxFP3E4vDGNbr+JtBdftTqROoMxhunL9vPInPV0jw1nzv399IAKD6KFrmouKYmOfTvjs3I5\na9v2JvaZx0m560GoqLA6maLycIo/f7aNv3y5nWEdm/DevX0JC/S1OpaqR1ro6oK1TGhG25Xf8/Wg\nm2n53jukDB6OOXHC6lgeraCkjPGzknl/1QEeuKwlb43pRaCfbrTlabTQ1UVpFB7M5QvnMf/OicQt\n/55D3fpSejDd6lgeKT2niFveWsmyvVm8OLILT1/TQbfA9VC1KnQRuVpEdonIXhH5o7NCKXsI8PXm\n5pkv8fnzb9IwLYX8br3IXL6m8hd1FUy9WLonk+v/vYzDucXMuqcPo/voSUOe7KILXUS8gcnAcKAj\nMFpEOjormLIHEeGmPz3A+vc/o7yigqDLB7N9+lx9qrSOORyGyYv3cuf0NUQ18OezRwZwaZtIq2Mp\ni9VmhN4H2GuMSTHGlAJzgRHOiaXsZuDtwyheupzDUTG0u28MAKa83OJU7imvuIz730/m5W93cX3X\naD59eAAto0KsjqVcQG0KvTmQdtr76VUfUx4q4ZM5tDm0B2/jAEB8ffWpUidbfzCH6/+9jB93ZTLp\n+o68Pqo7QX56MIWqVOc3RUXkfhFJFpHkzMzMur6cslLVU6WmahljgX8QRX4B7JIQMMbabDZXXuHg\n1YW7ufXtlVQ4DPMe6Mc9AxIQ0Zuf6n9qU+iHgNjT3o+p+tgvGGOmGGMSjTGJUVFRtbicsgvxqvy2\nOrZ8LTtcfHxKAAAIZ0lEQVTjO9EuaSJ7EgdSvP+gxcnsKTWrkFveXsnr3+9hRLdovnl0IL3iIqyO\npVxQbQp9LdBGRBJExA8YBejz4KrSpEm07tWRjptX8s2DzxKzOZnyTp3Y99qU/43WdSqmWhUOw8zl\n+7n2X0tJyTzBv0f34JXbuxMaoA8LqbMTU4t/CovINcBrgDcw3Rjz1+pen5iYaJKT9axKT5S8cDX+\n991Ll4Pb2dL/SuLmziI0LlqnYs5hx5F8/rhgC5vScrmsbRR/H9mF6PBAq2Mpi4jIOmNM4nlfV5tC\nv1Ba6J6tqPgkq3/zNAPe/zf5QQ2IPJGDKS9HvPWJxlOKSyt4/fs9TF2aQnigL3++viM3dIvWuXIP\nV9NC19vjqt4EBfozJD4UHOVEnsgBQHyqvgUnTfLoKRiHw/DpxkO8/O0ujuSVcHtiLE9f057wID+r\noykb0Uf/Vf2qWglTUVa5Rv1oWOWN8u2ff0/GiuRfvs5DrNyXzQ2Tl/H4R5uIDPHnowf689ItXbXM\n1QXTQleW8PapnGYJSt3Hj+OfJGb7Bhpd2peNw24ma9c+j3jSdFNaLuNnrmX01FUcP1HKa7d357OH\nB9AnQVewqIujha6sM2kSoeENGDztZQq372TpNXfQ4YfPCe7cCYCjm3b8+nPcYOS+OiWbce+uZsTk\n5SQfyGHiVe344cnB3NijuW6qpWpFb4oq15GUdNaR+fFb7yBi3uz/nWdqw5UxZRUOFm0/xozlqaxJ\nPU5kiB/3DWzJ2H5xhPjrrSxVPV3louxNhCU330fXr+cRXlzA3ti2ZN/7IH2ff/yXhZ6U5NKj9sO5\nxcxdc5C5a9PIKDhJ8/BAJgxMYFSfFgT46uoeVTNa6Mreqkbiedl55N8wktgVP/zqJRXPPov3X//q\ncgWfW1TKd9uP8dXmIyzdk4kBBreNYkzfOIa0b4y3TquoC1TTQtc5dOWaJk0CIKxRGLHLv8eUl7Pj\ng08ByAuo3Fkw79U3ANj4rxnkZ2RXft7pUzaniv3Mn+tAek4Rc9cc5K7pa0j8v0U8NX8z+zJP8OCg\nViyZOIQZ9/RhaMcmWuaqTukIXdmLCOVPP4PPi3/71S9lNGxC45xjbJk6l+ZXDyYitmnl6P3UvLvI\n/9a7JyXBjz9WfmJqKhw4UOO5eYfDkJZTxKb0PFbuy2L53mwOHi8CIKZhINd2bca1XZrRpXmYPhCk\nnEKnXJR7OnNKRYSMkaNovGDuWV++rscgem34iVV/+gf9XngSgPysHEIjG/76xaf9WXA4DNmFpRzJ\nK+ZwbglH84pJySpk++F8dhzJp7C0ckfJBv4+9G3ZiAGtG9G/VSPaNWmgJa6cTgtdeYYzV73UokyH\nP/sfjvk3oKSsguKyil8N2EP8fejQrAEdm4XSoVkonaLD6NCsAT7eOnOp6pY++q88Q9Vc+y+cauLT\np1pq4Ju/3lz56cAr3+4kqoE/TUMDiA4PpGlYAI2C/XT0rVyaFrqytzNvdJ6t4OGXxX6ukq/6i0CA\nJ5wWUKn6o/9WVO7l9II/Ve5n/qyUm9IRunJf1S1bnDTp16tclLI5vSmqlFIuTh8sUkopD6OFrpRS\nbkILXSml3IQWulJKuQktdKWUchP1uspFRDKBi10fFglkOTFOXbNTXjtlBXvltVNWsFdeO2WF2uWN\nM8ZEne9F9VrotSEiyTVZtuMq7JTXTlnBXnntlBXslddOWaF+8uqUi1JKuQktdKWUchN2KvQpVge4\nQHbKa6esYK+8dsoK9sprp6xQD3ltM4eulFKqenYaoSullKqGrQpdRG4VkW0i4hARl7y7LSJXi8gu\nEdkrIn+0Ok91RGS6iGSIyFars5yPiMSKyGIR2V71PfB7qzNVR0QCRGSNiGyqyvv8+T/LWiLiLSIb\nRORLq7Ocj4ikisgWEdkoIi6945+IhIvIfBHZKSI7RKR/XV3LVoUObAVGAkusDnI2IuINTAaGAx2B\n0SLS0dpU1ZoJXG11iBoqB54wxnQE+gEPu/jX9iRwuTGmG9AduFpE+lmc6Xx+D+ywOsQFGGKM6W6D\npYuvA/81xrQHulGHX2NbFboxZocxZpfVOarRB9hrjEkxxpQCc4ERFmc6J2PMEuC41TlqwhhzxBiz\nvurtAir/UDS3NtW5mUonqt71rfrhsjesRCQGuBaYZnUWdyIiYcBlwLsAxphSY0xuXV3PVoVuA82B\ntNPeT8eFS8euRCQe6AGstjZJ9aqmMDYCGcBCY4wr530NeApwWB2khgywSETWicj9VoepRgKQCcyo\nms6aJiLBdXUxlyt0EVkkIlvP8sNlR7qq/ohICPAf4FFjTL7VeapjjKkwxnQHYoA+ItLZ6kxnIyLX\nARnGmHVWZ7kAl1Z9bYdTOf12mdWBzsEH6Am8ZYzpARQCdXZvzeWOoDPGDLU6Qy0cAmJPez+m6mPK\nCUTEl8oy/8AYs8DqPDVljMkVkcVU3q9wxRvQA4AbROQaIAAIFZHZxpixFuc6J2PMoaqfM0TkEyqn\nO13x3lo6kH7av87mU4eF7nIjdJtbC7QRkQQR8QNGAZ9bnMktiIhQOQ+5wxjzitV5zkdEokQkvOrt\nQOBKYKe1qc7OGPO0MSbGGBNP5ffsD65c5iISLCINTr0NDMM1/6LEGHMUSBORdlUfugLYXlfXs1Wh\ni8hNIpIO9Ae+EpFvrc50OmNMOfAI8C2VN+0+MsZsszbVuYnIHGAl0E5E0kVkvNWZqjEAGAdcXrVU\nbWPViNJVNQMWi8hmKv+iX2iMcfnlgDbRBFgmIpuANcBXxpj/WpypOr8FPqj6XugO/K2uLqRPiiql\nlJuw1QhdKaXUuWmhK6WUm9BCV0opN6GFrpRSbkILXSml3IQWulJKuQktdKWUchNa6Eop5Sb+P8u/\nPqhgwi92AAAAAElFTkSuQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "theta = 0.0\n", + "theta_history = [theta]\n", + "while True:\n", + " gradient = dJ(theta)\n", + " last_theta = theta\n", + " theta = theta - eta * gradient\n", + " theta_history.append(theta)\n", + " \n", + " if(abs(J(theta) - J(last_theta)) < epsilon):\n", + " break\n", + "\n", + "plt.plot(plot_x, J(plot_x))\n", + "# 下降中,导数的变换曲线。\n", + "plt.plot(np.array(theta_history), J(np.array(theta_history)), color=\"r\", marker='+')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "46" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(theta_history)" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "theta_history = []\n", + "\n", + "def gradient_descent(initial_theta, eta, epsilon=1e-8):\n", + " theta = initial_theta\n", + " theta_history.append(initial_theta)\n", + "\n", + " while True:\n", + " gradient = dJ(theta)\n", + " last_theta = theta\n", + " theta = theta - eta * gradient\n", + " theta_history.append(theta)\n", + " \n", + " if(abs(J(theta) - J(last_theta)) < epsilon):\n", + " break\n", + " \n", + "def plot_theta_history():\n", + " plt.plot(plot_x, J(plot_x))\n", + " plt.plot(np.array(theta_history), J(np.array(theta_history)), color=\"r\", marker='+')\n", + " plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "eta = 0.01\n", + "theta_history = []\n", + "gradient_descent(0, eta)\n", + "plot_theta_history()" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "424" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(theta_history)" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXQAAAD8CAYAAABn919SAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3Xl4leWd//H3NythC1tYAyTsIohoZBER3MW9tiooWq1L\nZ9SZ6q+1v3bmNxXba9rOZRedjrVF64qKS+ni0ioo+x42ZV9CQsKWEEgIS0KSc//+SOggJieBc3Ke\n85zzeV0XF+TkkOfTVD7c3M/93Lc55xAREf9L8DqAiIiEhwpdRCRGqNBFRGKECl1EJEao0EVEYoQK\nXUQkRqjQRURihApdRCRGqNBFRGJEUiQv1qVLF5eVlRXJS4qI+N6qVasOOOcymnpfRAs9KyuL3Nzc\nSF5SRMT3zKygOe/TlIuISIxQoYuIxAgVuohIjFChi4jECBW6iEiMUKGLiMQIFbqISIzwRaEv3FbC\nb+dt9zqGiMgZO3aihqfe30BB6dEWv5YvCn3RtgP86pOtFFdUeh1FROSMfPD5Xl5enE9xRVWLX8sX\nhX77Rb2pCTjeW1XkdRQRkTMyc8Uu+me0Iadvxxa/li8KvX9GW0Zld+LtlYU457yOIyLSLFv3V7B6\nVxmTL+qDmbX49XxR6ABTRvWmoPQYS/NKvY4iItIsM1cUkpxo3HpBr4hczzeFPmlYD9q3SmLmikKv\no4iINKmyupZZa4q4emh3OrdNjcg1fVPorZIT+drIXvx9/T4OHT3hdRwRkaA+2bifsmPVTB7VO2LX\n9E2hA0we1YcTtQH+tGa311FERIKauWIXmR3TGNe/S8Su6atCP6dHe0b07sDMlbt0c1REolZB6VGW\n7CjljpzeJCS0/M3Qk3xV6ACTL+rN1v1HWL2rzOsoIiINmrmykASD23IiN90CPiz0G0f0pHVKIm+v\n3OV1FBGRr6iuDfDeqiIuH9KV7umtInpt3xV629QkbhrRk/fX7aWistrrOCIiX/LZ5mJKKqq446I+\nEb+27wod6m6OHq+u5a/r9ngdRUTkS2au2EW39qlcNrjJM53DzpeFPiIznSHd22lNuohElT1lx5m/\ntYTbLuxNUmLk69WXhW5mTL6oN1/sLmf97nKv44iIAPBubhEBB7dH+GboSb4sdICvjcwkJSmBt1dq\nlC4i3qsNON7JLeSSAV3o07m1Jxl8W+jprZO5blh3/rx2N8dP1HodR0Ti3MJtJewuOx7RJ0NP59tC\nh7qboxWVNXzwuW6Oioi3Zq4opGPrZK4a2s2zDE0Wupm9ZGbFZrb+lNc6mdlsM9tW/3PLb/TbgNHZ\nneif0YY3lmtNuoh4Z195JbM37ecbF2aSmpToWY7mjNBfAa497bUfAJ865wYCn9Z/HHFmxl2j+7K2\nsEw3R0XEMzNX7qI24LhrdF9PczRZ6M65BcDB016+GXi1/tevAreEOVezff3CTFolJ/DG8gKvIohI\nHKupDTBzRSHjB3Yhq0sbT7Oc7Rx6N+fc3vpf7wManTQys4fMLNfMcktKSs7yco1LT0vmphE9+fOa\nPRzWk6MiEmFzNhWz73Ald4/xdnQOYbgp6uq2PWx060Pn3HTnXI5zLicjo2WenLp7TBbHq2uZpTNH\nRSTCZiwroEd6Ky4f0tXrKGdd6PvNrAdA/c/F4Yt05oZnpjMiM50Zy7WtrohEzs4DR1m0/QBTRvXx\n5MnQ051tgr8C36z/9TeBv4Qnztm7a0xfthcfYfnO06f7RURaxhvLCkhKqHtyPRo0Z9niW8BSYLCZ\nFZnZ/cDPgavMbBtwZf3HnrrxvJ6kpyXz+jLdHBWRlldZXcu7q4q45tzudG0f2W1yG5PU1Bucc1Ma\n+dQVYc4SkrSURL5xYSavLsmnuKKSru2i4xssIrHp/XV7KD9ezV1jIr9NbmO8n/QJo7tG96Em4HhH\n+7uISAubsXwX/TPaMLZfZ6+j/ENMFXq/jLaMG9CZN5fXLfIXEWkJXxSVs66wjKlj+mIWuTNDmxJT\nhQ5w95i+7Cmv5LPNni68EZEYNmNZAWnJidx6QabXUb4k5gr9ynO60a19KjN0c1REWkD58Wr+sm43\nN59ftxAjmsRcoSclJjD5oj4s2FZCQelRr+OISIyZtbqIyuoAU6PgydDTxVyhA0wZ1YcEM97ULowi\nEkbOOWYsK2BE7w4M65XudZyviMlC757eiqvO6cY7uYVUVuvwCxEJj6U7StlRcpSpo6NnqeKpYrLQ\nAe65uC+HjlXz17U6/EJEwuPlJfl0apPCjSN6eh2lQTFb6GP7dWZwt3a8vCRf+7uISMgKDx5jzqb9\nTBnVm1bJ3h1iEUzMFrqZcd+4LDbtPcwK7e8iIiF6bWk+CWbcPSbL6yiNitlCB7j5/F50aJ3My4vz\nvY4iIj52tKqGmSsLmTSsO93To3dbkZgu9LSURCZf1IdPNu6j6NAxr+OIiE/NWrObisoa7huX5XWU\noGK60AHuHlv3aO7rS/WgkYicOeccryzeyXmZ6VzQp6PXcYKK+ULv1SGNa87txlsrdnHsRI3XcUTE\nZxZuO8COkqPce3FWVO3b0pCYL3SA+8Zlc7iyhj+v0RJGETkzryzJp0vbVK4/r4fXUZoUF4We07cj\n5/ZszytLdmoJo4g0284DR/lsczF3je5DalJ0LlU8VVwUuplx78VZbN1/hCU7Sr2OIyI+8eqSfJIT\nLaoOsQgmLgod4MYRPencJoWXF+/0OoqI+EBFZTXvrSrihvN6+uYEtLgp9FbJidw5ug+fbi7WLowi\n0qQ/ririSFUN916c5XWUZoubQgeYOqYviWa8piWMIhJEIOB4dWkBI/t0YETvDl7Haba4KvRu7Vtx\n3fAevLOykCNVWsIoIg2bv7WEnQeOct+4bK+jnJG4KnSAe8dlUVFVw3u5OkhaRBr20uKddGufyqRh\n3b2OckbirtBH9u7AyD4deGlxvg6SFpGv2LT3MAu3HeCesVkkJ/qrIkNKa2aPm9kGM1tvZm+ZWdTf\nCjYzHhrfj10Hj/HJhn1exxGRKPPiwp20Tknkrig9xCKYsy50M+sF/CuQ45wbBiQCk8MVrCVdfW53\n+nRqze8X5OlBIxH5h33llfx13W5uz+lNh9YpXsc5Y6H+eyIJSDOzJKA14Itn6xMTjAfGZ7O2sIxV\nBYe8jiMiUeKVJXVTsfdf4q+boSeddaE753YDvwB2AXuBcufcJ+EK1tK+cWEmHVonM31BntdRRCQK\nHKmq4Y3lBUwa1oPenVp7HeeshDLl0hG4GcgGegJtzGxqA+97yMxyzSy3pKTk7JOGWeuUJO4e05fZ\nm/aTV3LE6zgi4rG3VxZSUVnDA+P9OTqH0KZcrgR2OudKnHPVwCzg4tPf5Jyb7pzLcc7lZGRkhHC5\n8LtnbBbJCQn8YZG2AxCJZzW1AV5atJNRWZ0YGeV7ngcTSqHvAsaYWWur2yT4CmBTeGJFRka7VG69\noBfvrSqi9EiV13FExCMfrd/H7rLjPHhpP6+jhCSUOfTlwHvAauCL+q81PUy5IuaB8dlU1QR4fZm2\nAxCJR845pi/YQb8ubbhiSFev44QkpFUuzrknnXNDnHPDnHN3O+d8N8wd0LUdVwzpyutLC6isrvU6\njohE2LK8g6zffZgHxvcjISG6TyRqir8eg2ohD17aj9KjJ5i1erfXUUQkwl5YmEfnNincekEvr6OE\nTIUOjM7uxHmZ6by4MI+AtgMQiRvb9lfw2eZi7hmbRavk6D+RqCkqdOq2A3hwfD/yDhzl083FXscR\nkQh5ceFOUpMSuHtsX6+jhIUKvd6kYd3p1SGN6Qt2eB1FRCKguKKSP63ZzW05mXRq47/H/BuiQq+X\nlJjA/ZdkszL/ELn5B72OIyIt7KVF+VQHAtx/ib+XKp5KhX6KyaN606lNCr+dp1G6SCwrP1bNjGUF\nXD+8B9ld2ngdJ2xU6KdonZLEt8Zl8dnmYjbsKfc6joi0kNeW5nOkqoaHJw7wOkpYqdBPc/fYLNqm\nJvG8RukiMenYiRpeWryTy4d0ZWjP9l7HCSsV+mnS05K5e2xfPvxirzbtEolBb60o5NCxah65rL/X\nUcJOhd6Ab43LJiUxgd/P19a6IrGkqqaWFxbkMTq7Exf27eR1nLBToTcgo10qky/qzaw1RewpO+51\nHBEJkz+t3s2+w5U8cllszZ2fpEJvxIOX9sO5useCRcT/amoDPD9/B8N7pTN+YBev47QIFXojMju2\n5paRvXhrxS4OaGtdEd/7aP0+CkqP8chlA6jb8Tv2qNCD+KcJ/amqCfDyYh2AIeJngYDjt3O3M6Br\nW64e2s3rOC1GhR7EgK5tmTSsO68tKeBwZbXXcUTkLH22uZjN+yp4eGJ/32+RG4wKvQkPTxxARVUN\nry/VARgifuSc43/mbiezYxo3jujpdZwWpUJvwrBe6UwYlMFLi3Zy/IQOwBDxm6V5pawtLOPbE/qT\nnBjblRfb/+vC5JHLBlB69AQzV+7yOoqInKHn5m6nS9tUbrsw0+soLU6F3gyjsjsxKrsTz8/boWPq\nRHxkZf5BFm8v5duX9ouJAyyaokJvpsevHERxRRVvLtcoXcQvfj17K13apjJ1TGwcYNEUFXozje3f\nmTH9OvH8fI3SRfxgeV4pS3aU8k8T+pGWEvujc1Chn5HHrxxESUUVM5ZpxYtItHtmzjYy2sXP6BxU\n6GdkdL/OXNy/M7+bn6cVLyJRbFleKUvzSvnnCf3jYu78pJAK3cw6mNl7ZrbZzDaZ2dhwBYtWj105\niANHNEoXiWa/nr2Vru1SuXN0H6+jRFSoI/Rngb8754YAI4BNoUeKbqOyOzFuQGd+N38Hx07UeB1H\nRE6zZMcBlu88yD9PjK/ROYRQ6GaWDlwK/AHAOXfCOVcWrmDR7PErB1F69ISeHhWJMs45npm9jW7t\nU5kyKr5G5xDaCD0bKAFeNrM1ZvaimcXOaatB5GR1YvzALvx+QR5HqzRKF4kWS3aUsiL/IA9PHBB3\no3MIrdCTgAuA551zI4GjwA9Of5OZPWRmuWaWW1JSEsLlostjVw7i4NETvKZRukhUcM7x69lb6d6+\nFXdc1NvrOJ4IpdCLgCLn3PL6j9+jruC/xDk33TmX45zLycjICOFy0eXCvh25dFAG0xfs4IhG6SKe\nW7T9ALkFh3jksvibOz/prAvdObcPKDSzwfUvXQFsDEsqn3j8yoEcOlbNq0vyvY4iEtdOjs57prfi\n9jgdnUPoq1z+BXjDzD4Hzgd+Gnok/xjZpyMTB2fwwsI8KrRfuohnFmw7wOpdZTx82QBSk+JzdA4h\nFrpzbm39dMp5zrlbnHOHwhXML/7PVYMoO1bNCwt1qpGIFwIBx9MfbyazYxq358Tv6Bz0pGjIzsvs\nwKRh3fnDwjxKdfaoSMT9bf0+1u8+zONXDiIlKb4rLb7/14fJd68ezPHqWp6bu8PrKCJxpaY2wC8/\n2cKgbm25ZWQvr+N4ToUeBgO6tuUbF2YyY1kBu8uOex1HJG68t6qIvANH+d7Vg0mM4bNCm0uFHibf\nuXIQAM/O2epxEpH4UFldy7OfbmNknw5cNbSb13Giggo9THp1SGPqmL68t6qI7cUVMHGi15FEYtqM\nZQXsLa/kiWsGY6bROajQw+qRy/qTlpzILz/ZCvPnex1HJGZVVFbz3NztjB/YhYv7d/E6TtRQoYdR\n57apPDY4jduf/HbdC1lZnuYRiVUvLNzJoWPVfP+aIV5HiSpJXgeIKRMn8uCpI/OCAjCDCRNg3jzP\nYonEkuLDlby4MI/rh/dgeGa613GiikboIuIrv56zjeraAE9cM7jpN8cZFXo4zZsHfRs4v3D+fE2/\niITBtv0VvL1yF3eN7ktWl7jYrfuMqNDDrbHiVqGLhOznf9tMm5Qk/vWKgV5HiUoq9HDTKF2kRSzd\nUcqnm4t5+LIBdGqT4nWcqKRCbwkapYuEVSDg+NnfNtEzvRX3jcvyOk7UUqG3BI3SRcLq/c/38HlR\nOd+7ZnDcHl7RHCr0ltJYcRcUwLRpkUwi4muV1bU8/fEWhvZozy3nawOuYFToLWXevLr15419TkSa\n5aXFOyk6dJx/v/4cErQBV1Aq9JbU2H4u8+drrxeRZig+XMlzn23nqqHdGDdAj/g3RYXekqZNa3gu\nHSA/P5JJRHzpF59s4URtgH+77hyvo/iCCr2l5ec3XOoFBbpBKhLE+t3lvLuqiPvGZZOth4iaRYUe\nCVrGKHJGnHM89f4GOrVO4dHLB3gdxzdU6JGgZYwiZ+TDL/ayMv8Q3716MO1bJXsdxzdU6JGiZYwi\nzVJZXcvPPtrMOT3ac8dFvb2O4ysq9EhpbJQO8MorkUwiEtV+Pz+P3WXH+Y8bztE5oWdIhR5J997b\n8OsFBVrGKAIUHjzGb+dt5/rhPXQS0VkIudDNLNHM1pjZB+EIFNO0jFEkqB9/sJEEM/79ei1TPBvh\nGKF/B9gUhq8TH7SMUaRBczcXM3vjfv71ioH07JDmdRxfCqnQzSwTuB54MTxx4oRukIp8SWV1LdPe\n30C/jDbcf0m213F8K9QR+jPA94FAY28ws4fMLNfMcktKSkK8XIzQDVKRL3lhQR4Fpcd46qZzSUnS\nrb2zddbfOTO7ASh2zq0K9j7n3HTnXI5zLicjI+NsLxd7dINUBKi7EfrcvO1MGtad8QPVEaEI5a/C\nccBNZpYPzAQuN7MZYUkVD3SDVASouxFqGP/vhqFeR/G9sy5059wPnXOZzrksYDLwmXNuatiSxYP8\nfEhP/+rrBQXQoUPE44hE2scb9v3jRmgv3QgNmSarvHb++Q2/Xl6uG6QS045U1fDkXzYwpHs7Hhiv\nG6HhEJZCd87Nc87dEI6vFXd0g1Ti1C8/2cL+ikp+eutwkhM1tgwHfRejgW6QSpz5vKiMV5fkM3V0\nXy7o09HrODFDhR4Ngt0gnT9fUy8SU2pqA/xw1hd0aZvKE9cO9jpOTFGhR4vGniAFTb1ITHllST4b\n9hxm2k3namvcMFOhR5NgT5Bq6kViQOHBY/xq9lYuH9KVScO6ex0n5qjQo0mwG6Ramy4+55zjh7O+\nwIAf33wuZtoaN9xU6NFGa9MlRr29spBF2w/ww+vOIbNja6/jxCQVejTS2nSJMXvLj/OfH25iTL9O\n3Dmqj9dxYpYKPRrNm9fwKB3gmWciGkUkVM45/m3WF1QHAvzX188jQacQtRgVerQqK2u41MvLNfUi\nvvKnNbuZu6WEJ64ZQt/ObbyOE9NU6NEs2NSLVr2IDxRXVPLU+xu5sG9H7r04y+s4MU+FHs206kV8\n7ORUy/HqWv7r6+fpwOcIUKFHu2DbAujIOoli7+QWMmdTMd+/ZjADurb1Ok5cUKFHu2nTYMKEhj+n\nB44kSu0qPcaP39/I2H6d+dY47aQYKSp0Pwi26mXZsohGEWlKbcDxvXfXkWDGL24foVUtEaRC94uy\nMkhN/errVVVa9SJR5cWFeazIP8i0m87VoRURpkL3kzFjGn69vFzz6RIVNu09zC8/2co153bj1gt6\neR0n7qjQ/STYqpeCAj1FKp6qrK7l8bfX0j4tmZ9+bbj2avGACt1vGtvrBfQUqXjqZx9tYvO+Cp6+\n7Tw6t21gelBanArdjx57rOHX9RSpeOSTDft4dWkBD1ySzWWDu3odJ26p0P0o2FJGPUUqEba3/Djf\n/+PnDOvVXicQeUyF7lfz5jW86gVgwYKIRpH4VRtwPDZzLSdqAvxmygWkJiV6HSmuqdD9rLKy4VJ3\nTlMvEhHPzd3O8p0H+cnNw8juoo23vKZC9zstZRSPLMsr5Zk5W/nayF58/cJMr+MIIRS6mfU2s7lm\nttHMNpjZd8IZTJqpqaWMmk+XFlB8uJJH31xDVpc2/OSWYV7HkXpJIfzeGuC7zrnVZtYOWGVms51z\nG8OUTZorPx9atap7avR0mk+XMKupDfDoW2s4WlXDmw+Opm1qKDUi4XTWI3Tn3F7n3Or6X1cAmwA9\nGuaVykpo6EEO5+rKXiRMnv54Cyt2HuRntw5nULd2XseRU4RlDt3MsoCRwPJwfD05Sz/6UcOva78X\nCZO/r9/H7xfkMXVMH24ZqfFbtAm50M2sLfBH4DHn3OEGPv+QmeWaWW5JSUmol5Ngpk1rfD5d69Ml\nRPkHjvLEu+sYkZnOf9ww1Os40oCQCt3Mkqkr8zecc7Maeo9zbrpzLsc5l5ORkRHK5aQ58vMbX58+\nf35Eo0jsqKis5sHXcklMNJ67S+vNo1Uoq1wM+AOwyTn3q/BFkpA1Np8Ojb8u0ohAwPH422vJO3CU\n3955AZkdW3sdSRoRygh9HHA3cLmZra3/cV2YckmoAoHGP5egxw+k+X41eytzNhXzoxuGcvGALl7H\nkSDOer2Rc24RoOFeNJswoeFplpNPkpaVRT6T+MoHn+/hf+ZuZ/JFvblnbCP3ZyRqaKgWy4I9dKQn\nSaUJ63eX871315HTtyM/vnmY9jf3ARV6rAu2f7qeJJVG7D9cyYOv5dKpdQrPT72QlCRVhR/o/6V4\nEGxqRStf5DRHqmq47+WVHD5ezQvfzCGjnQ6r8AsVerxwrvHP6Z/SUq+mNsCjb65my/4KnrvrAs7t\n2ci/7iQqqdDjyZNPNv45lXrcc87xo79uYN6WEn5y8zAm6uQh31Ghx5Np01Tq0qjfL8jjzeW7+OeJ\n/blzdB+v48hZUKHHm2DbAwAkaee8ePSnNUX8/G+buXFET564WsfI+ZUKPR4F2x6gtla7M8aZORv3\n8713P+fi/p15+hvnkZCgf6n5lQo9XjV2fB3U7c6oUo8LS3eU8vCbqxnWsz3T78mhVbL2aPEzFXo8\nq6xs/HNVVXrwKMZ9UVTOg6/l0rdTa165b5QOqogBKvR4F2w5Y0GBSj1GbS8+wjdfXkF6WjKv3z+a\njm1SvI4kYaBCF5V6nNlRcoQ7X1hGghkzHhhN93RNr8UKFbrUUanHhR0lR5gyfRkB53jrwdFkd2nj\ndSQJIxW6/C+VekzL+1KZj2GgzgONOSp0+bKmSl1nk/pSXskRJk9fRm3A8abKPGap0OWrgpV6ebke\nPvKZzfsOc0d9mb/10BgGqcxjlgpdGhas1GtrVeo+sargELf/bikJBjNV5jFPfyqlcc41vr9LbW3d\n54IVv3hqwdYSvv36Krq1T+X1+0fTu5POAo11KnQJLlipg0o9Sn34+V4ee3sNA7u249VvjdKe5nFC\nhS5NU6n7hnOOlxfn85MPN5LTtyMvfvMi0tOSvY4lEaI5dGmepgrbTMfZeaymNsCP/rKBH3+wkauH\nduO1b41WmccZjdCl+Zoaqc+fX7esMdiRd9IiKiqrefTNNczfWsK3L+3H/712iHZNjEMqdDkzTZV6\neTkkJEAgELlMca7o0DHufyWX7SVH+Nmtw5kySodTxKuQplzM7Foz22Jm283sB+EKJVHOOUgMss1q\nU6UvYbNwWwk3/mYRe8qO8+p9o1Tmce6sC93MEoHngEnAUGCKmQ0NVzCJcjU1kN7EAcJm2le9hQQC\njufmbueel1aQ0S6Vvzw6jksGdvE6lngslCmXUcB251wegJnNBG4GNoYjmPhAWVnd/i4FBY2/p6pK\nq2DCrPx4Nd99Zy1zNhVz04ie/Pzrw2mdotlTCW3KpRdQeMrHRfWvSTzJzw9+8PRJWgUTFqt3HeLG\n3yxi3pYSnrxxKM9OPl9lLv/Q4ssWzewhM8s1s9ySkpKWvpx4Ydq05o3A58/X3PpZqqkN8OvZW7nt\nd0upDTje/vYY7huXjen7KacI5a/23UDvUz7OrH/tS5xz04HpADk5Ofp3dyxzrm6FS3PWrKena3lj\nM+UfOMpjb69lbWEZt47sxbSbz6V9K60vl68KpdBXAgPNLJu6Ip8M3BmWVOJfgUDdWvTy8uDvKy/X\n3HoTagOO15fm8/THW0hMMH4zZSQ3jujpdSyJYmdd6M65GjN7FPgYSARecs5tCFsy8a+TI+/mTAec\nfI+K/Us27T3MD2Z9wbrCMi4dlMHPbx1Ozw5pXseSKBfS3RTn3EfAR2HKIrGmuVMwUFfsZnH/QNLx\nE7U8++k2XliYR4e0ZJ6dfD43jeipuXJpFt0el5YVCDS9tPGkkw8kJSbWrXOPI4GA489rd/P0x1vY\nW17JHTm9+eF1Q+jQOsXraOIjKnRpefn5dT83d5R5cq91iIupmKU7SvnPjzayfvdhhvdK59nJIxmV\n3cnrWOJDKnSJHOeaP1o/KYaLfV1hGf/96TY+3VxMz/RWPHNH3fSKNtWSs6VCl8g609H6SSffP2EC\nzJsXzkQRtzyvlP+Zu52F2w6QnpbME9cM5v5LsmmVHGR/HJFmUKGLN5yreyDpqafO7Ped+nCSj0bt\n1bUB5mzcz8uL81mRf5AubVP4waQhTB3Tl7ap+mMo4WEugn8ocnJyXG5ubsSuJz7RqlXdni+hiNJy\n31N2nJkrdjFzZSHFFVX06pDGg+OzmTyqj0bk0mxmtso5l9PU+zQ0EO9VVtb9HMrSvNN/r4cFX3bs\nBJ9s3M+Hn+9l4bYSHDBxUAY/Hd2Xy4Z0JVFz5NJCVOgSPU6WcDjWXDf2NVqo6IsOHWPRtgP8bf0+\nFm8/QE3AkdkxjX+a0J8po/rQu1PrFrmuyKlU6BJ9wlnspwv2NZtZ9oGAo/DQMdYVlbN0xwEWby9l\n18FjAGR2TOP+8dlcP7wHw3ul64EgiSgVukSvkwXb3KdNwygQcJQePcHe8uPsKatkX/lx8g4cZeOe\nw2zae5ijJ2oBaJeaxOh+nblvXBZj+3dmcLd2KnHxjApdot+p2wG0YFlO/PHfOGxJVFbXcry69it/\nh7RNTeKcHu34xoWZnNOjPef2TOecHu1ISmzxXahFmkWFLv5ysmWbs6PjGZr35HV1lwB+9fFmMtql\n0r19K3p2SKN7eis6t0nR6Fuimgpd/On0vdTDUbT1f1kY8N3Qv5pIxOnfihIbnPvfH805Ek8kBqnQ\nJfacPBLv9B8iMU5TLhI/VOoS4zRCFxGJESp0EZEYoUIXEYkRKnQRkRihQhcRiRER3Q/dzEqAMzh/\n7Eu6AAfCGKel+Smvn7KCv/L6KSv4K6+fskJoefs65zKaelNECz0UZpbbnA3eo4Wf8vopK/grr5+y\ngr/y+innjLjFAAADbklEQVQrRCavplxERGKECl1EJEb4qdCnex3gDPkpr5+ygr/y+ikr+Cuvn7JC\nBPL6Zg5dRESC89MIXUREgvBVoZvZbWa2wcwCZhaVd7fN7Foz22Jm283sB17nCcbMXjKzYjNb73WW\npphZbzOba2Yb6/8b+I7XmYIxs1ZmtsLM1tXnfcrrTE0xs0QzW2NmH3idpSlmlm9mX5jZWjPL9TpP\nMGbWwczeM7PNZrbJzMa21LV8VejAeuBWYIHXQRpiZonAc8AkYCgwxcyGepsqqFeAa70O0Uw1wHed\nc0OBMcAjUf69rQIud86NAM4HrjWzMR5nasp3gE1ehzgDlznnzvfB0sVngb8754YAI2jB77GvCt05\nt8k5t8XrHEGMArY75/KccyeAmcDNHmdqlHNuAXDQ6xzN4Zzb65xbXf/rCur+UPTyNlXjXJ0j9R8m\n1/+I2htWZpYJXA+86HWWWGJm6cClwB8AnHMnnHNlwX/X2fNVoftAL6DwlI+LiOLS8SszywJGAsu9\nTRJc/RTGWqAYmO2ci+a8zwDfBwJNvTFKOGCOma0ys4e8DhNENlACvFw/nfWimbVpqYtFXaGb2Rwz\nW9/Aj6gd6UrkmFlb4I/AY865w17nCcY5V+ucOx/IBEaZ2TCvMzXEzG4Aip1zq7zOcgYuqf/eTqJu\n+u1SrwM1Igm4AHjeOTcSOAq02L21qDuxyDl3pdcZQrAb6H3Kx5n1r0kYmFkydWX+hnNultd5mss5\nV2Zmc6m7XxGNN6DHATeZ2XVAK6C9mc1wzk31OFejnHO7638uNrM/UTfdGY331oqAolP+dfYeLVjo\nUTdC97mVwEAzyzazFGAy8FePM8UEMzPq5iE3Oed+5XWepphZhpl1qP91GnAVsNnbVA1zzv3QOZfp\nnMui7r/Zz6K5zM2sjZm1O/lr4Gqi8y9KnHP7gEIzG1z/0hXAxpa6nq8K3cy+ZmZFwFjgQzP72OtM\np3LO1QCPAh9Td9PuHefcBm9TNc7M3gKWAoPNrMjM7vc6UxDjgLuBy+uXqq2tH1FGqx7AXDP7nLq/\n6Gc756J+OaBPdAMWmdk6YAXwoXPu7x5nCuZfgDfq/1s4H/hpS11IT4qKiMQIX43QRUSkcSp0EZEY\noUIXEYkRKnQRkRihQhcRiREqdBGRGKFCFxGJESp0EZEY8f8BU8VcmTG+cWEAAAAASUVORK5CYII=\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "eta = 0.001\n", + "theta_history = []\n", + "gradient_descent(0, eta)\n", + "plot_theta_history()" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3682" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(theta_history)" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "eta = 0.8\n", + "theta_history = []\n", + "gradient_descent(0, eta)\n", + "plot_theta_history()" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [ + { + "ename": "OverflowError", + "evalue": "(34, 'Result too large')", + "output_type": "error", + "traceback": [ + "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m", + "\u001B[0;31mOverflowError\u001B[0m Traceback (most recent call last)", + "\u001B[0;32m\u001B[0m in \u001B[0;36m\u001B[0;34m()\u001B[0m\n\u001B[1;32m 1\u001B[0m \u001B[0meta\u001B[0m \u001B[0;34m=\u001B[0m \u001B[0;36m1.1\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[1;32m 2\u001B[0m \u001B[0mtheta_history\u001B[0m \u001B[0;34m=\u001B[0m \u001B[0;34m[\u001B[0m\u001B[0;34m]\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[0;32m----> 3\u001B[0;31m \u001B[0mgradient_descent\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0;36m0\u001B[0m\u001B[0;34m,\u001B[0m \u001B[0meta\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[0m", + "\u001B[0;32m\u001B[0m in \u001B[0;36mgradient_descent\u001B[0;34m(initial_theta, eta, epsilon)\u001B[0m\n\u001B[1;32m 11\u001B[0m \u001B[0mtheta_history\u001B[0m\u001B[0;34m.\u001B[0m\u001B[0mappend\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0mtheta\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[1;32m 12\u001B[0m \u001B[0;34m\u001B[0m\u001B[0m\n\u001B[0;32m---> 13\u001B[0;31m \u001B[0;32mif\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0mabs\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0mJ\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0mtheta\u001B[0m\u001B[0;34m)\u001B[0m \u001B[0;34m-\u001B[0m \u001B[0mJ\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0mlast_theta\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m)\u001B[0m \u001B[0;34m<\u001B[0m \u001B[0mepsilon\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m:\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[0m\u001B[1;32m 14\u001B[0m \u001B[0;32mbreak\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[1;32m 15\u001B[0m \u001B[0;34m\u001B[0m\u001B[0m\n", + "\u001B[0;32m\u001B[0m in \u001B[0;36mJ\u001B[0;34m(theta)\u001B[0m\n\u001B[1;32m 1\u001B[0m \u001B[0;32mdef\u001B[0m \u001B[0mJ\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0mtheta\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m:\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[0;32m----> 2\u001B[0;31m \u001B[0;32mreturn\u001B[0m \u001B[0;34m(\u001B[0m\u001B[0mtheta\u001B[0m\u001B[0;34m-\u001B[0m\u001B[0;36m2.5\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m**\u001B[0m\u001B[0;36m2\u001B[0m \u001B[0;34m-\u001B[0m \u001B[0;36m1.\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[0m\u001B[1;32m 3\u001B[0m \u001B[0;34m\u001B[0m\u001B[0m\n\u001B[1;32m 4\u001B[0m \u001B[0;32mdef\u001B[0m \u001B[0mdJ\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0mtheta\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m:\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[1;32m 5\u001B[0m \u001B[0;32mreturn\u001B[0m \u001B[0;36m2\u001B[0m\u001B[0;34m*\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0mtheta\u001B[0m\u001B[0;34m-\u001B[0m\u001B[0;36m2.5\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n", + "\u001B[0;31mOverflowError\u001B[0m: (34, 'Result too large')" + ] + } + ], + "source": [ + "eta = 1.1\n", + "theta_history = []\n", + "gradient_descent(0, eta)" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def J(theta):\n", + " try:\n", + " return (theta-2.5)**2 - 1.\n", + " except:\n", + " return float('inf')" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def gradient_descent(initial_theta, eta, n_iters = 1e4, epsilon=1e-8):\n", + " \n", + " theta = initial_theta\n", + " i_iter = 0\n", + " theta_history.append(initial_theta)\n", + " # 控制迭代次数。 \n", + " while i_iter < n_iters:\n", + " gradient = dJ(theta)\n", + " last_theta = theta\n", + " theta = theta - eta * gradient\n", + " theta_history.append(theta)\n", + " \n", + " if(abs(J(theta) - J(last_theta)) < epsilon):\n", + " break\n", + " \n", + " i_iter += 1\n", + " \n", + " return" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "eta = 1.1\n", + "theta_history = []\n", + "gradient_descent(0, eta)" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "10001" + ] + }, + "execution_count": 45, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(theta_history)" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n8pyCXkQkz/1/CxE6FcrtP+EAAAAASUVORK5CYII=\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "eta = 1.1\n", + "theta_history = []\n", + "gradient_descent(0, eta, n_iters=10)\n", + "plot_theta_history()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/machinelearning/gradientDescent/02-ImplementGradientDescentInLinearRegression/02-ImplementGradientDescentInLinearRegression.ipynb b/machinelearning/gradientDescent/02-ImplementGradientDescentInLinearRegression/02-ImplementGradientDescentInLinearRegression.ipynb new file mode 100644 index 0000000..723aa74 --- /dev/null +++ b/machinelearning/gradientDescent/02-ImplementGradientDescentInLinearRegression/02-ImplementGradientDescentInLinearRegression.ipynb @@ -0,0 +1,413 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 在线性回归模型中使用梯度下降法" + ] + }, + { + "cell_type": "code", + "metadata": { + "collapsed": true, + "ExecuteTime": { + "end_time": "2024-08-25T12:21:51.535409Z", + "start_time": "2024-08-25T12:21:51.167840Z" + } + }, + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt" + ], + "outputs": [], + "execution_count": 1 + }, + { + "cell_type": "code", + "metadata": { + "collapsed": true, + "ExecuteTime": { + "end_time": "2024-08-25T12:21:53.462001Z", + "start_time": "2024-08-25T12:21:53.432907Z" + } + }, + "source": [ + "np.random.seed(666)\n", + "# x是100个 数组\n", + "x = 2 * np.random.random(size=100)\n", + "# 截距是4,theta是3 , y 也是100个值的数组\n", + "y = x * 3. + 4. + np.random.normal(size=100)" + ], + "outputs": [], + "execution_count": 2 + }, + { + "cell_type": "code", + "metadata": { + "collapsed": true, + "ExecuteTime": { + "end_time": "2024-08-25T12:22:31.331770Z", + "start_time": "2024-08-25T12:22:31.326773Z" + } + }, + "source": [ + "X = x.reshape(-1, 1)" + ], + "outputs": [], + "execution_count": 3 + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2024-08-25T12:26:33.155828Z", + "start_time": "2024-08-25T12:26:33.149562Z" + } + }, + "source": "X[:20]", + "outputs": [ + { + "data": { + "text/plain": [ + "array([[1.40087424],\n", + " [1.68837329],\n", + " [1.35302867],\n", + " [1.45571611],\n", + " [1.90291591],\n", + " [0.02540639],\n", + " [0.8271754 ],\n", + " [0.09762559],\n", + " [0.19985712],\n", + " [1.01613261],\n", + " [0.40049508],\n", + " [1.48830834],\n", + " [0.38578401],\n", + " [1.4016895 ],\n", + " [0.58645621],\n", + " [1.54895891],\n", + " [0.01021768],\n", + " [0.22571531],\n", + " [0.22190734],\n", + " [0.49533646]])" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 13 + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2024-08-25T12:24:30.836663Z", + "start_time": "2024-08-25T12:24:30.831399Z" + } + }, + "source": "y[:20]", + "outputs": [ + { + "data": { + "text/plain": [ + "array([8.91412688, 8.89446981, 8.85921604, 9.04490343, 8.75831915,\n", + " 4.01914255, 6.84103696, 4.81582242, 3.68561238, 6.46344854,\n", + " 4.61756153, 8.45774339, 3.21438541, 7.98486624, 4.18885101,\n", + " 8.46060979, 4.29706975, 4.06803046, 3.58490782, 7.0558176 ])" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 11 + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2024-08-25T12:24:54.980016Z", + "start_time": "2024-08-25T12:24:54.884883Z" + } + }, + "source": [ + "plt.scatter(x, y)\n", + "plt.show()" + ], + "outputs": [ + { + "data": { + "text/plain": [ + "
" + ], + "image/png": "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/w5TqZQ++OADV977trn77rt18OBBff7zn888Nm3aNK1Zs0abNm3SqlWr1NbWpk9+8pPq6uoKcE9L09DQoHvvvVePPfaYHnvsMTU2NuqSSy5RS0uLJHc+v2zy9ttv61e/+tWgf4e2nsPe3l4tXrxYF154oSZPnpx3OxuuidZ1tUVlli9frvXr12vz5s1ZCZlXX3115v/POussnX322Zo4caI2b96syy67LIhddWT69OmaPn165vsLLrhAZ5xxhu677z7dcccdAe6ZN+6//36dddZZmjp1atbjYT+PcfLwww9r6dKl2rhxY1ZOxOzZszP/f/bZZ2vatGmaMGGCHnnkEX3pS18KYldLdtppp+m0007LfH/BBRdoz549uueee/Tv//7vAe6ZNx588EGNHDlSV155Zdbjtp7DRYsWqbW1NbD8EydCN/IxZswYVVdX65133sl6/J133lF9fX3O36mvry+4ffq/Tp7TK+UcX9rdd9+t5cuX69e//rXOPvvsgtuecsopGjNmjHbv3l3xPjtVyTGmDRkyROeee25m/206h1Jlx3jo0CGtX7++pA+xIM+jU/n+HdbV1WnYsGGuvC9ssX79el1//fV65JFHBg1vDzRy5Eh99KMfDcU5zGXq1KmZfY/SOTTG6Mc//rGuvfZaDR06tOC2NpzDr371q/rP//xPPffcczrxxBMLbmvDNTF0wcfQoUP1sY99TM8880zmsd7eXj3zzDNZd8b9TZ8+PWt7SXrqqacy2zc1Nam+vj5rm1QqpVdeeSXvc3qlnOOT+jKT77jjDm3atEnnn39+0b/z5z//Wfv371dDQ4Mr++1EucfYX09Pj3bs2JHZf5vOoVTZMT766KPq7u7WggULiv6dIM+jU8X+HbrxvrDBunXr9MUvflHr1q3LWiadz8GDB7Vnz55QnMNctm/fntn3qJxDqW8Vye7du0u6CQjyHBpj9NWvflUbNmzQs88+q6ampqK/Y8U10ZW0VZ+tX7/e1NTUmDVr1pidO3ear3zlK2bkyJGmo6PDGGPMtddea26++ebM9i+99JI55phjzN13321ef/11s2TJEjNkyBCzY8eOzDbLly83I0eONBs3bjT/9V//ZebNm2eamprMBx98YP3xLV++3AwdOtT8x3/8h2lvb898dXV1GWOM6erqMv/4j/9ompubTVtbm3n66afNeeedZ0499VRz5MgR34+vnGNcunSpefLJJ82ePXvMq6++aq6++mpTW1trfve732W2sekcGuP8GNMuuugic9VVVw163Lbz2NXVZbZt22a2bdtmJJnvfve7Ztu2beZPf/qTMcaYm2++2Vx77bWZ7f/4xz+aY4891vzTP/2Tef31183KlStNdXW12bRpU2abYq+Z35we40MPPWSOOeYYs3Llyqx/iwcOHMhs881vftNs3rzZtLW1mZdeesnMmDHDjBkzxuzbt8/647vnnnvM448/bnbt2mV27NhhbrjhBlNVVWWefvrpzDZhP4dpCxYsMNOmTcv5nDadw4ULF5pkMmk2b96c9Z47fPhwZhsbr4mhDD6MMeYHP/iBOemkk8zQoUPN1KlTzZYtWzI/u/jii811112Xtf0jjzxiPvrRj5qhQ4eaM8880/ziF7/I+nlvb6+59dZbzbhx40xNTY257LLLzBtvvOHHoeTk5PgmTJhgJA36WrJkiTHGmMOHD5vLL7/cHH/88WbIkCFmwoQJ5stf/nJgHwZpTo5x8eLFmW3HjRtn/vZv/9a0tLRkPZ9t59AY5+/T3//+90aS+fWvfz3ouWw7j+lllwO/0sd03XXXmYsvvnjQ70yZMsUMHTrUnHLKKeaBBx4Y9LyFXjO/OT3Giy++uOD2xvQtL25oaDBDhw41J5xwgrnqqqvM7t27/T2w/+H0+FasWGEmTpxoamtrzahRo8wll1xinn322UHPG+ZzaEzfstJhw4aZH/3oRzmf06ZzmOvYJGX927Lxmpj4n50HAADwRehyPgAAQLgRfAAAAF8RfAAAAF8RfAAAAF8RfAAAAF8RfAAAAF8RfAAAAF8RfAAAAF8RfAAAAF8RfAAAAF8RfAAAAF8RfAAAAF/9fxVKDGDMLLIMAAAAAElFTkSuQmCC" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "execution_count": 12 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 使用梯度下降法训练" + ] + }, + { + "cell_type": "code", + "metadata": { + "collapsed": true, + "ExecuteTime": { + "end_time": "2024-08-25T12:41:39.021887Z", + "start_time": "2024-08-25T12:41:39.017169Z" + } + }, + "source": [ + "# 求均方差,mes , theta 是一个数组,X_b 是一个矩阵 ,n行i列, n=len(X_b)\n", + "def J(theta, X_b, y):\n", + " try:\n", + " return np.sum((y - X_b.dot(theta))**2) / len(X_b)\n", + " except:\n", + " # 异常则给 浮点数中的最大值\n", + " return float('inf')" + ], + "outputs": [], + "execution_count": 14 + }, + { + "cell_type": "code", + "metadata": { + "collapsed": true, + "ExecuteTime": { + "end_time": "2024-08-25T12:41:41.230095Z", + "start_time": "2024-08-25T12:41:41.224505Z" + } + }, + "source": [ + "# 求导 (也就是损失值)\n", + "def dJ(theta, X_b, y):\n", + " res = np.empty(len(theta))\n", + " # 第0行特殊\n", + " res[0] = np.sum(X_b.dot(theta) - y)\n", + " for i in range(1, len(theta)):\n", + " # X_b[:,i] 代表, 第几列\n", + " res[i] = (X_b.dot(theta) - y).dot(X_b[:,i])\n", + " return res * 2 / len(X_b)" + ], + "outputs": [], + "execution_count": 15 + }, + { + "cell_type": "code", + "metadata": { + "collapsed": true, + "ExecuteTime": { + "end_time": "2024-08-25T12:41:43.556152Z", + "start_time": "2024-08-25T12:41:43.550315Z" + } + }, + "source": [ + "# 求梯度下降中的 最优theta \n", + "# initial_theta 初始化theta\n", + "# n_iters 迭代次数控制\n", + "# eta 学习率\n", + "# X_b 矩阵\n", + "# y 结果值\n", + "# epsilon 接受的误差值\n", + "def gradient_descent(X_b, y, initial_theta, eta, n_iters = 1e4, epsilon=1e-8):\n", + " \n", + " theta = initial_theta\n", + " cur_iter = 0\n", + "\n", + " while cur_iter < n_iters:\n", + " gradient = dJ(theta, X_b, y)\n", + " last_theta = theta\n", + " theta = theta - eta * gradient\n", + " if(abs(J(theta, X_b, y) - J(last_theta, X_b, y)) < epsilon):\n", + " break\n", + " \n", + " cur_iter += 1\n", + "\n", + " return theta" + ], + "outputs": [], + "execution_count": 16 + }, + { + "cell_type": "code", + "metadata": { + "collapsed": true, + "ExecuteTime": { + "end_time": "2024-08-25T12:47:06.578672Z", + "start_time": "2024-08-25T12:47:06.525801Z" + } + }, + "source": [ + "# 追加一列,截距处理 * 固定值1 ,x0=1 \n", + "X_b = np.hstack([np.ones((len(x), 1)), x.reshape(-1,1)])\n", + "print(X_b.shape[1]) # 2列, 本身只有一列,现在多了一列 截距\n", + "#初始化 theta 为2个0 \n", + "initial_theta = np.zeros(X_b.shape[1])\n", + "print(initial_theta)\n", + "# 学习率\n", + "eta = 0.01\n", + "theta = gradient_descent(X_b, y, initial_theta, eta)" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2\n", + "[0. 0.]\n" + ] + } + ], + "execution_count": 18 + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2024-08-25T12:48:43.623696Z", + "start_time": "2024-08-25T12:48:43.617543Z" + } + }, + "source": [ + "theta\n", + "# 4代表截距, 3代表 theta,这里只有一列" + ], + "outputs": [ + { + "data": { + "text/plain": [ + "array([4.02145786, 3.00706277])" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 19 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 封装我们的线性回归算法" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2024-08-25T12:49:32.276724Z", + "start_time": "2024-08-25T12:49:32.220813Z" + } + }, + "source": [ + "from playML.LinearRegression import LinearRegression\n", + "\n", + "lin_reg = LinearRegression()\n", + "lin_reg.fit_gd(X, y)" + ], + "outputs": [ + { + "data": { + "text/plain": [ + "LinearRegression()" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 20 + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2024-08-25T12:49:34.437813Z", + "start_time": "2024-08-25T12:49:34.431767Z" + } + }, + "source": [ + "lin_reg.coef_" + ], + "outputs": [ + { + "data": { + "text/plain": [ + "array([3.00706277])" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 21 + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2024-08-25T12:49:39.289223Z", + "start_time": "2024-08-25T12:49:39.284149Z" + } + }, + "source": [ + "lin_reg.intercept_" + ], + "outputs": [ + { + "data": { + "text/plain": [ + "np.float64(4.021457858204859)" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 22 + }, + { + "metadata": {}, + "cell_type": "code", + "outputs": [], + "execution_count": null, + "source": "" + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.4" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/machinelearning/gradientDescent/02-ImplementGradientDescentInLinearRegression/playML/LinearRegression.py b/machinelearning/gradientDescent/02-ImplementGradientDescentInLinearRegression/playML/LinearRegression.py new file mode 100644 index 0000000..2dd167b --- /dev/null +++ b/machinelearning/gradientDescent/02-ImplementGradientDescentInLinearRegression/playML/LinearRegression.py @@ -0,0 +1,88 @@ +import numpy as np +from .metrics import r2_score + +class LinearRegression: + + def __init__(self): + """初始化Linear Regression模型""" + self.coef_ = None + self.intercept_ = None + self._theta = None + + def fit_normal(self, X_train, y_train): + """根据训练数据集X_train, y_train训练Linear Regression模型""" + assert X_train.shape[0] == y_train.shape[0], \ + "the size of X_train must be equal to the size of y_train" + + X_b = np.hstack([np.ones((len(X_train), 1)), X_train]) + self._theta = np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y_train) + + self.intercept_ = self._theta[0] + self.coef_ = self._theta[1:] + + return self + + def fit_gd(self, X_train, y_train, eta=0.01, n_iters=1e4): + """根据训练数据集X_train, y_train, 使用梯度下降法训练Linear Regression模型""" + assert X_train.shape[0] == y_train.shape[0], \ + "the size of X_train must be equal to the size of y_train" + + def J(theta, X_b, y): + try: + return np.sum((y - X_b.dot(theta)) ** 2) / len(y) + except: + return float('inf') + + def dJ(theta, X_b, y): + res = np.empty(len(theta)) + res[0] = np.sum(X_b.dot(theta) - y) + for i in range(1, len(theta)): + res[i] = (X_b.dot(theta) - y).dot(X_b[:, i]) + return res * 2 / len(X_b) + + def gradient_descent(X_b, y, initial_theta, eta, n_iters=1e4, epsilon=1e-8): + + theta = initial_theta + cur_iter = 0 + + while cur_iter < n_iters: + gradient = dJ(theta, X_b, y) + last_theta = theta + theta = theta - eta * gradient + if (abs(J(theta, X_b, y) - J(last_theta, X_b, y)) < epsilon): + break + + cur_iter += 1 + + return theta + + # X_train追加截距 + X_b = np.hstack([np.ones((len(X_train), 1)), X_train]) + # 每个特征默认都给0的theta值 + initial_theta = np.zeros(X_b.shape[1]) + self._theta = gradient_descent(X_b, y_train, initial_theta, eta, n_iters) + # 截距 + self.intercept_ = self._theta[0] + # 所有参数的 因子 + self.coef_ = self._theta[1:] + + return self + + def predict(self, X_predict): + """给定待预测数据集X_predict,返回表示X_predict的结果向量""" + assert self.intercept_ is not None and self.coef_ is not None, \ + "must fit before predict!" + assert X_predict.shape[1] == len(self.coef_), \ + "the feature number of X_predict must be equal to X_train" + + X_b = np.hstack([np.ones((len(X_predict), 1)), X_predict]) + return X_b.dot(self._theta) + + def score(self, X_test, y_test): + """根据测试数据集 X_test 和 y_test 确定当前模型的准确度""" + + y_predict = self.predict(X_test) + return r2_score(y_test, y_predict) + + def __repr__(self): + return "LinearRegression()" diff --git a/machinelearning/gradientDescent/02-ImplementGradientDescentInLinearRegression/playML/SimpleLinearRegression.py b/machinelearning/gradientDescent/02-ImplementGradientDescentInLinearRegression/playML/SimpleLinearRegression.py new file mode 100644 index 0000000..a133e4d --- /dev/null +++ b/machinelearning/gradientDescent/02-ImplementGradientDescentInLinearRegression/playML/SimpleLinearRegression.py @@ -0,0 +1,47 @@ +import numpy as np +from .metrics import r2_score + + +class SimpleLinearRegression: + + def __init__(self): + """初始化Simple Linear Regression模型""" + self.a_ = None + self.b_ = None + + def fit(self, x_train, y_train): + """根据训练数据集x_train, y_train训练Simple Linear Regression模型""" + assert x_train.ndim == 1, \ + "Simple Linear Regressor can only solve single feature training data." + assert len(x_train) == len(y_train), \ + "the size of x_train must be equal to the size of y_train" + + x_mean = np.mean(x_train) + y_mean = np.mean(y_train) + + self.a_ = (x_train - x_mean).dot(y_train - y_mean) / (x_train - x_mean).dot(x_train - x_mean) + self.b_ = y_mean - self.a_ * x_mean + + return self + + def predict(self, x_predict): + """给定待预测数据集x_predict,返回表示x_predict的结果向量""" + assert x_predict.ndim == 1, \ + "Simple Linear Regressor can only solve single feature training data." + assert self.a_ is not None and self.b_ is not None, \ + "must fit before predict!" + + return np.array([self._predict(x) for x in x_predict]) + + def _predict(self, x_single): + """给定单个待预测数据x,返回x的预测结果值""" + return self.a_ * x_single + self.b_ + + def score(self, x_test, y_test): + """根据测试数据集 x_test 和 y_test 确定当前模型的准确度""" + + y_predict = self.predict(x_test) + return r2_score(y_test, y_predict) + + def __repr__(self): + return "SimpleLinearRegression()" diff --git a/machinelearning/gradientDescent/02-ImplementGradientDescentInLinearRegression/playML/__init__.py b/machinelearning/gradientDescent/02-ImplementGradientDescentInLinearRegression/playML/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/machinelearning/gradientDescent/02-ImplementGradientDescentInLinearRegression/playML/kNN.py b/machinelearning/gradientDescent/02-ImplementGradientDescentInLinearRegression/playML/kNN.py new file mode 100644 index 0000000..0b54a95 --- /dev/null +++ b/machinelearning/gradientDescent/02-ImplementGradientDescentInLinearRegression/playML/kNN.py @@ -0,0 +1,59 @@ +import numpy as np +from math import sqrt +from collections import Counter +from .metrics import accuracy_score + +class KNNClassifier: + + def __init__(self, k): + """初始化kNN分类器""" + assert k >= 1, "k must be valid" + self.k = k + self._X_train = None + self._y_train = None + + def fit(self, X_train, y_train): + """根据训练数据集X_train和y_train训练kNN分类器""" + assert X_train.shape[0] == y_train.shape[0], \ + "the size of X_train must be equal to the size of y_train" + assert self.k <= X_train.shape[0], \ + "the size of X_train must be at least k." + + self._X_train = X_train + self._y_train = y_train + return self + + def predict(self, X_predict): + """给定待预测数据集X_predict,返回表示X_predict的结果向量""" + assert self._X_train is not None and self._y_train is not None, \ + "must fit before predict!" + assert X_predict.shape[1] == self._X_train.shape[1], \ + "the feature number of X_predict must be equal to X_train" + + y_predict = [self._predict(x) for x in X_predict] + return np.array(y_predict) + + def _predict(self, x): + """给定单个待预测数据x,返回x的预测结果值""" + assert x.shape[0] == self._X_train.shape[1], \ + "the feature number of x must be equal to X_train" + + distances = [sqrt(np.sum((x_train - x) ** 2)) + for x_train in self._X_train] + nearest = np.argsort(distances) + + topK_y = [self._y_train[i] for i in nearest[:self.k]] + votes = Counter(topK_y) + + return votes.most_common(1)[0][0] + + def score(self, X_test, y_test): + """根据测试数据集 X_test 和 y_test 确定当前模型的准确度""" + + y_predict = self.predict(X_test) + return accuracy_score(y_test, y_predict) + + def __repr__(self): + return "KNN(k=%d)" % self.k + + diff --git a/machinelearning/gradientDescent/02-ImplementGradientDescentInLinearRegression/playML/metrics.py b/machinelearning/gradientDescent/02-ImplementGradientDescentInLinearRegression/playML/metrics.py new file mode 100644 index 0000000..4b2fda9 --- /dev/null +++ b/machinelearning/gradientDescent/02-ImplementGradientDescentInLinearRegression/playML/metrics.py @@ -0,0 +1,38 @@ +import numpy as np +from math import sqrt + + +def accuracy_score(y_true, y_predict): + """计算y_true和y_predict之间的准确率""" + assert len(y_true) == len(y_predict), \ + "the size of y_true must be equal to the size of y_predict" + + return np.sum(y_true == y_predict) / len(y_true) + + +def mean_squared_error(y_true, y_predict): + """计算y_true和y_predict之间的MSE""" + assert len(y_true) == len(y_predict), \ + "the size of y_true must be equal to the size of y_predict" + + return np.sum((y_true - y_predict)**2) / len(y_true) + + +def root_mean_squared_error(y_true, y_predict): + """计算y_true和y_predict之间的RMSE""" + + return sqrt(mean_squared_error(y_true, y_predict)) + + +def mean_absolute_error(y_true, y_predict): + """计算y_true和y_predict之间的MAE""" + assert len(y_true) == len(y_predict), \ + "the size of y_true must be equal to the size of y_predict" + + return np.sum(np.absolute(y_true - y_predict)) / len(y_true) + + +def r2_score(y_true, y_predict): + """计算y_true和y_predict之间的R Square""" + + return 1 - mean_squared_error(y_true, y_predict)/np.var(y_true) \ No newline at end of file diff --git a/machinelearning/gradientDescent/02-ImplementGradientDescentInLinearRegression/playML/model_selection.py b/machinelearning/gradientDescent/02-ImplementGradientDescentInLinearRegression/playML/model_selection.py new file mode 100644 index 0000000..878e7ed --- /dev/null +++ b/machinelearning/gradientDescent/02-ImplementGradientDescentInLinearRegression/playML/model_selection.py @@ -0,0 +1,26 @@ +import numpy as np + + +def train_test_split(X, y, test_ratio=0.2, seed=None): + """将数据 X 和 y 按照test_ratio分割成X_train, X_test, y_train, y_test""" + assert X.shape[0] == y.shape[0], \ + "the size of X must be equal to the size of y" + assert 0.0 <= test_ratio <= 1.0, \ + "test_ration must be valid" + + if seed: + np.random.seed(seed) + + shuffled_indexes = np.random.permutation(len(X)) + + test_size = int(len(X) * test_ratio) + test_indexes = shuffled_indexes[:test_size] + train_indexes = shuffled_indexes[test_size:] + + X_train = X[train_indexes] + y_train = y[train_indexes] + + X_test = X[test_indexes] + y_test = y[test_indexes] + + return X_train, X_test, y_train, y_test diff --git a/machinelearning/gradientDescent/02-ImplementGradientDescentInLinearRegression/playML/preprocessing.py b/machinelearning/gradientDescent/02-ImplementGradientDescentInLinearRegression/playML/preprocessing.py new file mode 100644 index 0000000..e95f89a --- /dev/null +++ b/machinelearning/gradientDescent/02-ImplementGradientDescentInLinearRegression/playML/preprocessing.py @@ -0,0 +1,30 @@ +import numpy as np + + +class StandardScaler: + + def __init__(self): + self.mean_ = None + self.scale_ = None + + def fit(self, X): + """根据训练数据集X获得数据的均值和方差""" + assert X.ndim == 2, "The dimension of X must be 2" + + self.mean_ = np.array([np.mean(X[:,i]) for i in range(X.shape[1])]) + self.scale_ = np.array([np.std(X[:,i]) for i in range(X.shape[1])]) + + return self + + def transform(self, X): + """将X根据这个StandardScaler进行均值方差归一化处理""" + assert X.ndim == 2, "The dimension of X must be 2" + assert self.mean_ is not None and self.scale_ is not None, \ + "must fit before transform!" + assert X.shape[1] == len(self.mean_), \ + "the feature number of X must be equal to mean_ and std_" + + resX = np.empty(shape=X.shape, dtype=float) + for col in range(X.shape[1]): + resX[:,col] = (X[:,col] - self.mean_[col]) / self.scale_[col] + return resX diff --git a/machinelearning/gradientDescent/05-Vectorize-Gradient-Descent/05-Vectorize-Gradient-Descent.ipynb b/machinelearning/gradientDescent/05-Vectorize-Gradient-Descent/05-Vectorize-Gradient-Descent.ipynb new file mode 100644 index 0000000..4c27c59 --- /dev/null +++ b/machinelearning/gradientDescent/05-Vectorize-Gradient-Descent/05-Vectorize-Gradient-Descent.ipynb @@ -0,0 +1,398 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 梯度下降法的向量化" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "from sklearn import datasets" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "boston = datasets.load_boston()\n", + "X = boston.data\n", + "y = boston.target\n", + "\n", + "X = X[y < 50.0]\n", + "y = y[y < 50.0]" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "from playML.model_selection import train_test_split\n", + "\n", + "X_train, X_test, y_train, y_test = train_test_split(X, y, seed=666)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 45.6 ms, sys: 5.74 ms, total: 51.3 ms\n", + "Wall time: 56.4 ms\n" + ] + }, + { + "data": { + "text/plain": [ + "0.81298026026584658" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from playML.LinearRegression import LinearRegression\n", + "\n", + "lin_reg1 = LinearRegression()\n", + "%time lin_reg1.fit_normal(X_train, y_train)\n", + "lin_reg1.score(X_test, y_test)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 使用梯度下降法" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/yuanzhang/Dropbox/code/My MOOC/Play-with-Machine-Learning-Algorithms/06-Gradient-Descent/05-Vectorize-Gradient-Descent/playML/LinearRegression.py:32: RuntimeWarning: overflow encountered in square\n", + " return np.sum((y - X_b.dot(theta)) ** 2) / len(y)\n", + "/Users/yuanzhang/Dropbox/code/My MOOC/Play-with-Machine-Learning-Algorithms/06-Gradient-Descent/05-Vectorize-Gradient-Descent/playML/LinearRegression.py:48: RuntimeWarning: invalid value encountered in double_scalars\n", + " if (abs(J(theta, X_b, y) - J(last_theta, X_b, y)) < epsilon):\n" + ] + }, + { + "data": { + "text/plain": [ + "LinearRegression()" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lin_reg2 = LinearRegression()\n", + "lin_reg2.fit_gd(X_train, y_train)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,\n", + " nan, nan])" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lin_reg2.coef_" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "LinearRegression()" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lin_reg2.fit_gd(X_train, y_train, eta=0.000001)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.27556634853389195" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lin_reg2.score(X_test, y_test)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 48.4 s, sys: 265 ms, total: 48.6 s\n", + "Wall time: 49.9 s\n" + ] + }, + { + "data": { + "text/plain": [ + "LinearRegression()" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%time lin_reg2.fit_gd(X_train, y_train, eta=0.000001, n_iters=1e6)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.75418523539807636" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lin_reg2.score(X_test, y_test)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 使用梯度下降法前进行数据归一化" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 237 ms, sys: 4.37 ms, total: 242 ms\n", + "Wall time: 258 ms\n" + ] + }, + { + "data": { + "text/plain": [ + "LinearRegression()" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from sklearn.preprocessing import StandardScaler\n", + "\n", + "standardScaler = StandardScaler()\n", + "standardScaler.fit(X_train)\n", + "X_train_standard = standardScaler.transform(X_train)\n", + "\n", + "lin_reg3 = LinearRegression()\n", + "%time lin_reg3.fit_gd(X_train_standard, y_train)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.81298806201222351" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "X_test_standard = standardScaler.transform(X_test)\n", + "lin_reg3.score(X_test_standard, y_test)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 梯度下降法的优势" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "m = 1000\n", + "n = 5000\n", + "\n", + "big_X = np.random.normal(size=(m, n))\n", + "\n", + "true_theta = np.random.uniform(0.0, 100.0, size=n+1)\n", + "\n", + "big_y = big_X.dot(true_theta[1:]) + true_theta[0] + np.random.normal(0., 10., size=m)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 18.8 s, sys: 899 ms, total: 19.7 s\n", + "Wall time: 10.9 s\n" + ] + }, + { + "data": { + "text/plain": [ + "LinearRegression()" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "big_reg1 = LinearRegression()\n", + "%time big_reg1.fit_normal(big_X, big_y)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 9.51 s, sys: 121 ms, total: 9.63 s\n", + "Wall time: 5.76 s\n" + ] + }, + { + "data": { + "text/plain": [ + "LinearRegression()" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "big_reg2 = LinearRegression()\n", + "%time big_reg2.fit_gd(big_X, big_y)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/machinelearning/gradientDescent/05-Vectorize-Gradient-Descent/playML/LinearRegression.py b/machinelearning/gradientDescent/05-Vectorize-Gradient-Descent/playML/LinearRegression.py new file mode 100644 index 0000000..ef08ac5 --- /dev/null +++ b/machinelearning/gradientDescent/05-Vectorize-Gradient-Descent/playML/LinearRegression.py @@ -0,0 +1,81 @@ +import numpy as np +from .metrics import r2_score + +class LinearRegression: + + def __init__(self): + """初始化Linear Regression模型""" + self.coef_ = None + self.intercept_ = None + self._theta = None + + def fit_normal(self, X_train, y_train): + """根据训练数据集X_train, y_train训练Linear Regression模型""" + assert X_train.shape[0] == y_train.shape[0], \ + "the size of X_train must be equal to the size of y_train" + + X_b = np.hstack([np.ones((len(X_train), 1)), X_train]) + self._theta = np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y_train) + + self.intercept_ = self._theta[0] + self.coef_ = self._theta[1:] + + return self + + def fit_gd(self, X_train, y_train, eta=0.01, n_iters=1e4): + """根据训练数据集X_train, y_train, 使用梯度下降法训练Linear Regression模型""" + assert X_train.shape[0] == y_train.shape[0], \ + "the size of X_train must be equal to the size of y_train" + + def J(theta, X_b, y): + try: + return np.sum((y - X_b.dot(theta)) ** 2) / len(y) + except: + return float('inf') + + def dJ(theta, X_b, y): + return X_b.T.dot(X_b.dot(theta) - y) * 2. / len(y) + + def gradient_descent(X_b, y, initial_theta, eta, n_iters=1e4, epsilon=1e-8): + + theta = initial_theta + cur_iter = 0 + + while cur_iter < n_iters: + gradient = dJ(theta, X_b, y) + last_theta = theta + theta = theta - eta * gradient + if (abs(J(theta, X_b, y) - J(last_theta, X_b, y)) < epsilon): + break + + cur_iter += 1 + + return theta + + X_b = np.hstack([np.ones((len(X_train), 1)), X_train]) + initial_theta = np.zeros(X_b.shape[1]) + self._theta = gradient_descent(X_b, y_train, initial_theta, eta, n_iters) + + self.intercept_ = self._theta[0] + self.coef_ = self._theta[1:] + + return self + + def predict(self, X_predict): + """给定待预测数据集X_predict,返回表示X_predict的结果向量""" + assert self.intercept_ is not None and self.coef_ is not None, \ + "must fit before predict!" + assert X_predict.shape[1] == len(self.coef_), \ + "the feature number of X_predict must be equal to X_train" + + X_b = np.hstack([np.ones((len(X_predict), 1)), X_predict]) + return X_b.dot(self._theta) + + def score(self, X_test, y_test): + """根据测试数据集 X_test 和 y_test 确定当前模型的准确度""" + + y_predict = self.predict(X_test) + return r2_score(y_test, y_predict) + + def __repr__(self): + return "LinearRegression()" diff --git a/machinelearning/gradientDescent/05-Vectorize-Gradient-Descent/playML/SimpleLinearRegression.py b/machinelearning/gradientDescent/05-Vectorize-Gradient-Descent/playML/SimpleLinearRegression.py new file mode 100644 index 0000000..a133e4d --- /dev/null +++ b/machinelearning/gradientDescent/05-Vectorize-Gradient-Descent/playML/SimpleLinearRegression.py @@ -0,0 +1,47 @@ +import numpy as np +from .metrics import r2_score + + +class SimpleLinearRegression: + + def __init__(self): + """初始化Simple Linear Regression模型""" + self.a_ = None + self.b_ = None + + def fit(self, x_train, y_train): + """根据训练数据集x_train, y_train训练Simple Linear Regression模型""" + assert x_train.ndim == 1, \ + "Simple Linear Regressor can only solve single feature training data." + assert len(x_train) == len(y_train), \ + "the size of x_train must be equal to the size of y_train" + + x_mean = np.mean(x_train) + y_mean = np.mean(y_train) + + self.a_ = (x_train - x_mean).dot(y_train - y_mean) / (x_train - x_mean).dot(x_train - x_mean) + self.b_ = y_mean - self.a_ * x_mean + + return self + + def predict(self, x_predict): + """给定待预测数据集x_predict,返回表示x_predict的结果向量""" + assert x_predict.ndim == 1, \ + "Simple Linear Regressor can only solve single feature training data." + assert self.a_ is not None and self.b_ is not None, \ + "must fit before predict!" + + return np.array([self._predict(x) for x in x_predict]) + + def _predict(self, x_single): + """给定单个待预测数据x,返回x的预测结果值""" + return self.a_ * x_single + self.b_ + + def score(self, x_test, y_test): + """根据测试数据集 x_test 和 y_test 确定当前模型的准确度""" + + y_predict = self.predict(x_test) + return r2_score(y_test, y_predict) + + def __repr__(self): + return "SimpleLinearRegression()" diff --git a/machinelearning/gradientDescent/05-Vectorize-Gradient-Descent/playML/__init__.py b/machinelearning/gradientDescent/05-Vectorize-Gradient-Descent/playML/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/machinelearning/gradientDescent/05-Vectorize-Gradient-Descent/playML/kNN.py b/machinelearning/gradientDescent/05-Vectorize-Gradient-Descent/playML/kNN.py new file mode 100644 index 0000000..0b54a95 --- /dev/null +++ b/machinelearning/gradientDescent/05-Vectorize-Gradient-Descent/playML/kNN.py @@ -0,0 +1,59 @@ +import numpy as np +from math import sqrt +from collections import Counter +from .metrics import accuracy_score + +class KNNClassifier: + + def __init__(self, k): + """初始化kNN分类器""" + assert k >= 1, "k must be valid" + self.k = k + self._X_train = None + self._y_train = None + + def fit(self, X_train, y_train): + """根据训练数据集X_train和y_train训练kNN分类器""" + assert X_train.shape[0] == y_train.shape[0], \ + "the size of X_train must be equal to the size of y_train" + assert self.k <= X_train.shape[0], \ + "the size of X_train must be at least k." + + self._X_train = X_train + self._y_train = y_train + return self + + def predict(self, X_predict): + """给定待预测数据集X_predict,返回表示X_predict的结果向量""" + assert self._X_train is not None and self._y_train is not None, \ + "must fit before predict!" + assert X_predict.shape[1] == self._X_train.shape[1], \ + "the feature number of X_predict must be equal to X_train" + + y_predict = [self._predict(x) for x in X_predict] + return np.array(y_predict) + + def _predict(self, x): + """给定单个待预测数据x,返回x的预测结果值""" + assert x.shape[0] == self._X_train.shape[1], \ + "the feature number of x must be equal to X_train" + + distances = [sqrt(np.sum((x_train - x) ** 2)) + for x_train in self._X_train] + nearest = np.argsort(distances) + + topK_y = [self._y_train[i] for i in nearest[:self.k]] + votes = Counter(topK_y) + + return votes.most_common(1)[0][0] + + def score(self, X_test, y_test): + """根据测试数据集 X_test 和 y_test 确定当前模型的准确度""" + + y_predict = self.predict(X_test) + return accuracy_score(y_test, y_predict) + + def __repr__(self): + return "KNN(k=%d)" % self.k + + diff --git a/machinelearning/gradientDescent/05-Vectorize-Gradient-Descent/playML/metrics.py b/machinelearning/gradientDescent/05-Vectorize-Gradient-Descent/playML/metrics.py new file mode 100644 index 0000000..4b2fda9 --- /dev/null +++ b/machinelearning/gradientDescent/05-Vectorize-Gradient-Descent/playML/metrics.py @@ -0,0 +1,38 @@ +import numpy as np +from math import sqrt + + +def accuracy_score(y_true, y_predict): + """计算y_true和y_predict之间的准确率""" + assert len(y_true) == len(y_predict), \ + "the size of y_true must be equal to the size of y_predict" + + return np.sum(y_true == y_predict) / len(y_true) + + +def mean_squared_error(y_true, y_predict): + """计算y_true和y_predict之间的MSE""" + assert len(y_true) == len(y_predict), \ + "the size of y_true must be equal to the size of y_predict" + + return np.sum((y_true - y_predict)**2) / len(y_true) + + +def root_mean_squared_error(y_true, y_predict): + """计算y_true和y_predict之间的RMSE""" + + return sqrt(mean_squared_error(y_true, y_predict)) + + +def mean_absolute_error(y_true, y_predict): + """计算y_true和y_predict之间的MAE""" + assert len(y_true) == len(y_predict), \ + "the size of y_true must be equal to the size of y_predict" + + return np.sum(np.absolute(y_true - y_predict)) / len(y_true) + + +def r2_score(y_true, y_predict): + """计算y_true和y_predict之间的R Square""" + + return 1 - mean_squared_error(y_true, y_predict)/np.var(y_true) \ No newline at end of file diff --git a/machinelearning/gradientDescent/05-Vectorize-Gradient-Descent/playML/model_selection.py b/machinelearning/gradientDescent/05-Vectorize-Gradient-Descent/playML/model_selection.py new file mode 100644 index 0000000..878e7ed --- /dev/null +++ b/machinelearning/gradientDescent/05-Vectorize-Gradient-Descent/playML/model_selection.py @@ -0,0 +1,26 @@ +import numpy as np + + +def train_test_split(X, y, test_ratio=0.2, seed=None): + """将数据 X 和 y 按照test_ratio分割成X_train, X_test, y_train, y_test""" + assert X.shape[0] == y.shape[0], \ + "the size of X must be equal to the size of y" + assert 0.0 <= test_ratio <= 1.0, \ + "test_ration must be valid" + + if seed: + np.random.seed(seed) + + shuffled_indexes = np.random.permutation(len(X)) + + test_size = int(len(X) * test_ratio) + test_indexes = shuffled_indexes[:test_size] + train_indexes = shuffled_indexes[test_size:] + + X_train = X[train_indexes] + y_train = y[train_indexes] + + X_test = X[test_indexes] + y_test = y[test_indexes] + + return X_train, X_test, y_train, y_test diff --git a/machinelearning/gradientDescent/05-Vectorize-Gradient-Descent/playML/preprocessing.py b/machinelearning/gradientDescent/05-Vectorize-Gradient-Descent/playML/preprocessing.py new file mode 100644 index 0000000..e95f89a --- /dev/null +++ b/machinelearning/gradientDescent/05-Vectorize-Gradient-Descent/playML/preprocessing.py @@ -0,0 +1,30 @@ +import numpy as np + + +class StandardScaler: + + def __init__(self): + self.mean_ = None + self.scale_ = None + + def fit(self, X): + """根据训练数据集X获得数据的均值和方差""" + assert X.ndim == 2, "The dimension of X must be 2" + + self.mean_ = np.array([np.mean(X[:,i]) for i in range(X.shape[1])]) + self.scale_ = np.array([np.std(X[:,i]) for i in range(X.shape[1])]) + + return self + + def transform(self, X): + """将X根据这个StandardScaler进行均值方差归一化处理""" + assert X.ndim == 2, "The dimension of X must be 2" + assert self.mean_ is not None and self.scale_ is not None, \ + "must fit before transform!" + assert X.shape[1] == len(self.mean_), \ + "the feature number of X must be equal to mean_ and std_" + + resX = np.empty(shape=X.shape, dtype=float) + for col in range(X.shape[1]): + resX[:,col] = (X[:,col] - self.mean_[col]) / self.scale_[col] + return resX diff --git a/machinelearning/gradientDescent/06-Stochastic-Gradient-Descent/06-Stochastic-Gradient-Descent.ipynb b/machinelearning/gradientDescent/06-Stochastic-Gradient-Descent/06-Stochastic-Gradient-Descent.ipynb new file mode 100644 index 0000000..83b943d --- /dev/null +++ b/machinelearning/gradientDescent/06-Stochastic-Gradient-Descent/06-Stochastic-Gradient-Descent.ipynb @@ -0,0 +1,230 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 随机梯度下降法" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "m = 100000\n", + "\n", + "x = np.random.normal(size=m)\n", + "X = x.reshape(-1,1)\n", + "y = 4.*x + 3. + np.random.normal(0, 3, size=m)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.scatter(x, y)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def J(theta, X_b, y):\n", + " try:\n", + " return np.sum((y - X_b.dot(theta)) ** 2) / len(y)\n", + " except:\n", + " return float('inf')\n", + " \n", + "def dJ(theta, X_b, y):\n", + " return X_b.T.dot(X_b.dot(theta) - y) * 2. / len(y)\n", + "\n", + "def gradient_descent(X_b, y, initial_theta, eta, n_iters=1e4, epsilon=1e-8):\n", + "\n", + " theta = initial_theta\n", + " cur_iter = 0\n", + "\n", + " while cur_iter < n_iters:\n", + " gradient = dJ(theta, X_b, y)\n", + " last_theta = theta\n", + " theta = theta - eta * gradient\n", + " if (abs(J(theta, X_b, y) - J(last_theta, X_b, y)) < epsilon):\n", + " break\n", + "\n", + " cur_iter += 1\n", + "\n", + " return theta" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 2.81 s, sys: 134 ms, total: 2.94 s\n", + "Wall time: 1.88 s\n" + ] + } + ], + "source": [ + "%%time\n", + "X_b = np.hstack([np.ones((len(X), 1)), X])\n", + "initial_theta = np.zeros(X_b.shape[1])\n", + "eta = 0.01\n", + "theta = gradient_descent(X_b, y, initial_theta, eta)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ 3.00383464, 4.01706856])" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "theta" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 随机梯度下降法" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def dJ_sgd(theta, X_b_i, y_i):\n", + " return 2 * X_b_i.T.dot(X_b_i.dot(theta) - y_i)\n", + "\n", + "def sgd(X_b, y, initial_theta, n_iters):\n", + "\n", + " t0, t1 = 5, 50\n", + " def learning_rate(t):\n", + " return t0 / (t + t1)\n", + "\n", + " theta = initial_theta\n", + " for cur_iter in range(n_iters):\n", + " rand_i = np.random.randint(len(X_b))\n", + " gradient = dJ_sgd(theta, X_b[rand_i], y[rand_i])\n", + " theta = theta - learning_rate(cur_iter) * gradient\n", + "\n", + " return theta" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 559 ms, sys: 22.6 ms, total: 582 ms\n", + "Wall time: 647 ms\n" + ] + } + ], + "source": [ + "%%time\n", + "X_b = np.hstack([np.ones((len(X), 1)), X])\n", + "initial_theta = np.zeros(X_b.shape[1])\n", + "theta = sgd(X_b, y, initial_theta, n_iters=m//3)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ 3.04732375, 4.03214249])" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "theta" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/machinelearning/gradientDescent/07-SGD-in-scikit-learn/07-SGD-in-scikit-learn.ipynb b/machinelearning/gradientDescent/07-SGD-in-scikit-learn/07-SGD-in-scikit-learn.ipynb new file mode 100644 index 0000000..38616c8 --- /dev/null +++ b/machinelearning/gradientDescent/07-SGD-in-scikit-learn/07-SGD-in-scikit-learn.ipynb @@ -0,0 +1,321 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 封装我们自己的SGD" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "m = 100000\n", + "\n", + "x = np.random.normal(size=m)\n", + "X = x.reshape(-1,1)\n", + "y = 4.*x + 3. + np.random.normal(0, 3, size=m)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "from playML.LinearRegression import LinearRegression" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3.01644183437 [ 3.99995653]\n" + ] + } + ], + "source": [ + "lin_reg = LinearRegression()\n", + "lin_reg.fit_bgd(X, y)\n", + "print(lin_reg.intercept_, lin_reg.coef_)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2.99558568395 [ 4.02610767]\n" + ] + } + ], + "source": [ + "lin_reg = LinearRegression()\n", + "lin_reg.fit_sgd(X, y, n_iters=2)\n", + "print(lin_reg.intercept_, lin_reg.coef_)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 真实使用我们自己的SGD" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "from sklearn import datasets\n", + "\n", + "boston = datasets.load_boston()\n", + "X = boston.data\n", + "y = boston.target\n", + "\n", + "X = X[y < 50.0]\n", + "y = y[y < 50.0]" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "from playML.model_selection import train_test_split\n", + "\n", + "X_train, X_test, y_train, y_test = train_test_split(X, y, seed=666)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "from sklearn.preprocessing import StandardScaler\n", + "\n", + "standardScaler = StandardScaler()\n", + "standardScaler.fit(X_train)\n", + "X_train_standard = standardScaler.transform(X_train)\n", + "X_test_standard = standardScaler.transform(X_test)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 11.9 ms, sys: 4.13 ms, total: 16.1 ms\n", + "Wall time: 13.5 ms\n" + ] + }, + { + "data": { + "text/plain": [ + "0.78651716204682975" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from playML.LinearRegression import LinearRegression\n", + "\n", + "lin_reg = LinearRegression()\n", + "%time lin_reg.fit_sgd(X_train_standard, y_train, n_iters=2)\n", + "lin_reg.score(X_test_standard, y_test)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 155 ms, sys: 8.11 ms, total: 163 ms\n", + "Wall time: 158 ms\n" + ] + }, + { + "data": { + "text/plain": [ + "0.80857287165738345" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%time lin_reg.fit_sgd(X_train_standard, y_train, n_iters=50)\n", + "lin_reg.score(X_test_standard, y_test)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 282 ms, sys: 5.11 ms, total: 287 ms\n", + "Wall time: 287 ms\n" + ] + }, + { + "data": { + "text/plain": [ + "0.81294846132723497" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%time lin_reg.fit_sgd(X_train_standard, y_train, n_iters=100)\n", + "lin_reg.score(X_test_standard, y_test)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### scikit-learn中的SGD" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 631 µs, sys: 54 µs, total: 685 µs\n", + "Wall time: 690 µs\n" + ] + }, + { + "data": { + "text/plain": [ + "0.80478459701573024" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from sklearn.linear_model import SGDRegressor\n", + "\n", + "sgd_reg = SGDRegressor()\n", + "%time sgd_reg.fit(X_train_standard, y_train)\n", + "sgd_reg.score(X_test_standard, y_test)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 4.5 ms, sys: 1.04 ms, total: 5.54 ms\n", + "Wall time: 3.94 ms\n" + ] + }, + { + "data": { + "text/plain": [ + "0.81199073931878407" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sgd_reg = SGDRegressor(n_iter=50)\n", + "%time sgd_reg.fit(X_train_standard, y_train)\n", + "sgd_reg.score(X_test_standard, y_test)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/machinelearning/gradientDescent/07-SGD-in-scikit-learn/playML/LinearRegression.py b/machinelearning/gradientDescent/07-SGD-in-scikit-learn/playML/LinearRegression.py new file mode 100644 index 0000000..c42cf64 --- /dev/null +++ b/machinelearning/gradientDescent/07-SGD-in-scikit-learn/playML/LinearRegression.py @@ -0,0 +1,116 @@ +import numpy as np +from .metrics import r2_score + +class LinearRegression: + + def __init__(self): + """初始化Linear Regression模型""" + self.coef_ = None + self.intercept_ = None + self._theta = None + + def fit_normal(self, X_train, y_train): + """根据训练数据集X_train, y_train训练Linear Regression模型""" + assert X_train.shape[0] == y_train.shape[0], \ + "the size of X_train must be equal to the size of y_train" + + X_b = np.hstack([np.ones((len(X_train), 1)), X_train]) + self._theta = np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y_train) + + self.intercept_ = self._theta[0] + self.coef_ = self._theta[1:] + + return self + + def fit_bgd(self, X_train, y_train, eta=0.01, n_iters=1e4): + """根据训练数据集X_train, y_train, 使用梯度下降法训练Linear Regression模型""" + assert X_train.shape[0] == y_train.shape[0], \ + "the size of X_train must be equal to the size of y_train" + + def J(theta, X_b, y): + try: + return np.sum((y - X_b.dot(theta)) ** 2) / len(y) + except: + return float('inf') + + def dJ(theta, X_b, y): + return X_b.T.dot(X_b.dot(theta) - y) * 2. / len(y) + + def gradient_descent(X_b, y, initial_theta, eta, n_iters=1e4, epsilon=1e-8): + + theta = initial_theta + cur_iter = 0 + + while cur_iter < n_iters: + gradient = dJ(theta, X_b, y) + last_theta = theta + theta = theta - eta * gradient + if (abs(J(theta, X_b, y) - J(last_theta, X_b, y)) < epsilon): + break + + cur_iter += 1 + + return theta + + X_b = np.hstack([np.ones((len(X_train), 1)), X_train]) + initial_theta = np.zeros(X_b.shape[1]) + self._theta = gradient_descent(X_b, y_train, initial_theta, eta, n_iters) + + self.intercept_ = self._theta[0] + self.coef_ = self._theta[1:] + + return self + + def fit_sgd(self, X_train, y_train, n_iters=50, t0=5, t1=50): + """根据训练数据集X_train, y_train, 使用梯度下降法训练Linear Regression模型""" + assert X_train.shape[0] == y_train.shape[0], \ + "the size of X_train must be equal to the size of y_train" + assert n_iters >= 1 + + def dJ_sgd(theta, X_b_i, y_i): + return X_b_i * (X_b_i.dot(theta) - y_i) * 2. + + def sgd(X_b, y, initial_theta, n_iters=5, t0=5, t1=50): + + def learning_rate(t): + return t0 / (t + t1) + + theta = initial_theta + m = len(X_b) + for i_iter in range(n_iters): + indexes = np.random.permutation(m) + X_b_new = X_b[indexes,:] + y_new = y[indexes] + for i in range(m): + gradient = dJ_sgd(theta, X_b_new[i], y_new[i]) + theta = theta - learning_rate(i_iter * m + i) * gradient + + return theta + + X_b = np.hstack([np.ones((len(X_train), 1)), X_train]) + initial_theta = np.random.randn(X_b.shape[1]) + self._theta = sgd(X_b, y_train, initial_theta, n_iters, t0, t1) + + self.intercept_ = self._theta[0] + self.coef_ = self._theta[1:] + + return self + + def predict(self, X_predict): + """给定待预测数据集X_predict,返回表示X_predict的结果向量""" + assert self.intercept_ is not None and self.coef_ is not None, \ + "must fit before predict!" + assert X_predict.shape[1] == len(self.coef_), \ + "the feature number of X_predict must be equal to X_train" + + X_b = np.hstack([np.ones((len(X_predict), 1)), X_predict]) + return X_b.dot(self._theta) + + def score(self, X_test, y_test): + """根据测试数据集 X_test 和 y_test 确定当前模型的准确度""" + + y_predict = self.predict(X_test) + return r2_score(y_test, y_predict) + + def __repr__(self): + return "LinearRegression()" diff --git a/machinelearning/gradientDescent/07-SGD-in-scikit-learn/playML/SimpleLinearRegression.py b/machinelearning/gradientDescent/07-SGD-in-scikit-learn/playML/SimpleLinearRegression.py new file mode 100644 index 0000000..a133e4d --- /dev/null +++ b/machinelearning/gradientDescent/07-SGD-in-scikit-learn/playML/SimpleLinearRegression.py @@ -0,0 +1,47 @@ +import numpy as np +from .metrics import r2_score + + +class SimpleLinearRegression: + + def __init__(self): + """初始化Simple Linear Regression模型""" + self.a_ = None + self.b_ = None + + def fit(self, x_train, y_train): + """根据训练数据集x_train, y_train训练Simple Linear Regression模型""" + assert x_train.ndim == 1, \ + "Simple Linear Regressor can only solve single feature training data." + assert len(x_train) == len(y_train), \ + "the size of x_train must be equal to the size of y_train" + + x_mean = np.mean(x_train) + y_mean = np.mean(y_train) + + self.a_ = (x_train - x_mean).dot(y_train - y_mean) / (x_train - x_mean).dot(x_train - x_mean) + self.b_ = y_mean - self.a_ * x_mean + + return self + + def predict(self, x_predict): + """给定待预测数据集x_predict,返回表示x_predict的结果向量""" + assert x_predict.ndim == 1, \ + "Simple Linear Regressor can only solve single feature training data." + assert self.a_ is not None and self.b_ is not None, \ + "must fit before predict!" + + return np.array([self._predict(x) for x in x_predict]) + + def _predict(self, x_single): + """给定单个待预测数据x,返回x的预测结果值""" + return self.a_ * x_single + self.b_ + + def score(self, x_test, y_test): + """根据测试数据集 x_test 和 y_test 确定当前模型的准确度""" + + y_predict = self.predict(x_test) + return r2_score(y_test, y_predict) + + def __repr__(self): + return "SimpleLinearRegression()" diff --git a/machinelearning/gradientDescent/07-SGD-in-scikit-learn/playML/__init__.py b/machinelearning/gradientDescent/07-SGD-in-scikit-learn/playML/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/machinelearning/gradientDescent/07-SGD-in-scikit-learn/playML/kNN.py b/machinelearning/gradientDescent/07-SGD-in-scikit-learn/playML/kNN.py new file mode 100644 index 0000000..0b54a95 --- /dev/null +++ b/machinelearning/gradientDescent/07-SGD-in-scikit-learn/playML/kNN.py @@ -0,0 +1,59 @@ +import numpy as np +from math import sqrt +from collections import Counter +from .metrics import accuracy_score + +class KNNClassifier: + + def __init__(self, k): + """初始化kNN分类器""" + assert k >= 1, "k must be valid" + self.k = k + self._X_train = None + self._y_train = None + + def fit(self, X_train, y_train): + """根据训练数据集X_train和y_train训练kNN分类器""" + assert X_train.shape[0] == y_train.shape[0], \ + "the size of X_train must be equal to the size of y_train" + assert self.k <= X_train.shape[0], \ + "the size of X_train must be at least k." + + self._X_train = X_train + self._y_train = y_train + return self + + def predict(self, X_predict): + """给定待预测数据集X_predict,返回表示X_predict的结果向量""" + assert self._X_train is not None and self._y_train is not None, \ + "must fit before predict!" + assert X_predict.shape[1] == self._X_train.shape[1], \ + "the feature number of X_predict must be equal to X_train" + + y_predict = [self._predict(x) for x in X_predict] + return np.array(y_predict) + + def _predict(self, x): + """给定单个待预测数据x,返回x的预测结果值""" + assert x.shape[0] == self._X_train.shape[1], \ + "the feature number of x must be equal to X_train" + + distances = [sqrt(np.sum((x_train - x) ** 2)) + for x_train in self._X_train] + nearest = np.argsort(distances) + + topK_y = [self._y_train[i] for i in nearest[:self.k]] + votes = Counter(topK_y) + + return votes.most_common(1)[0][0] + + def score(self, X_test, y_test): + """根据测试数据集 X_test 和 y_test 确定当前模型的准确度""" + + y_predict = self.predict(X_test) + return accuracy_score(y_test, y_predict) + + def __repr__(self): + return "KNN(k=%d)" % self.k + + diff --git a/machinelearning/gradientDescent/07-SGD-in-scikit-learn/playML/metrics.py b/machinelearning/gradientDescent/07-SGD-in-scikit-learn/playML/metrics.py new file mode 100644 index 0000000..4b2fda9 --- /dev/null +++ b/machinelearning/gradientDescent/07-SGD-in-scikit-learn/playML/metrics.py @@ -0,0 +1,38 @@ +import numpy as np +from math import sqrt + + +def accuracy_score(y_true, y_predict): + """计算y_true和y_predict之间的准确率""" + assert len(y_true) == len(y_predict), \ + "the size of y_true must be equal to the size of y_predict" + + return np.sum(y_true == y_predict) / len(y_true) + + +def mean_squared_error(y_true, y_predict): + """计算y_true和y_predict之间的MSE""" + assert len(y_true) == len(y_predict), \ + "the size of y_true must be equal to the size of y_predict" + + return np.sum((y_true - y_predict)**2) / len(y_true) + + +def root_mean_squared_error(y_true, y_predict): + """计算y_true和y_predict之间的RMSE""" + + return sqrt(mean_squared_error(y_true, y_predict)) + + +def mean_absolute_error(y_true, y_predict): + """计算y_true和y_predict之间的MAE""" + assert len(y_true) == len(y_predict), \ + "the size of y_true must be equal to the size of y_predict" + + return np.sum(np.absolute(y_true - y_predict)) / len(y_true) + + +def r2_score(y_true, y_predict): + """计算y_true和y_predict之间的R Square""" + + return 1 - mean_squared_error(y_true, y_predict)/np.var(y_true) \ No newline at end of file diff --git a/machinelearning/gradientDescent/07-SGD-in-scikit-learn/playML/model_selection.py b/machinelearning/gradientDescent/07-SGD-in-scikit-learn/playML/model_selection.py new file mode 100644 index 0000000..878e7ed --- /dev/null +++ b/machinelearning/gradientDescent/07-SGD-in-scikit-learn/playML/model_selection.py @@ -0,0 +1,26 @@ +import numpy as np + + +def train_test_split(X, y, test_ratio=0.2, seed=None): + """将数据 X 和 y 按照test_ratio分割成X_train, X_test, y_train, y_test""" + assert X.shape[0] == y.shape[0], \ + "the size of X must be equal to the size of y" + assert 0.0 <= test_ratio <= 1.0, \ + "test_ration must be valid" + + if seed: + np.random.seed(seed) + + shuffled_indexes = np.random.permutation(len(X)) + + test_size = int(len(X) * test_ratio) + test_indexes = shuffled_indexes[:test_size] + train_indexes = shuffled_indexes[test_size:] + + X_train = X[train_indexes] + y_train = y[train_indexes] + + X_test = X[test_indexes] + y_test = y[test_indexes] + + return X_train, X_test, y_train, y_test diff --git a/machinelearning/gradientDescent/07-SGD-in-scikit-learn/playML/preprocessing.py b/machinelearning/gradientDescent/07-SGD-in-scikit-learn/playML/preprocessing.py new file mode 100644 index 0000000..e95f89a --- /dev/null +++ b/machinelearning/gradientDescent/07-SGD-in-scikit-learn/playML/preprocessing.py @@ -0,0 +1,30 @@ +import numpy as np + + +class StandardScaler: + + def __init__(self): + self.mean_ = None + self.scale_ = None + + def fit(self, X): + """根据训练数据集X获得数据的均值和方差""" + assert X.ndim == 2, "The dimension of X must be 2" + + self.mean_ = np.array([np.mean(X[:,i]) for i in range(X.shape[1])]) + self.scale_ = np.array([np.std(X[:,i]) for i in range(X.shape[1])]) + + return self + + def transform(self, X): + """将X根据这个StandardScaler进行均值方差归一化处理""" + assert X.ndim == 2, "The dimension of X must be 2" + assert self.mean_ is not None and self.scale_ is not None, \ + "must fit before transform!" + assert X.shape[1] == len(self.mean_), \ + "the feature number of X must be equal to mean_ and std_" + + resX = np.empty(shape=X.shape, dtype=float) + for col in range(X.shape[1]): + resX[:,col] = (X[:,col] - self.mean_[col]) / self.scale_[col] + return resX diff --git a/machinelearning/gradientDescent/08-Debug-Gradient/08-Debug-Gradient.ipynb b/machinelearning/gradientDescent/08-Debug-Gradient/08-Debug-Gradient.ipynb new file mode 100644 index 0000000..d005a70 --- /dev/null +++ b/machinelearning/gradientDescent/08-Debug-Gradient/08-Debug-Gradient.ipynb @@ -0,0 +1,257 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 关于梯度的计算调试" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "np.random.seed(666)\n", + "X = np.random.random(size=(1000, 10))\n", + "\n", + "true_theta = np.arange(1, 12, dtype=float)\n", + "X_b = np.hstack([np.ones((len(X), 1)), X])\n", + "y = X_b.dot(true_theta) + np.random.normal(size=1000)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11.])" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "true_theta" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(1000, 10)" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "X.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(1000,)" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "y.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def J(theta, X_b, y):\n", + " try:\n", + " return np.sum((y - X_b.dot(theta))**2) / len(X_b)\n", + " except:\n", + " return float('inf')" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def dJ_math(theta, X_b, y):\n", + " return X_b.T.dot(X_b.dot(theta) - y) * 2. / len(y)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def dJ_debug(theta, X_b, y, epsilon=0.01):\n", + " res = np.empty(len(theta))\n", + " for i in range(len(theta)):\n", + " theta_1 = theta.copy()\n", + " theta_1[i] += epsilon\n", + " theta_2 = theta.copy()\n", + " theta_2[i] -= epsilon\n", + " res[i] = (J(theta_1, X_b, y) - J(theta_2, X_b, y)) / (2 * epsilon)\n", + " return res" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def gradient_descent(dJ, X_b, y, initial_theta, eta, n_iters = 1e4, epsilon=1e-8):\n", + " \n", + " theta = initial_theta\n", + " cur_iter = 0\n", + "\n", + " while cur_iter < n_iters:\n", + " gradient = dJ(theta, X_b, y)\n", + " last_theta = theta\n", + " theta = theta - eta * gradient\n", + " if(abs(J(theta, X_b, y) - J(last_theta, X_b, y)) < epsilon):\n", + " break\n", + " \n", + " cur_iter += 1\n", + "\n", + " return theta" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 13.8 s, sys: 283 ms, total: 14.1 s\n", + "Wall time: 7.6 s\n" + ] + }, + { + "data": { + "text/plain": [ + "array([ 1.1251597 , 2.05312521, 2.91522497, 4.11895968,\n", + " 5.05002117, 5.90494046, 6.97383745, 8.00088367,\n", + " 8.86213468, 9.98608331, 10.90529198])" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "X_b = np.hstack([np.ones((len(X), 1)), X])\n", + "initial_theta = np.zeros(X_b.shape[1])\n", + "eta = 0.01\n", + "\n", + "%time theta = gradient_descent(dJ_debug, X_b, y, initial_theta, eta)\n", + "theta" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 1.57 s, sys: 30.6 ms, total: 1.6 s\n", + "Wall time: 856 ms\n" + ] + }, + { + "data": { + "text/plain": [ + "array([ 1.1251597 , 2.05312521, 2.91522497, 4.11895968,\n", + " 5.05002117, 5.90494046, 6.97383745, 8.00088367,\n", + " 8.86213468, 9.98608331, 10.90529198])" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%time theta = gradient_descent(dJ_math, X_b, y, initial_theta, eta)\n", + "theta" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/machinelearning/images/ml_11.png b/machinelearning/images/ml_11.png new file mode 100644 index 0000000..99cdbe7 Binary files /dev/null and b/machinelearning/images/ml_11.png differ diff --git a/machinelearning/images/ml_12.png b/machinelearning/images/ml_12.png new file mode 100644 index 0000000..2c9dfa4 Binary files /dev/null and b/machinelearning/images/ml_12.png differ diff --git a/machinelearning/images/ml_13.png b/machinelearning/images/ml_13.png new file mode 100644 index 0000000..4d64494 Binary files /dev/null and b/machinelearning/images/ml_13.png differ diff --git a/machinelearning/images/ml_14.png b/machinelearning/images/ml_14.png new file mode 100644 index 0000000..1ac7916 Binary files /dev/null and b/machinelearning/images/ml_14.png differ diff --git a/machinelearning/images/ml_15.png b/machinelearning/images/ml_15.png new file mode 100644 index 0000000..3fdadd6 Binary files /dev/null and b/machinelearning/images/ml_15.png differ diff --git a/machinelearning/images/ml_16.png b/machinelearning/images/ml_16.png new file mode 100644 index 0000000..7f0f76f Binary files /dev/null and b/machinelearning/images/ml_16.png differ diff --git a/machinelearning/images/ml_17.png b/machinelearning/images/ml_17.png new file mode 100644 index 0000000..f665469 Binary files /dev/null and b/machinelearning/images/ml_17.png differ diff --git a/machinelearning/images/ml_18.png b/machinelearning/images/ml_18.png new file mode 100644 index 0000000..6a0ae24 Binary files /dev/null and b/machinelearning/images/ml_18.png differ diff --git a/machinelearning/images/ml_19.png b/machinelearning/images/ml_19.png new file mode 100644 index 0000000..2bb5fbd Binary files /dev/null and b/machinelearning/images/ml_19.png differ