{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "4e2f570b",
   "metadata": {},
   "source": [
    "# 监督学习（有输入x，有标签y）\n",
    "\n",
    "## 回归（regression）\n",
    "回归通常指从一系列可能的数值中预测一个具体的数字\n",
    "\n",
    "## 分类（classification）\n",
    "分类通常指从一系列输入中，输出不同的类别\n",
    "\n",
    "## 回归和分类的区别\n",
    "在分类中，只有少数可能的输出\n",
    "在回归中，可以输出无限多的的数字\n",
    "\n",
    "# 无监督学习（只有输入x，没有标签y）\n",
    "\n",
    "## 聚类（clustering）\n",
    "获取没有标签的数据并尝试将它们分到不同的集群中\n",
    "\n",
    "## 异常检测（Anomaly detection）\n",
    "常用在金融系统中去判断欺诈事件\n",
    "\n",
    "## 降维（Dimensionality reduction）\n",
    "将一个大数据集经过压缩得到几个小的数据集，并尽可能丢失少的信息\n",
    "\n",
    "# 线性回归\n",
    "通俗理解：根据一系列的点集拟合出一条直线\n",
    "\n",
    "$f_{w,b}=wx+b$，其中$w$和$b$称为系数（coefficients）或权重（weights）\n",
    "\n",
    "## 成本函数（Squared error cost function）\n",
    "更准确地说，这是平方误差成本函数，对应不同的模型会有不同的成本函数，但函数是在线性回归中用的最多的\n",
    "$$J(w,b)=\\frac{1}{2m} \\sum_{i=1}^{m}(\\hat{y}^{i}-y^{i})^2$$\n",
    "之所以除以$2m$，是机器学习的习惯\n",
    "\n",
    "线性回归的目标是找到$w$和$b$的值使误差最小\n",
    "\n",
    "# 梯度下降（gradient descent）\n",
    "\n",
    "梯度下降可以用来最小化任何函数，在这里典型的例子就是可以用来找出使成本函数最小的$w$和$b$\n",
    "\n",
    "## 一般步骤\n",
    "* 设置初始值，线性回归中初始值可任意设置，一般设$w = 0$，$b=0$\n",
    "* 不断改变$w$和$b$的值，计算成本\n",
    "* 重复上述步骤，直到找到最小成本\n",
    "\n",
    "对于平方误差成本函数，一般最后成本函数的形状是弓形\n",
    "\n",
    "## 特性\n",
    "梯度下降法可能会找到多个局部最小值\n",
    "\n",
    "## 正确算法\n",
    "一定要注意是同时更新\n",
    "\n",
    "step1 $\\begin{align} temp\\_w = w - \\alpha \\frac{\\partial J(w, b)}{\\partial w} \\\\ temp\\_b = b - \\alpha \\frac{\\partial J(w, b)}{\\partial b} \\end{align}$ \n",
    "\n",
    "step2 $\\begin{align}w = temp \\_ w \\\\ b = temp \\_ b \\end{align}$ \n",
    "\n",
    "其中$\\alpha$为学习率，$\\alpha \\in (0, 1)$，$\\alpha$越大，梯度下降得越快；$\\alpha$越小，梯度下降得越慢\n",
    "\n",
    "## 线性回归模型中的梯度下降算法\n",
    "$\\begin{aligned}\n",
    "& w=w-\\alpha \\frac{1}{m} \\sum_{i=1}^m\\left(f_{w, b}\\left(x^{(i)}\\right)-y^{(i)}\\right) x^{(i)} \\\\\n",
    "& b=b-\\alpha \\frac{1}{m} \\sum_{i=1}^m\\left(f_{w, b}\\left(x^{(i)}\\right)-y^{(i)}\\right)\n",
    "\\end{aligned}$\n",
    "\n",
    "## 线性回归算法自己实现\n",
    "x_train = np.array([6.3787, 12.2712, 8.8355, 5.1608, 5.4483, 12.5224, 8.8200, 7.3056])\n",
    "\n",
    "y_train = np.array([18.5392, 22.3163, 18.3613, 15.6808, 7.9078, 29.7959, 23.7576, 20.0180])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "4d854591",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "w1=1.9908611171372912, b1=2.7828092378827813, cost1=6.264848979042775, w2=1.8064732542637973, b2=4.476044124425181, cost2=6.132133115631797\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import math\n",
    "\n",
    "def cost(x_train, y_train, w, b, n):\n",
    "    temp_cost = 0\n",
    "    for i in range(n):\n",
    "        y_hat = w * x_train[i] + b\n",
    "        temp_cost = temp_cost + pow((y_hat - y_train[i]), 2)\n",
    "    cost = temp_cost / (2 * n)\n",
    "    return cost\n",
    "\n",
    "def gradient(x_train, y_train, w, b, n, alpha):\n",
    "    temp_w = 0\n",
    "    temp_b = 0\n",
    "    for i in range(n):\n",
    "        temp_w = temp_w + (w * x_train[i] + b - y_train[i]) * x_train[i]\n",
    "        temp_b = temp_b + (w * x_train[i] + b - y_train[i])\n",
    "    w = w - alpha * temp_w / n\n",
    "    b = b - alpha * temp_b / n\n",
    "    return w, b\n",
    "\n",
    "x_train = np.array([6.3787, 12.2712, 8.8355, 5.1608, 5.4483, 12.5224, 8.8200, 7.3056])\n",
    "y_train = np.array([18.5392, 22.3163, 18.3613, 15.6808, 7.9078, 29.7959, 23.7576, 20.0180])\n",
    "n = x_train.shape[0]\n",
    "y_hat1 = y_hat2 = np.zeros(n)\n",
    "w1 = b1 = w2 = b2 =  0\n",
    "alpha = 1.0e-2\n",
    "cost1 = 0\n",
    "cost2 = np.zeros(2)\n",
    "iteration = 1000;\n",
    "for i in range (iteration):\n",
    "    w1, b1 = gradient(x_train, y_train, w1, b1, n, alpha)\n",
    "    cost1 = cost(x_train, y_train, w1, b1, n)\n",
    "while (1) :\n",
    "    w2, b2 = gradient(x_train, y_train, w2, b2, n, alpha)\n",
    "    cost2[0] = cost(x_train, y_train, w2, b2, n)\n",
    "    if (cost2[1] == cost2[0]):\n",
    "        break\n",
    "    cost2[1] = cost2[0]\n",
    "for i in range (n):\n",
    "    y_hat1[i] = w1 * x_train[i] + b1\n",
    "    y_hat2[i] = w2 * x_train[i] + b2\n",
    "print(f\"w1={w1}, b1={b1}, cost1={cost1}, w2={w2}, b2={b2}, cost2={cost2[0]}\")\n",
    "plt.figure()\n",
    "plt.scatter(x_train, y_hat1, c = 'r', label = '1000 iterations')\n",
    "plt.plot(x_train, y_hat2, c = 'b', label = 'precise prediction')\n",
    "plt.scatter(x_train, y_train, marker = 'x', c = 'g', label = 'train data')\n",
    "plt.xlabel(\"x_train\")\n",
    "plt.ylabel(\"y\")\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "80b4a3c9",
   "metadata": {},
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "74e6b750-0af2-4f0a-bf44-3417416210c8",
   "metadata": {
    "tags": []
   },
   "source": [
    "## numpy知识复习总结"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "3ed2c6b0-2aef-4464-933e-965ed83ffa7e",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "np.zeros(4) : a = [0. 0. 0. 0.] ,a shape = (4,), a data type = float64\n",
      "np.zeros(4,) : a = [0. 0. 0. 0.] a shape = (4,), a data type = float64\n",
      "np.random.random_sample(4): a = [0.52890149 0.21425091 0.71127027 0.93062679], a shape = (4,), a data type = float64\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "import time\n",
    "\n",
    "a=np.zeros(4);print(f\"np.zeros(4) : a = {a} ,a shape = {a.shape}, a data type = {a.dtype}\")\n",
    "a = np.zeros((4,));print(f\"np.zeros(4,) : a = {a} a shape = {a.shape}, a data type = {a.dtype}\")\n",
    "a = np.random.random_sample(4);print(f\"np.random.random_sample(4): a = {a}, a shape = {a.shape}, a data type = {a.dtype}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "a54430dd-0319-42bc-8ff0-122d601e3961",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "np.arrange(4.): a = [0. 1. 2. 3.], a shape = (4,), a data type = float64\n",
      "np.arrange(4): a = [0 1 2 3], a shape = (4,), a data type = int64\n",
      "np.random.rand(4): a = [0.73422853 0.4686557  0.41362072 0.45870399], a shape = (4,), a data type = float64\n"
     ]
    }
   ],
   "source": [
    "a = np.arange(4.); print(f\"np.arrange(4.): a = {a}, a shape = {a.shape}, a data type = {a.dtype}\")\n",
    "a = np.arange(4); print(f\"np.arrange(4): a = {a}, a shape = {a.shape}, a data type = {a.dtype}\")\n",
    "a = np.random.rand(4);print(f\"np.random.rand(4): a = {a}, a shape = {a.shape}, a data type = {a.dtype}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "211c8ab8-d787-4d86-8de6-ab3e05100b21",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "np.array([5, 4, 3, 2]): a = [5 4 3 2], a shape = (4,), a data type = int64\n",
      "np.array([5., 4, 3, 2]): a = [5. 4. 3. 2.], a shape = (4,), a data type = float64\n"
     ]
    }
   ],
   "source": [
    "a = np.array([5, 4, 3, 2]);print(f\"np.array([5, 4, 3, 2]): a = {a}, a shape = {a.shape}, a data type = {a.dtype}\")\n",
    "a = np.array([5., 4, 3, 2]);print(f\"np.array([5., 4, 3, 2]): a = {a}, a shape = {a.shape}, a data type = {a.dtype}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "4e58176c-f907-48d1-aba9-5a5e571f6769",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0 1 2 3 4 5 6 7 8 9]\n",
      "a[2].shape: () a[2] = 2\n",
      "a[-1] = 9\n",
      "The error message you'll see is:\n",
      "index 10 is out of bounds for axis 0 with size 10\n"
     ]
    }
   ],
   "source": [
    "a = np.arange(10)\n",
    "print (a)\n",
    "\n",
    "print(f\"a[2].shape: {a[2].shape} a[2] = {a[2]}\")\n",
    "print(f\"a[-1] = {a[-1]}\")\n",
    "\n",
    "try:\n",
    "    c = a[10]\n",
    "except Exception as e:\n",
    "    print(\"The error message you'll see is:\")\n",
    "    print(e)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "f16dd444-f735-4b08-88a2-eb701b37b6e2",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a = [0 1 2 3 4 5 6 7 8 9]\n",
      "a[3:9:1] = [3 4 5 6 7 8]\n",
      "a[3:9:2] = [3 5 7]\n",
      "a[3:] = [3 4 5 6 7 8 9]\n",
      "a[:6] = [0 1 2 3 4 5]\n",
      "a[:] = [0 1 2 3 4 5 6 7 8 9]\n"
     ]
    }
   ],
   "source": [
    "a = np.arange(10)\n",
    "print(f\"a = {a}\")\n",
    "c = a[3:9:1];print(f\"a[3:9:1] = {c}\")\n",
    "c = a[3:9:2];print(f\"a[3:9:2] = {c}\")\n",
    "c = a[3:];print(f\"a[3:] = {c}\")\n",
    "c = a[:6];print(f\"a[:6] = {c}\")\n",
    "c = a[:];print(f\"a[:] = {c}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "e2a37411-fadf-41fb-93e3-cbe088c59181",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a = [1 2 3 4]\n",
      "b = [-1 -2 -3 -4]\n",
      "b = 10\n",
      "b = 2.5\n",
      "b = [ 1  4  9 16]\n"
     ]
    }
   ],
   "source": [
    "a = np.array([1, 2, 3, 4])\n",
    "print(f\"a = {a}\")\n",
    "b = -a\n",
    "print(f\"b = {b}\")\n",
    "b = np.sum(a)\n",
    "print(f\"b = {b}\")\n",
    "b = np.mean(a)\n",
    "print(f\"b = {b}\")\n",
    "b = pow(a, 2)\n",
    "print(f\"b = {b}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "446ae4c7-47b5-4efc-a2c5-38ce71d34593",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a+b=[0 0 7 7]\n",
      "5 * a = [ 5 10 15 20]\n",
      "a与b的点积为19\n"
     ]
    }
   ],
   "source": [
    "a = np.array([1, 2, 3, 4])\n",
    "b = np.array([-1, -2, 4, 3])\n",
    "print(f\"a+b={a+b}\")\n",
    "c = 5 * a\n",
    "print(f\"5 * a = {5*a}\")\n",
    "d = np.dot(a, b)\n",
    "print(f\"a与b的点积为{d}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "18417e49-656e-4682-82d7-a8944727ff3b",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a.shape = (1, 5), a = [[0. 0. 0. 0. 0.]]\n",
      " b.shape = (5, 1), b = [[0.]\n",
      " [0.]\n",
      " [0.]\n",
      " [0.]\n",
      " [0.]]\n"
     ]
    }
   ],
   "source": [
    "a = np.zeros((1, 5))\n",
    "b = np.zeros((5, 1))\n",
    "print(f\"a.shape = {a.shape}, a = {a}\\n b.shape = {b.shape}, b = {b}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "afff1b73-e1f9-4c11-8159-ba5a53fe736c",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a = [[1]\n",
      " [2]\n",
      " [3]] \n",
      " b = [1 2 3] \n",
      " a为矩阵，b为向量\n"
     ]
    }
   ],
   "source": [
    "a = np.array([[1], [2], [3]])\n",
    "b = np.array([1, 2, 3])\n",
    "print(f\"a = {a} \\n b = {b} \\n a为矩阵，b为向量\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "92a0fa4e-e334-44fa-a1c9-b195d3c9be92",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a.shape = (3, 2), a = [[0 1]\n",
      " [2 3]\n",
      " [4 5]]\n",
      "b.shape = (3, 2), b = [[0 1]\n",
      " [2 3]\n",
      " [4 5]]\n",
      "c.shape = (3, 2), c = [[0 1]\n",
      " [2 3]\n",
      " [4 5]]\n",
      "a[2, 0](a矩阵中第3行第1列) = 4\n"
     ]
    }
   ],
   "source": [
    "# 下面3条命令是等价的\n",
    "a = np.arange(6).reshape(-1, 2) \n",
    "b = np.arange(6).reshape(3, -1)\n",
    "c = np.arange(6).reshape(3, 2)\n",
    "print(f\"a.shape = {a.shape}, a = {a}\")\n",
    "print(f\"b.shape = {b.shape}, b = {b}\")\n",
    "print(f\"c.shape = {c.shape}, c = {c}\")\n",
    "print(f\"a[2, 0](a矩阵中第3行第1列) = {a[2, 0]}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "6ab05300-d3ea-408b-baeb-646a7f45c959",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a = \n",
      " [[ 0  1  2  3  4  5  6  7  8  9]\n",
      " [10 11 12 13 14 15 16 17 18 19]] \n",
      "\n",
      "a[0, 2:7:1] = [2 3 4 5 6], a[0, 2:7:1].shape = (5,) \n",
      "\n",
      "a[:, 2:7:1] = [[ 2  3  4  5  6]\n",
      " [12 13 14 15 16]], a[:, 2:7:1].shape = (2, 5) \n",
      "\n",
      "a[:, :] = [[ 0  1  2  3  4  5  6  7  8  9]\n",
      " [10 11 12 13 14 15 16 17 18 19]], a[:, :].shape = (2, 10) \n",
      "\n"
     ]
    }
   ],
   "source": [
    "a = np.arange(20).reshape(-1, 10)\n",
    "print(f\"a = \\n {a} \\n\")\n",
    "print(f\"a[0, 2:7:1] = {a[0, 2:7:1]}, a[0, 2:7:1].shape = {a[0, 2:7:1].shape} \\n\")\n",
    "print(f\"a[:, 2:7:1] = {a[:, 2:7:1]}, a[:, 2:7:1].shape = {a[:, 2:7:1].shape} \\n\")\n",
    "print(f\"a[:, :] = {a[:, :]}, a[:, :].shape = {a[:,  :].shape} \\n\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2e7b589e-6c39-4e0b-a022-2e03102b781d",
   "metadata": {},
   "source": [
    "\n",
    "# 多元线性回归\n",
    "\n",
    "## 表达式\n",
    "\n",
    "$f_{\\vec{w}, b}(\\vec{x})=\\vec{w} \\cdot \\vec{x}+b=w_1 x_1+w_2 x_2+w_3 x_3+\\cdots+w_n x_n+b$<br>\n",
    "\n",
    "成本函数：$$J(\\mathbf{w},b) = \\frac{1}{2m} \\sum\\limits_{i = 0}^{m-1} (f_{\\mathbf{w},b}(\\mathbf{x}^{(i)}) - y^{(i)})^2$$ \n",
    "\n",
    "更新参数：$$\\begin{align*}  \\;  \\newline\\;\n",
    "& w_j = w_j -  \\alpha \\frac{\\partial J(\\mathbf{w},b)}{\\partial w_j}  \\; & \\text{for j = 0..n-1}\\newline\n",
    "&b\\ \\ = b -  \\alpha \\frac{\\partial J(\\mathbf{w},b)}{\\partial b}  \\newline \n",
    "\\end{align*}$$\n",
    "其中<br>\n",
    "$$\n",
    "\\begin{align}\n",
    "\\frac{\\partial J(\\mathbf{w},b)}{\\partial w_j}  &= \\frac{1}{m} \\sum\\limits_{i = 0}^{m-1} (f_{\\mathbf{w},b}(\\mathbf{x}^{(i)}) - y^{(i)})x_{j}^{(i)}   \\\\\n",
    "\\frac{\\partial J(\\mathbf{w},b)}{\\partial b}  &= \\frac{1}{m} \\sum\\limits_{i = 0}^{m-1} (f_{\\mathbf{w},b}(\\mathbf{x}^{(i)}) - y^{(i)}) \n",
    "\\end{align}\n",
    "$$\n",
    "各符号表示的含义：<br>\n",
    "$x^{(i)}$：第i个例子，$x^{(i)}_{j}$：第i个例子下的第j个数据  \n",
    "为了便于编写代码，将上面公式改写成矩阵形式，有$m$组数据，每组数据有$n$个变量：\n",
    "\n",
    "$\\vec{f}=\\mathbf{x}\\vec{w}+\\vec{b}$，其中，$\\mathbf{x}=\\begin{equation*}\n",
    "\t\\begin{bmatrix} {x_{11}} &{x_{12}}&\\cdots&{x_{1n}} \\\\\n",
    "\t{x_{21}}&{x_{22}}&\\cdots & {x_{2n}}\\\\\n",
    "\t\\vdots&\\vdots& \\ddots&\\vdots \\\\\n",
    "\t{x_{m1}}&{x_{m2}}&\\cdots&{x_{mn}}\n",
    "\t\\end{bmatrix}\n",
    "\t\\end{equation*}_{m\\times n}$，$\\vec{w}=\\begin{equation*}\\begin{bmatrix} {w_1}\\\\{w_2}\\\\\\vdots\\\\{w_n}\\end{bmatrix}\\end{equation*}_{n\\times 1}$，$\\vec{b}=\\begin{equation*}\\begin{bmatrix} {b_1}\\\\{b_2}\\\\\\vdots\\\\{b_m}\\end{bmatrix}\\end{equation*}_{m\\times 1}$，$b_1 = b_2 = ··· = b_m = b$，预测值$\\vec{f}=\\begin{equation*}\\begin{bmatrix} {f_1}\\\\{f_2}\\\\\\vdots\\\\{f_m}\\end{bmatrix}\\end{equation*}_{m\\times 1}$，实际值$\\vec{y}=\\begin{equation*}\\begin{bmatrix} {y_1}\\\\{y_2}\\\\\\vdots\\\\{y_m}\\end{bmatrix}\\end{equation*}_{m\\times 1}$\n",
    "\n",
    "成本函数：$$J(\\mathbf{w},b) = \\frac{1}{2m} \\sum\\limits_{i = 0}^{m-1} (f_{\\mathbf{w},b}(\\mathbf{x}^{(i)}) - y^{(i)})^2$$ 对应的矩阵形式：$J(\\mathbf{w},b) = \\frac{1}{2m}(\\vec{f} - \\vec{y})^T(\\vec{f} - \\vec{y})$\n",
    "\n",
    "更新变量：$\\vec{w}^T=\\vec{w}^T-\\alpha\\cdot\\frac{1}{m}\\cdot (\\vec{f} - \\vec{y})^T \\mathbf{x} \\\\ \\vec{b}=\\vec{b}-\\alpha\\cdot\\frac{1}{m}\\cdot np.sum((\\vec{f} - \\vec{y}))$\n",
    "| Size (sqft) | Number of Bedrooms  | Number of floors | Age of  Home | Price (1000s dollars)  |   \n",
    "| ----------------| ------------------- |----------------- |--------------|-------------- |  \n",
    "| 2104            | 5                   | 1                | 45           | 460           |  \n",
    "| 1416            | 3                   | 2                | 40           | 232           |  \n",
    "| 852             | 2                   | 1                | 35           | 178           |  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "021e6749-05f1-4458-ac25-d681d7196f7f",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "w = [[ 0.2 ]\n",
      " [ 0.  ]\n",
      " [-0.01]\n",
      " [-0.07]] \n",
      " b = [[-0.]\n",
      " [-0.]\n",
      " [-0.]]\n"
     ]
    },
    {
     "data": {
      "image/png": "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BAYGAtCiRQucnJzs2wQHB7Nr1y4AunXrRnh4OA0bNqR79+50796d+++/H09Pz+vKIiJlT8NYImK6ixcv8vjjj5OSkmJ/7dixg7S0NBo1amTf7r/LCEBSUhKDBg2iZ8+erFq1iu3bt/Pcc89RWFhYLjldXFxK/WyxWLDZbMDl4bRt27axePFigoODef7552nTpg2ZmZnlkkVErp2+2RGRCuXq6kpJSUmpZe3atWPPnj00btz4uva1YcMGwsPDee655+zLjhw58rvv97+aNWvGggULyM3NtReqxMRErFYrTZs2veY8zs7OxMTEEBMTwwsvvICvry/fffcdDzzwwHUclYiUNX2zIyIVqn79+vz444+cOHGCs2fPApfvqNqwYQPjxo0jJSWFtLQ0VqxYccUFwv+rSZMmHD16lI8//piDBw8SFxfHsmXLrni/w4cPk5KSwtmzZykoKLhiP4MGDcLd3Z1hw4axe/du1q9fz/jx4xkyZIh9COv3rFq1iri4OFJSUjhy5Ajvv/8+NpvtusqSiJQPlR0RqVAvvfQSP//8M40aNcLf3x+A1q1b88MPP7B//36io6Np27Ytzz//PCEhIb+5r969ezNp0iTGjRvHzTffzIYNG+x3af2iX79+dO/enTvuuAN/f38WL158xX48PT358ssvOX/+PLfccgsPPvggd911F7Nnz77m4/L19WXp0qXceeedNGvWjLlz57J48WJatGhxzfsQkfKhJyiLiIiIQ9M3OyIiIuLQVHZERETEoansiIiIiENT2RERERGHprIjIiIiDk1lR0RERByayo6IiIg4NJUdERERcWgqOyIiIuLQVHZERETEoansiIiIiEP7/6DIskR3u76CAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import copy, math\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "def gradient(x_train, y_train, w, b, alpha):\n",
    "    f = np.dot(x_train, w) + b\n",
    "    cost.append(np.sum(np.square(f - y_train)) / (2 * m))\n",
    "    w  = w - alpha * (np.dot((f - y_train).T, x_train)).T / m\n",
    "    b = b - alpha * np.sum(f - y_train) / m\n",
    "    return cost, w, b\n",
    "    \n",
    "np.set_printoptions(precision=2)  # reduced display precision on numpy arrays\n",
    "x_train = np.array([[2104, 5, 1, 45], \n",
    "                    [1416, 3, 2, 40], \n",
    "                    [852,  2, 1, 35]])\n",
    "y_train = np.array([[460], \n",
    "                  [232], \n",
    "                  [178]])\n",
    "m = x_train.shape[0]\n",
    "n = x_train.shape[1]\n",
    "# m = 3, n = 4\n",
    "# b = np.full((m, 1), 785.1811367994083)\n",
    "# w = np.array([0.39133535, 18.75376741, -53.36032453, -26.42131618]).reshape(-1, 1)\n",
    "w = np.zeros(4).reshape(-1, 1)\n",
    "b = np.zeros(3).reshape(-1, 1)\n",
    "alpha = 5.0e-7\n",
    "cost = []\n",
    "iterations = 1000\n",
    "for i in range(iterations):\n",
    "# while(cost > 1e-1):\n",
    "# for i in range (iterations):\n",
    "    # f = np.dot(x_train, w) + b\n",
    "    # cost.append(np.sum(np.square(f - y_train)) / (2 * m))\n",
    "    # w  = w - alpha * (np.dot((f - y_train).T, x_train)).T / m\n",
    "    # b = b - alpha * np.sum(f - y_train) / m\n",
    "# print(f\"cost = {cost} \\n\")\n",
    "    cost, w, b = gradient(x_train, y_train, w, b, alpha)\n",
    "print(f\"w = {w} \\n b = {b}\")\n",
    "\n",
    "plt.figure()\n",
    "plt.plot(np.arange(len(cost[100:])), cost[100:])\n",
    "plt.xlabel('iterations')\n",
    "plt.ylabel('cost')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "938da8df-32d5-4b98-8a41-49a68050930d",
   "metadata": {},
   "source": [
    "## Normalization\n",
    "\n",
    "用以将不同范围的数据缩放到相近的范围内，从而更快速地进行梯度下降法。\n",
    "\n",
    "* 由我们自己选定一个数（通常是一组数据中最大值），然后让数据的最大值和最小值都除以这个数，例如(500,1000)，选定1000，缩放后变为(0.5,1)\n",
    "* 均值归一化（Mean normalization）：$x_i := \\dfrac{x_i - \\mu_i}{max - min} $ \n",
    "* Z-score归一化（Z-score normalization）：  \n",
    "$$x^{(i)}_j = \\dfrac{x^{(i)}_j - \\mu_j}{\\sigma_j} \\\\ $$\n",
    "\\begin{align}\n",
    "\\mu_j &= \\frac{1}{m} \\sum_{i=0}^{m-1} x^{(i)}_j \\\\\n",
    "\\sigma^2_j &= \\frac{1}{m} \\sum_{i=0}^{m-1} (x^{(i)}_j - \\mu_j)^2 \n",
    "\\end{align}\n",
    "$$$$ "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "3152e291-0229-4d10-b19a-aa13cf5598a5",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "迭代次数为：343\n",
      "w = [[110.56]\n",
      " [-21.27]\n",
      " [-32.71]\n",
      " [-37.97]] \n",
      " b = [363.16]\n",
      "final cost = 219.20682452323885\n"
     ]
    },
    {
     "data": {
      "image/png": "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u01hYaH58MMPzfTp001KSkrYXQHtzT333GPWr19v9uzZY95++22TnZ1tunfvbg4cOGCMMeaOO+4wffr0MWvXrjXvvvuu8Xq9xuv12tzqb+7IkSPmvffeM++9956RZP77v//bvPfee+bTTz81xhjz8MMPm5SUFPPqq6+abdu2mZtuusn079/fHD9+3NrGuHHjzOWXX242bdpk3nrrLTNw4EAzadIkuw7pvHzdeThy5Ij55S9/aYqLi82ePXvMm2++aUaMGGEGDhxoqqurrW1E+3m48847TXJyslm/fr3Zv3+/9Tp27JhVc65/B/X19ebSSy81Y8eONaWlpWblypWmR48eZu7cuXYc0nk513n4+OOPzUMPPWTeffdds2fPHvPqq6+aCy+80Fx77bXWNtrDefjVr35lioqKzJ49e8y2bdvMr371K+NwOMxf//pXY0zH+C4Y8/XnIdLfBYJTG/fb3/7W9OnTx7hcLjN69Gjzzjvv2N2kVjVx4kTTs2dP43K5zAUXXGAmTpxoPv74Y2v98ePHzc9//nPTpUsXk5iYaL73ve+Z/fv329jilrFu3Toj6YzXlClTjDEnpiS4//77TVpamnG73WbMmDGmrKwsbBuHDh0ykyZNMklJScbj8ZipU6eaI0eO2HA05+/rzsOxY8fM2LFjTY8ePUxcXJzp27evuf3228/4HxLRfh4aO35J5vnnn7dqmvLv4JNPPjE33nijSUhIMN27dzf33HOPqauri/DRnL9znYfy8nJz7bXXmq5duxq3220GDBhg7r33XuP3+8O2E+3n4dZbbzV9+/Y1LpfL9OjRw4wZM8YKTcZ0jO+CMV9/HiL9XXAYY0zz+qgAAAA6JsY4AQAANBHBCQAAoIkITgAAAE1EcAIAAGgighMAAEATEZwAAACaiOAEAADQRAQnAACAJiI4AYgK1113nWbOnGl3M8I4HA698sordjcDQAQxcziAqHD48GHFxcWpc+fO6tevn2bOnBmxIPXAAw/olVdesR4cGuLz+dSlSxe53e6ItAOA/WLtbgAANEXXrl1bfJu1tbVyuVzn/fn09PQWbA2AaMClOgBRIXSp7rrrrtOnn36qWbNmyeFwyOFwWDVvvfWWrrnmGiUkJKh37976xS9+oaqqKmt9v3799K//+q/6yU9+Io/Ho+nTp0uS5syZo4svvliJiYm68MILdf/996uurk6SVFhYqAcffFDvv/++tb/CwkJJZ16q2759u2644QYlJCSoW7dumj59uo4ePWqt/+lPf6rx48frN7/5jXr27Klu3bopLy/P2pckPfXUUxo4cKDi4+OVlpam73//+61xOgGcJ4ITgKjy5z//Wb169dJDDz2k/fv3a//+/ZKk3bt3a9y4cZowYYK2bdumJUuW6K233tKMGTPCPv+b3/xGmZmZeu+993T//fdLkjp37qzCwkJ9+OGHevzxx/W73/1Ojz76qCRp4sSJuueeezR06FBrfxMnTjyjXVVVVcrJyVGXLl20ZcsWLVu2TG+++eYZ+1+3bp12796tdevWafHixSosLLSC2Lvvvqtf/OIXeuihh1RWVqaVK1fq2muvbelTCOCbMAAQBb71rW+Zu+++2xhjTN++fc2jjz4atn7atGlm+vTpYcv+9re/GafTaY4fP259bvz48efc1yOPPGJGjhxpvZ8/f77JzMw8o06Sefnll40xxjz77LOmS5cu5ujRo9b6FStWGKfTaXw+nzHGmClTppi+ffua+vp6q+YHP/iBmThxojHGmD/96U/G4/GYQCBwzjYCsAdjnAC0C++//762bdumF154wVpmjFEwGNSePXt0ySWXSJJGjRp1xmeXLFmiJ554Qrt379bRo0dVX18vj8fTrP3v3LlTmZmZ6tSpk7XsqquuUjAYVFlZmdLS0iRJQ4cOVUxMjFXTs2dPbd++XZL0T//0T+rbt68uvPBCjRs3TuPGjdP3vvc9JSYmNqstAFoPl+oAtAtHjx7Vz372M5WWllqv999/X7t27dJFF11k1Z0ebCSpuLhYkydP1re//W0tX75c7733nn7961+rtra2VdoZFxcX9t7hcCgYDEo6cclw69atevHFF9WzZ0/NmzdPmZmZqqysbJW2AGg+epwARB2Xy6WGhoawZSNGjNCHH36oAQMGNGtbGzduVN++ffXrX//aWvbpp5+ec39fdckll6iwsFBVVVVWOHv77bfldDo1aNCgJrcnNjZW2dnZys7O1vz585WSkqK1a9fq5ptvbsZRAWgt9DgBiDr9+vXThg0b9Pnnn+vgwYOSTtwZt3HjRs2YMUOlpaXatWuXXn311TMGZ3/VwIEDVV5erpdeekm7d+/WE088oZdffvmM/e3Zs0elpaU6ePCgampqztjO5MmTFR8frylTpuiDDz7QunXrdNddd+mWW26xLtOdy/Lly/XEE0+otLRUn376qX7/+98rGAw2K3gBaF0EJwBR56GHHtInn3yiiy66SD169JAkDR8+XEVFRfr73/+ua665RpdffrnmzZunjIyMr93Wd7/7Xc2aNUszZszQZZddpo0bN1p324VMmDBB48aN0/XXX68ePXroxRdfPGM7iYmJWrVqlQ4fPqwrrrhC3//+9zVmzBg9+eSTTT6ulJQU/fnPf9YNN9ygSy65RE8//bRefPFFDR06tMnbANC6mDkcAACgiehxAgAAaCKCEwAAQBMRnAAAAJqI4AQAANBEBCcAAIAmIjgBAAA0EcEJAACgiQhOAAAATURwAgAAaCKCEwAAQBMRnAAAAJro/wffq3UWB10ftQAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "房子的价格为：$ 318709.2998206627\n"
     ]
    }
   ],
   "source": [
    "def gradient(x_train, y_train, w, b, alpha):\n",
    "    f = np.dot(x_train, w) + b\n",
    "    cost.append(np.sum(np.square(f - y_train)) / (2 * m))\n",
    "    w  = w - alpha * (np.dot((f - y_train).T, x_train)).T / m\n",
    "    b = b - alpha * np.sum(f - y_train) / m\n",
    "    return cost, w, b\n",
    "\n",
    "def z_score_norm(x_train):\n",
    "    mean = np.mean(x_train, axis=0)\n",
    "    sigma = np.std(x_train, axis=0)\n",
    "    x_norm = (x_train - mean) / sigma\n",
    "    return mean, sigma, x_norm\n",
    "    \n",
    "data = np.loadtxt(\"houses.txt\", delimiter=',', skiprows=1)\n",
    "x_train = data[:,:4]\n",
    "y_train = data[:,4].reshape(-1,1)\n",
    "m = x_train.shape[0]\n",
    "n = x_train.shape[1]\n",
    "w = np.zeros(n).reshape(-1, 1)\n",
    "b = np.zeros(m).reshape(-1, 1)\n",
    "cost = []\n",
    "alpha = 1.0e-1\n",
    "num = 0\n",
    "x_mean, x_sigma, x_norm = z_score_norm(x_train)\n",
    "# print(f\"x_train = {x_train} \\n x_mean = {x_mean} \\n x_sigma = {x_sigma} \\n x_norm = {x_norm}\")\n",
    "while (1):\n",
    "    num = num + 1\n",
    "    cost, w, b = gradient(x_norm, y_train, w, b, alpha)\n",
    "    # print(cost)\n",
    "    if (len(cost) > 1):\n",
    "        if (abs(cost[len(cost)-1] - cost[len(cost)-2]) < 1e-8):\n",
    "            break\n",
    "\n",
    "print(f\"迭代次数为：{num}\")\n",
    "print(f\"w = {w} \\n b = {b[0]}\")\n",
    "print(f\"final cost = {cost[len(cost)-1]}\")\n",
    "plt.figure()\n",
    "plt.plot(np.arange(len(cost)), cost)\n",
    "plt.xlabel('iterations')\n",
    "plt.ylabel('cost')\n",
    "plt.show()\n",
    "\n",
    "#预测价格\n",
    "x1 = np.array([1200, 3, 1, 40])\n",
    "x1_norm = (x1 - x_mean) / x_sigma\n",
    "price = np.dot(x1_norm, w) + b[0]\n",
    "print(\"房子的价格为：$\", price[0]*1e3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f9911627-836a-49fc-9ba7-38bfbd625675",
   "metadata": {},
   "source": [
    "## 通过Z-score normalization对上一讲中的例题进行处理  \n",
    "| Size (sqft) | Number of Bedrooms  | Number of floors | Age of  Home | Price (1000s dollars)  |   \n",
    "| ----------------| ------------------- |----------------- |--------------|-------------- |  \n",
    "| 2104            | 5                   | 1                | 45           | 460           |  \n",
    "| 1416            | 3                   | 2                | 40           | 232           |  \n",
    "| 852             | 2                   | 1                | 35           | 178           |  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "66bd6570-b9d5-4dbc-9683-24ed98892c59",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "迭代次数为：133 \n",
      " w = [[ 38.05]\n",
      " [ 41.54]\n",
      " [-30.99]\n",
      " [ 36.34]] \n",
      " b = [290.] \n",
      " final cost = 3.5202911627464937e-08\n"
     ]
    },
    {
     "data": {
      "image/png": "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M2fO1Pz58yV1v+vxXaGcf0ZGRosbbZqamrRv374ue40Cgemrr77SypUrrV4mqXtejxMhNHVSsbGxGjlypIqKiqxtfr9fRUVFys7OtrGy8DDGaPr06Xr55Ze1atUqDRw4MGj/yJEjFRMTE3R9ysvLVVFR0SWvz1VXXaVNmzaprKzMeo0aNUqTJ0+2fu5O10OSLrroohbLUHz22Wfq37+/JGngwIHKyMgIuiZer1fvv/9+l7wmBw4ckNMZ/E96VFSU/H6/pO53Pb4rlPPPzs5WVVWVSktLrTarVq2S3+/XmDFjwl5zRwsEpq1bt+qtt95SWlpa0P7udj1CYvdMdBzbiy++aFwulyksLDSffPKJufnmm01qaqrxeDx2l9bhbr31VpOSkmLefvtts3PnTut14MABq80tt9xi+vXrZ1atWmU++OADk52dbbKzs22sOryOvHvOmO53PdatW2eio6PN73//e7N161bz3HPPmYSEBPN///d/Vpv777/fpKammldffdV89NFH5kc/+pEZOHCgOXjwoI2Vd4wpU6aYU0891Sxbtsxs27bNvPTSS6ZXr15m1qxZVpuufj1qamrMhx9+aD788EMjyfzP//yP+fDDD627wUI5/3HjxpnzzjvPvP/++2bNmjVm0KBBZtKkSXad0kk53vVoaGgw11xzjenbt68pKysL+ne2vr7eOkZXuh7tgdDUyT322GOmX79+JjY21owePdq89957dpcUFpKO+vrzn/9stTl48KC57bbbTI8ePUxCQoK59tprzc6dO+0rOsy+G5q64/V47bXXzNlnn21cLpcZMmSIefrpp4P2+/1+c/fdd5v09HTjcrnMVVddZcrLy22qtmN5vV5zxx13mH79+pm4uDhz2mmnmbvuuivoF2BXvx6rV68+6r8bU6ZMMcaEdv579+41kyZNMklJScbtdpupU6eampoaG87m5B3vemzbtu2Y/86uXr3aOkZXuh7twWHMEcvFAgAA4KiY0wQAABACQhMAAEAICE0AAAAhIDQBAACEgNAEAAAQAkITAABACAhNAAAAISA0AQAAhIDQBCAiXH755ZoxY4bdZQRxOBx65ZVX7C4DQJiwIjiAiLBv3z7FxMQoOTlZAwYM0IwZM8IWou655x698sorKisrC9ru8XjUo0cPuVyusNQBwF7RdhcAAKHo2bNnux+zoaFBsbGxbf58RkZGO1YDoLNjeA5ARAgMz11++eX66quvNHPmTDkcDjkcDqvNmjVrdMkllyg+Pl5ZWVn61a9+pdraWmv/gAED9Lvf/U433HCD3G63br75ZknS7NmzdeaZZyohIUGnnXaa7r77bjU2NkqSCgsLde+992rjxo3W9xUWFkpqOTy3adMmXXnllYqPj1daWppuvvlm7d+/39r/H//xHxo/frz+8Ic/qE+fPkpLS1N+fr71XZL0xBNPaNCgQYqLi1N6erp+/OMfd8TlBNAGhCYAEeWll15S3759dd9992nnzp3auXOnJOnzzz/XuHHjNGHCBH300UdavHix1qxZo+nTpwd9/g9/+INGjBihDz/8UHfffbckKTk5WYWFhfrkk0/06KOP6k9/+pMefvhhSdLEiRP161//WsOGDbO+b+LEiS3qqq2tVW5urnr06KH169dr6dKleuutt1p8/+rVq/X5559r9erVevbZZ1VYWGiFsA8++EC/+tWvdN9996m8vFxvvvmmLr300va+hADaygBABLjsssvMHXfcYYwxpn///ubhhx8O2j9t2jRz8803B2375z//aZxOpzl48KD1ufHjx5/wux566CEzcuRI6/28efPMiBEjWrSTZF5++WVjjDFPP/206dGjh9m/f7+1f/ny5cbpdBqPx2OMMWbKlCmmf//+pqmpyWrzk5/8xEycONEYY8zf/vY343a7jdfrPWGNAMKPOU0AuoSNGzfqo48+0nPPPWdtM8bI7/dr27ZtOuussyRJo0aNavHZxYsXa8GCBfr888+1f/9+NTU1ye12t+r7t2zZohEjRigxMdHadtFFF8nv96u8vFzp6emSpGHDhikqKspq06dPH23atEmS9P3vf1/9+/fXaaedpnHjxmncuHG69tprlZCQ0KpaAHQMhucAdAn79+/XL3/5S5WVlVmvjRs3auvWrTr99NOtdkeGGkkqKSnR5MmT9YMf/EDLli3Thx9+qLvuuksNDQ0dUmdMTEzQe4fDIb/fL6l5mHDDhg164YUX1KdPH82dO1cjRoxQVVVVh9QCoHXoaQIQcWJjY+Xz+YK2nX/++frkk090xhlntOpYa9euVf/+/XXXXXdZ27766qsTft93nXXWWSosLFRtba0VzN599105nU4NHjw45Hqio6OVk5OjnJwczZs3T6mpqVq1apWuu+66VpwVgI5ATxOAiDNgwAC98847+uabb7Rnzx5JzXfArV27VtOnT1dZWZm2bt2qV199tcVE7O8aNGiQKioq9OKLL+rzzz/XggUL9PLLL7f4vm3btqmsrEx79uxRfX19i+NMnjxZcXFxmjJlijZv3qzVq1fr9ttv1/XXX28NzZ3IsmXLtGDBApWVlemrr77SX/7yF/n9/laFLgAdh9AEIOLcd999+vLLL3X66afrlFNOkSSdc845Ki4u1meffaZLLrlE5513nubOnavMzMzjHuuaa67RzJkzNX36dJ177rlau3atdVddwIQJEzRu3DhdccUVOuWUU/TCCy+0OE5CQoJWrFihffv26YILLtCPf/xjXXXVVXr88cdDPq/U1FS99NJLuvLKK3XWWWfpySef1AsvvKBhw4aFfAwAHYcVwQEAAEJATxMAAEAICE0AAAAhIDQBAACEgNAEAAAQAkITAABACAhNAAAAISA0AQAAhIDQBAAAEAJCEwAAQAgITQAAACEgNAEAAITg/wcgL24fQZSRlQAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "x_train = np.array([[2104, 5, 1, 45], \n",
    "                    [1416, 3, 2, 40], \n",
    "                    [852,  2, 1, 35]])\n",
    "y_train = np.array([[460], \n",
    "                  [232], \n",
    "                  [178]])\n",
    "m = x_train.shape[0]\n",
    "n = x_train.shape[1]\n",
    "w = np.zeros(n).reshape(-1, 1)\n",
    "b = np.zeros(m).reshape(-1, 1)\n",
    "alpha = 1.0e-1\n",
    "cost = []\n",
    "num = 0\n",
    "x_mean, x_sigma, x_norm = z_score_norm(x_train)\n",
    "# iterations = 1000\n",
    "while (1):\n",
    "    num = num + 1\n",
    "    cost, w, b = gradient(x_norm, y_train, w, b, alpha)\n",
    "    if (len(cost) > 1):\n",
    "        if (abs(cost[len(cost)-1] - cost[len(cost)-2]) < 1e-8):\n",
    "            break\n",
    "print(f\"迭代次数为：{num} \\n w = {w} \\n b = {b[0]} \\n final cost = {cost[len(cost)-1]}\")\n",
    "\n",
    "plt.figure()\n",
    "plt.plot(np.arange(len(cost)), cost)\n",
    "plt.xlabel('iterations')\n",
    "plt.ylabel('cost')\n",
    "plt.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {
    "height": "calc(100% - 180px)",
    "left": "10px",
    "top": "150px",
    "width": "366px"
   },
   "toc_section_display": true,
   "toc_window_display": true
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
