{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Practical Lab Machine Learning Sheet 2\n",
    "### Authors: Yannick Burchart, Christoph Smoch"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Task 2.1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "def func_f(beta, y, X, b):\n",
    "    return (X @ X.T) @ (beta*y) + b * np.ones(len(y))\n",
    "\n",
    "def OneStep(i, j, beta, y, X, b, C):\n",
    "    f = func_f(beta, y, X, b)\n",
    "    delta = y[i] * ((f[j] - y[j]) - (f[i] - y[i]))\n",
    "    s = y[i] * y[j]\n",
    "    chi = np.linalg.norm(X[i] - X[j])**2\n",
    "    gamma = s * beta[i] + beta[j]\n",
    "    if s == 1:\n",
    "        L = max(0, gamma - C)\n",
    "        H = min(gamma, C)\n",
    "    else:\n",
    "        L = max(0, - gamma)\n",
    "        H = min(C,  C - gamma)\n",
    "    if chi > 0:\n",
    "        beta[i] = min(max(beta[i] + delta / chi, L), H)\n",
    "    elif delta > 0:\n",
    "        beta[i] = L\n",
    "    else:\n",
    "        beta[i] = H\n",
    "    beta[j] = gamma - s * beta[i]\n",
    "    f = func_f(beta, y, X, b)\n",
    "    b = b - 0.5 * (f[i] - y[i] + f[j] - y[j])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Task 2.2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "X = np.zeros((40, 2))\n",
    "X[:20] = np.random.exponential([4, 4], (20, 2))\n",
    "X[20:40] = np.random.exponential([0.5, 0.5], (20, 2))\n",
    "y = np.ones(40)\n",
    "y[:20] = -1 * np.ones(20)\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "plt.scatter(X[:20, 0], X[:20, 1], label = '-1')\n",
    "plt.scatter(X[20:40, 0], X[20:40, 1], label = '1')\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Task 2.3"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 2.3 a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [],
   "source": [
    "def SMO(X, y, max_iter, C):\n",
    "    n = X.shape[0]\n",
    "    beta = np.zeros(X.shape[0])\n",
    "    b = 0\n",
    "    iter = 0\n",
    "    while iter < max_iter:\n",
    "        i = 0\n",
    "        j = 0\n",
    "        while i == j:\n",
    "            i, j = np.random.randint(0, n, 2)\n",
    "        OneStep(i, j, beta, y, X, b, C)\n",
    "        iter += 1\n",
    "    f = func_f(beta, y, X, b)\n",
    "    med = np.median(((beta > 0) * (f - y))[np.nonzero((beta > 0) * (f - y))])\n",
    "    #print(med)\n",
    "    #print(b)\n",
    "    b = b - med\n",
    "    return beta, b"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 2.3 b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Number of Support Vectors for C = 0.01 : 30\n",
      "Number of Margin Defining Vectors for C = 0.01 : 2\n",
      "Number of Support Vectors for C = 1 : 12\n",
      "Number of Margin Defining Vectors for C = 1 : 3\n",
      "Number of Support Vectors for C = 100 : 20\n",
      "Number of Margin Defining Vectors for C = 100 : 16\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<matplotlib.legend.Legend at 0x1fb8c0afe80>"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "#SMO(X, y, 10000, 0.1)\n",
    "def f_func_plot(beta, y, X, x_1, x_2, b):\n",
    "    summe = 0\n",
    "    for i in range(len(y)):\n",
    "        summe += y[i]*beta[i]*(X[i, 0]*x_1 + X[i, 1]*x_2)\n",
    "    summe += b\n",
    "    return summe\n",
    "delta = 0.01\n",
    "x_1 = np.arange(min(X[:, 0])- 2,max(X[:, 0] + 1), delta)\n",
    "x_2 = np.arange(min(X[:, 1]) - 2,max(X[:, 1] + 1), delta)\n",
    "X_1, X_2 = np.meshgrid(x_1, x_2)\n",
    "\n",
    "C = 0.01\n",
    "\n",
    "fig, ax = plt.subplots()\n",
    "beta, b = SMO(X, y, 10000, C)\n",
    "num_SV = np.sum(beta > 0)\n",
    "num_MDV = np.sum(np.logical_and(beta > 0, beta < C))\n",
    "print(\"Number of Support Vectors for C = \" + str(C) + \" : \" + str(num_SV))\n",
    "print(\"Number of Margin Defining Vectors for C = \" + str(C) + \" : \" + str(num_MDV))\n",
    "ax.contourf(X_1, X_2, f_func_plot(beta, y, X, X_1, X_2, b), 1, colors=['moccasin', 'skyblue'])\n",
    "ax.scatter(X[:20, 0], X[:20, 1], label='-1')\n",
    "ax.scatter(X[20:40, 0], X[20:40, 1], label='1')\n",
    "supVec = X[np.nonzero(beta > 0)]\n",
    "margDefVec = X[np.nonzero(np.logical_and(beta > 0, beta < C))]\n",
    "ax.scatter(supVec[:, 0], supVec[:, 1], label= 'Support Vectors', marker = '+')\n",
    "ax.scatter(margDefVec[:, 0], margDefVec[:, 1], label= 'Marge Defining Vectors', marker = 'x')\n",
    "ax.legend()\n",
    "\n",
    "C = 1\n",
    "\n",
    "fig, ax = plt.subplots()\n",
    "beta, b = SMO(X, y, 10000, C)\n",
    "num_SV = np.sum(beta > 0)\n",
    "num_MDV = np.sum(np.logical_and(beta > 0, beta < C))\n",
    "print(\"Number of Support Vectors for C = \" + str(C) + \" : \" + str(num_SV))\n",
    "print(\"Number of Margin Defining Vectors for C = \" + str(C) + \" : \" + str(num_MDV))\n",
    "ax.contourf(X_1, X_2, f_func_plot(beta, y, X, X_1, X_2, b), 1, colors=['moccasin', 'skyblue'])\n",
    "ax.scatter(X[:20, 0], X[:20, 1], label='-1')\n",
    "ax.scatter(X[20:40, 0], X[20:40, 1], label='1')\n",
    "supVec = X[np.nonzero(beta > 0)]\n",
    "margDefVec = X[np.nonzero(np.logical_and(beta > 0, beta < C))]\n",
    "ax.scatter(supVec[:, 0], supVec[:, 1], label= 'Support Vectors', marker = '+')\n",
    "ax.scatter(margDefVec[:, 0], margDefVec[:, 1], label= 'Marge Defining Vectors', marker = 'x')\n",
    "ax.legend()\n",
    "\n",
    "C = 100\n",
    "\n",
    "fig, ax = plt.subplots()\n",
    "beta, b = SMO(X, y, 10000, C)\n",
    "num_SV = np.sum(beta > 0)\n",
    "num_MDV = np.sum(np.logical_and(beta > 0, beta < C))\n",
    "print(\"Number of Support Vectors for C = \" + str(C) + \" : \" + str(num_SV))\n",
    "print(\"Number of Margin Defining Vectors for C = \" + str(C) + \" : \" + str(num_MDV))\n",
    "ax.contourf(X_1, X_2, f_func_plot(beta, y, X, X_1, X_2, b), 1, colors=['moccasin', 'skyblue'])\n",
    "ax.scatter(X[:20, 0], X[:20, 1], label='-1')\n",
    "ax.scatter(X[20:40, 0], X[20:40, 1], label='1')\n",
    "supVec = X[np.nonzero(beta > 0)]\n",
    "margDefVec = X[np.nonzero(np.logical_and(beta > 0, beta < C))]\n",
    "ax.scatter(supVec[:, 0], supVec[:, 1], label= 'Support Vectors', marker = '+')\n",
    "ax.scatter(margDefVec[:, 0], margDefVec[:, 1], label= 'Marge Defining Vectors', marker = 'x')\n",
    "ax.legend()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Linear least squares:\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<matplotlib.legend.Legend at 0x1fb8c191470>"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "def LLS(X, y):\n",
    "    X_1 = np.transpose(X) @ X\n",
    "    a = np.linalg.solve(X_1, np.transpose(X) @ y)\n",
    "    return a\n",
    "k = np.ones((40, 1))\n",
    "X_new = np.concatenate((k, X), axis = 1)\n",
    "alpha = LLS(X_new, y)\n",
    "def z(x_1, x_2, alpha):\n",
    "    return alpha[0] + alpha[1]*x_1 + alpha[2]*x_2 - 0.5\n",
    "print(\"Linear least squares:\")\n",
    "fig, ax = plt.subplots()\n",
    "ax.contourf(X_1, X_2, z(X_1, X_2, alpha),1, colors=['moccasin', 'skyblue'])\n",
    "ax.scatter(X[:20, 0], X[:20, 1], label='-1')\n",
    "ax.scatter(X[20:40, 0], X[20:40, 1], label='1')\n",
    "ax.legend()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Task 2.4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Accuracy of LLS: \n",
      "0.556\n",
      "Accuracy of SVM with C = 0.01 :\n",
      "0.9115\n",
      "Accuracy of SVM with C = 1 :\n",
      "0.887\n",
      "Accuracy of SVM with C = 100 :\n",
      "0.845\n"
     ]
    }
   ],
   "source": [
    "X = np.zeros((2000, 2))\n",
    "X[:1000] = np.random.exponential([4, 4], (1000, 2))\n",
    "X[1000:2000] = np.random.exponential([0.5, 0.5], (1000, 2))\n",
    "y = np.ones(2000)\n",
    "y[:1000] = -1 * np.ones(1000)\n",
    "\n",
    "print(\"Accuracy of LLS: \")\n",
    "k = np.ones((2000, 1))\n",
    "X_new = np.concatenate((k, X), axis = 1)\n",
    "alpha = LLS(X_new, y)\n",
    "C_LLS = np.zeros((2, 2))\n",
    "C_LLS[0, 0] = np.sum(z(X[:1000, 0], X[:1000, 1], alpha) < 0)\n",
    "C_LLS[0, 1] = np.sum(z(X[:1000, 0], X[:1000, 1], alpha) > 0)\n",
    "C_LLS[1, 0] = np.sum(z(X[1000:2000, 0], X[1000:2000, 1], alpha) < 0)\n",
    "C_LLS[1, 1] = np.sum(z(X[1000:2000, 0], X[1000:2000, 1], alpha) > 0)\n",
    "accuracy = np.trace(C_LLS)/2000\n",
    "print(accuracy)\n",
    "\n",
    "def func_f_2(beta, y, X, b, x):\n",
    "    return (x @ X.T) @ (beta*y) + b * np.ones(x.shape[0])\n",
    "\n",
    "\n",
    "C = 0.01\n",
    "print(\"Accuracy of SVM with C = \" + str(C) + \" :\")\n",
    "beta, b = SMO(X, y, 1000, C)\n",
    "C_SVM_1 = np.zeros((2, 2))\n",
    "C_SVM_1[0, 0] = np.sum(func_f_2(beta, y, X, b, X[:1000]) < 0)\n",
    "C_SVM_1[0, 1] = np.sum(func_f_2(beta, y, X, b, X[:1000]) > 0)\n",
    "C_SVM_1[1, 0] = np.sum(func_f_2(beta, y, X, b, X[1000:2000]) < 0)\n",
    "C_SVM_1[1, 1] = np.sum(func_f_2(beta, y, X, b, X[1000:2000]) > 0)\n",
    "accuracy = np.trace(C_SVM_1)/2000\n",
    "print(accuracy)\n",
    "\n",
    "C = 1\n",
    "print(\"Accuracy of SVM with C = \" + str(C) + \" :\")\n",
    "beta, b = SMO(X, y, 1000, C)\n",
    "C_SVM_1 = np.zeros((2, 2))\n",
    "C_SVM_1[0, 0] = np.sum(func_f_2(beta, y, X, b, X[:1000]) < 0)\n",
    "C_SVM_1[0, 1] = np.sum(func_f_2(beta, y, X, b, X[:1000]) > 0)\n",
    "C_SVM_1[1, 0] = np.sum(func_f_2(beta, y, X, b, X[1000:2000]) < 0)\n",
    "C_SVM_1[1, 1] = np.sum(func_f_2(beta, y, X, b, X[1000:2000]) > 0)\n",
    "accuracy = np.trace(C_SVM_1)/2000\n",
    "print(accuracy)\n",
    "\n",
    "C = 100\n",
    "print(\"Accuracy of SVM with C = \" + str(C) + \" :\")\n",
    "beta, b = SMO(X, y, 1000, C)\n",
    "C_SVM_1 = np.zeros((2, 2))\n",
    "C_SVM_1[0, 0] = np.sum(func_f_2(beta, y, X, b, X[:1000]) < 0)\n",
    "C_SVM_1[0, 1] = np.sum(func_f_2(beta, y, X, b, X[:1000]) > 0)\n",
    "C_SVM_1[1, 0] = np.sum(func_f_2(beta, y, X, b, X[1000:2000]) < 0)\n",
    "C_SVM_1[1, 1] = np.sum(func_f_2(beta, y, X, b, X[1000:2000]) > 0)\n",
    "accuracy = np.trace(C_SVM_1)/2000\n",
    "print(accuracy)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Task 2.5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [],
   "source": [
    "def SMO_KKT(X, y, max_iter, C):\n",
    "    n = X.shape[0]\n",
    "    beta = np.zeros(X.shape[0])\n",
    "    b = 0\n",
    "    iter = 0\n",
    "    while iter < max_iter:\n",
    "        f = func_f(beta, y, X, b)\n",
    "        for i in range(n):\n",
    "            KKT = (C - beta[i]) * max(0, 1 - y[i] * f[i]) + beta[i] * max(0, y[i] * f[i] - 1)\n",
    "            if KKT > 0:\n",
    "                j = np.random.randint(0, n)\n",
    "                if sum(np.logical_and(beta > 0, beta < C)) > 0:    \n",
    "                    while i == j and (beta[j] < 0 or beta[j] > C):\n",
    "                        j = np.random.randint(0, n)\n",
    "                else:\n",
    "                    while i == j:\n",
    "                        j = np.random.randint(0,n)\n",
    "                break\n",
    "        if KKT == 0:\n",
    "            med = np.median(((beta > 0) * (f - y))[np.nonzero((beta > 0) * (f - y))])\n",
    "            b = b - med\n",
    "            break\n",
    "            return beta, b\n",
    " \n",
    "        OneStep(i, j, beta, y, X, b, C)\n",
    "        iter += 1\n",
    "    if iter == max_iter:\n",
    "        f = func_f(beta, y, X, b)\n",
    "        med = np.median(((beta > 0) * (f - y))[np.nonzero((beta > 0) * (f - y))])\n",
    "        b = b - med\n",
    "        return beta, b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Accuracy of SVM with C = 0.01 :\n",
      "0.775\n",
      "Number of Support Vectors for C = 0.01 : 25\n",
      "Number of Margin Defining Vectors for C = 0.01 : 9\n",
      "Accuracy of SVM with C = 1 :\n",
      "0.95\n",
      "Number of Support Vectors for C = 1 : 27\n",
      "Number of Margin Defining Vectors for C = 1 : 22\n",
      "Accuracy of SVM with C = 100 :\n",
      "0.725\n",
      "Number of Support Vectors for C = 100 : 37\n",
      "Number of Margin Defining Vectors for C = 100 : 37\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<matplotlib.legend.Legend at 0x1fb8c2d15c0>"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "X = np.zeros((40, 2))\n",
    "X[:20] = np.random.exponential([4, 4], (20, 2))\n",
    "X[20:40] = np.random.exponential([0.5, 0.5], (20, 2))\n",
    "y = np.ones(40)\n",
    "y[:20] = -1 * np.ones(20)\n",
    "\n",
    "delta = 0.01\n",
    "x_1 = np.arange(min(X[:, 0])- 2,max(X[:, 0] + 1), delta)\n",
    "x_2 = np.arange(min(X[:, 1]) - 2,max(X[:, 1] + 1), delta)\n",
    "X_1, X_2 = np.meshgrid(x_1, x_2)\n",
    "\n",
    "C = 0.01\n",
    "\n",
    "fig, ax = plt.subplots()\n",
    "beta, b = SMO_KKT(X, y, 10000, C)\n",
    "print(\"Accuracy of SVM with C = \" + str(C) + \" :\")\n",
    "C_SVM_1 = np.zeros((2, 2))\n",
    "C_SVM_1[0, 0] = np.sum(func_f_2(beta, y, X, b, X[:20]) < 0)\n",
    "C_SVM_1[0, 1] = np.sum(func_f_2(beta, y, X, b, X[:20]) > 0)\n",
    "C_SVM_1[1, 0] = np.sum(func_f_2(beta, y, X, b, X[20:40]) < 0)\n",
    "C_SVM_1[1, 1] = np.sum(func_f_2(beta, y, X, b, X[20:40]) > 0)\n",
    "accuracy = np.trace(C_SVM_1)/40\n",
    "print(accuracy)\n",
    "\n",
    "num_SV = np.sum(beta > 0)\n",
    "num_MDV = np.sum(np.logical_and(beta > 0, beta < C))\n",
    "print(\"Number of Support Vectors for C = \" + str(C) + \" : \" + str(num_SV))\n",
    "print(\"Number of Margin Defining Vectors for C = \" + str(C) + \" : \" + str(num_MDV))\n",
    "ax.contourf(X_1, X_2, f_func_plot(beta, y, X, X_1, X_2, b), 1, colors=['moccasin', 'skyblue'])\n",
    "ax.scatter(X[:20, 0], X[:20, 1], label='-1')\n",
    "ax.scatter(X[20:40, 0], X[20:40, 1], label='1')\n",
    "supVec = X[np.nonzero(beta > 0)]\n",
    "margDefVec = X[np.nonzero(np.logical_and(beta > 0, beta < C))]\n",
    "ax.scatter(supVec[:, 0], supVec[:, 1], label= 'Support Vectors', marker = '+')\n",
    "ax.scatter(margDefVec[:, 0], margDefVec[:, 1], label= 'Marge Defining Vectors', marker = 'x')\n",
    "ax.legend()\n",
    "\n",
    "C = 1\n",
    "\n",
    "fig, ax = plt.subplots()\n",
    "beta, b = SMO_KKT(X, y, 10000, C)\n",
    "print(\"Accuracy of SVM with C = \" + str(C) + \" :\")\n",
    "C_SVM_1 = np.zeros((2, 2))\n",
    "C_SVM_1[0, 0] = np.sum(func_f_2(beta, y, X, b, X[:20]) < 0)\n",
    "C_SVM_1[0, 1] = np.sum(func_f_2(beta, y, X, b, X[:20]) > 0)\n",
    "C_SVM_1[1, 0] = np.sum(func_f_2(beta, y, X, b, X[20:40]) < 0)\n",
    "C_SVM_1[1, 1] = np.sum(func_f_2(beta, y, X, b, X[20:40]) > 0)\n",
    "accuracy = np.trace(C_SVM_1)/40\n",
    "print(accuracy)\n",
    "\n",
    "num_SV = np.sum(beta > 0)\n",
    "num_MDV = np.sum(np.logical_and(beta > 0, beta < C))\n",
    "print(\"Number of Support Vectors for C = \" + str(C) + \" : \" + str(num_SV))\n",
    "print(\"Number of Margin Defining Vectors for C = \" + str(C) + \" : \" + str(num_MDV))\n",
    "ax.contourf(X_1, X_2, f_func_plot(beta, y, X, X_1, X_2, b), 1, colors=['moccasin', 'skyblue'])\n",
    "ax.scatter(X[:20, 0], X[:20, 1], label='-1')\n",
    "ax.scatter(X[20:40, 0], X[20:40, 1], label='1')\n",
    "supVec = X[np.nonzero(beta > 0)]\n",
    "margDefVec = X[np.nonzero(np.logical_and(beta > 0, beta < C))]\n",
    "ax.scatter(supVec[:, 0], supVec[:, 1], label= 'Support Vectors', marker = '+')\n",
    "ax.scatter(margDefVec[:, 0], margDefVec[:, 1], label= 'Marge Defining Vectors', marker = 'x')\n",
    "ax.legend()\n",
    "\n",
    "C = 100\n",
    "\n",
    "fig, ax = plt.subplots()\n",
    "beta, b = SMO_KKT(X, y, 10000, C)\n",
    "print(\"Accuracy of SVM with C = \" + str(C) + \" :\")\n",
    "C_SVM_1 = np.zeros((2, 2))\n",
    "C_SVM_1[0, 0] = np.sum(func_f_2(beta, y, X, b, X[:20]) < 0)\n",
    "C_SVM_1[0, 1] = np.sum(func_f_2(beta, y, X, b, X[:20]) > 0)\n",
    "C_SVM_1[1, 0] = np.sum(func_f_2(beta, y, X, b, X[20:40]) < 0)\n",
    "C_SVM_1[1, 1] = np.sum(func_f_2(beta, y, X, b, X[20:40]) > 0)\n",
    "accuracy = np.trace(C_SVM_1)/40\n",
    "print(accuracy)\n",
    "\n",
    "num_SV = np.sum(beta > 0)\n",
    "num_MDV = np.sum(np.logical_and(beta > 0, beta < C))\n",
    "print(\"Number of Support Vectors for C = \" + str(C) + \" : \" + str(num_SV))\n",
    "print(\"Number of Margin Defining Vectors for C = \" + str(C) + \" : \" + str(num_MDV))\n",
    "ax.contourf(X_1, X_2, f_func_plot(beta, y, X, X_1, X_2, b), 1, colors=['moccasin', 'skyblue'])\n",
    "ax.scatter(X[:20, 0], X[:20, 1], label='-1')\n",
    "ax.scatter(X[20:40, 0], X[20:40, 1], label='1')\n",
    "supVec = X[np.nonzero(beta > 0)]\n",
    "margDefVec = X[np.nonzero(np.logical_and(beta > 0, beta < C))]\n",
    "ax.scatter(supVec[:, 0], supVec[:, 1], label= 'Support Vectors', marker = '+')\n",
    "ax.scatter(margDefVec[:, 0], margDefVec[:, 1], label= 'Marge Defining Vectors', marker = 'x')\n",
    "ax.legend()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Accuracy of SVM with C = 0.01 :\n",
      "0.919\n",
      "Number of Support Vectors for C = 0.01 : 148\n",
      "Number of Margin Defining Vectors for C = 0.01 : 13\n",
      "Accuracy of SVM with C = 1 :\n",
      "0.891\n",
      "Number of Support Vectors for C = 1 : 65\n",
      "Number of Margin Defining Vectors for C = 1 : 44\n",
      "Accuracy of SVM with C = 100 :\n",
      "0.7775\n",
      "Number of Support Vectors for C = 100 : 256\n",
      "Number of Margin Defining Vectors for C = 100 : 256\n"
     ]
    }
   ],
   "source": [
    "X = np.zeros((2000, 2))\n",
    "X[:1000] = np.random.exponential([4, 4], (1000, 2))\n",
    "X[1000:2000] = np.random.exponential([0.5, 0.5], (1000, 2))\n",
    "y = np.ones(2000)\n",
    "y[:1000] = -1 * np.ones(1000)\n",
    "\n",
    "C = 0.01\n",
    "\n",
    "beta, b = SMO_KKT(X, y, 1000, C)\n",
    "print(\"Accuracy of SVM with C = \" + str(C) + \" :\")\n",
    "C_SVM_1 = np.zeros((2, 2))\n",
    "C_SVM_1[0, 0] = np.sum(func_f_2(beta, y, X, b, X[:1000]) < 0)\n",
    "C_SVM_1[0, 1] = np.sum(func_f_2(beta, y, X, b, X[:1000]) > 0)\n",
    "C_SVM_1[1, 0] = np.sum(func_f_2(beta, y, X, b, X[1000:2000]) < 0)\n",
    "C_SVM_1[1, 1] = np.sum(func_f_2(beta, y, X, b, X[1000:2000]) > 0)\n",
    "accuracy = np.trace(C_SVM_1)/2000\n",
    "print(accuracy)\n",
    "\n",
    "num_SV = np.sum(beta > 0)\n",
    "num_MDV = np.sum(np.logical_and(beta > 0, beta < C))\n",
    "print(\"Number of Support Vectors for C = \" + str(C) + \" : \" + str(num_SV))\n",
    "print(\"Number of Margin Defining Vectors for C = \" + str(C) + \" : \" + str(num_MDV))\n",
    "\n",
    "C = 1\n",
    "\n",
    "beta, b = SMO_KKT(X, y, 1000, C)\n",
    "print(\"Accuracy of SVM with C = \" + str(C) + \" :\")\n",
    "C_SVM_1 = np.zeros((2, 2))\n",
    "C_SVM_1[0, 0] = np.sum(func_f_2(beta, y, X, b, X[:1000]) < 0)\n",
    "C_SVM_1[0, 1] = np.sum(func_f_2(beta, y, X, b, X[:1000]) > 0)\n",
    "C_SVM_1[1, 0] = np.sum(func_f_2(beta, y, X, b, X[1000:2000]) < 0)\n",
    "C_SVM_1[1, 1] = np.sum(func_f_2(beta, y, X, b, X[1000:2000]) > 0)\n",
    "accuracy = np.trace(C_SVM_1)/2000\n",
    "print(accuracy)\n",
    "\n",
    "num_SV = np.sum(beta > 0)\n",
    "num_MDV = np.sum(np.logical_and(beta > 0, beta < C))\n",
    "print(\"Number of Support Vectors for C = \" + str(C) + \" : \" + str(num_SV))\n",
    "print(\"Number of Margin Defining Vectors for C = \" + str(C) + \" : \" + str(num_MDV))\n",
    "\n",
    "C = 100\n",
    "\n",
    "beta, b = SMO_KKT(X, y, 1000, C)\n",
    "print(\"Accuracy of SVM with C = \" + str(C) + \" :\")\n",
    "C_SVM_1 = np.zeros((2, 2))\n",
    "C_SVM_1[0, 0] = np.sum(func_f_2(beta, y, X, b, X[:1000]) < 0)\n",
    "C_SVM_1[0, 1] = np.sum(func_f_2(beta, y, X, b, X[:1000]) > 0)\n",
    "C_SVM_1[1, 0] = np.sum(func_f_2(beta, y, X, b, X[1000:2000]) < 0)\n",
    "C_SVM_1[1, 1] = np.sum(func_f_2(beta, y, X, b, X[1000:2000]) > 0)\n",
    "accuracy = np.trace(C_SVM_1)/2000\n",
    "print(accuracy)\n",
    "\n",
    "num_SV = np.sum(beta > 0)\n",
    "num_MDV = np.sum(np.logical_and(beta > 0, beta < C))\n",
    "print(\"Number of Support Vectors for C = \" + str(C) + \" : \" + str(num_SV))\n",
    "print(\"Number of Margin Defining Vectors for C = \" + str(C) + \" : \" + str(num_MDV))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "C=0.1\n",
      "SVM KK:\n",
      "130 ms ± 1.62 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "SVM:\n",
      "35.4 ms ± 474 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "C=1\n",
      "SVM KK:\n",
      "124 ms ± 753 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "SVM:\n",
      "36 ms ± 268 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "C=100\n",
      "SVM KK:\n",
      "125 ms ± 541 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "SVM:\n",
      "35.7 ms ± 143 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n"
     ]
    }
   ],
   "source": [
    "#Runtime:\n",
    "X = np.zeros((40, 2))\n",
    "X[:20] = np.random.exponential([4, 4], (20, 2))\n",
    "X[20:40] = np.random.exponential([0.5, 0.5], (20, 2))\n",
    "y = np.ones(40)\n",
    "y[:20] = -1 * np.ones(20)\n",
    "\n",
    "print('C=0.1')\n",
    "C=0.1\n",
    "print('SVM KK:')\n",
    "%timeit SMO_KKT(X, y, 1000, C)\n",
    "print('SVM:')\n",
    "%timeit SMO(X, y, 1000, C)\n",
    "\n",
    "print('C=1')\n",
    "C=1\n",
    "print('SVM KK:')\n",
    "%timeit SMO_KKT(X, y, 1000, C)\n",
    "print('SVM:')\n",
    "%timeit SMO(X, y, 1000, C)\n",
    "\n",
    "print('C=100')\n",
    "C=100\n",
    "print('SVM KK:')\n",
    "%timeit SMO_KKT(X, y, 1000, C)\n",
    "print('SVM:')\n",
    "%timeit SMO(X, y, 1000, C)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Task 2.6"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXYAAAD8CAYAAABjAo9vAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvOIA7rQAAHYtJREFUeJzt3X+MXWWZB/Dvt9MLM0W2Q6ENdqbYJkuKUsp0nSCExNWCtgrUyiqIP1bCJo0JBES32C4bqIpr3RogRDZuA8ZNRGRUKD+qliq6BrKgUzodwNLV+ItpJZRqiy6DnU6f/ePeW+7cOefec+557/nx3u8naaZz58w5b+d2nvve533e59DMICIi/piR9QBERMQtBXYREc8osIuIeEaBXUTEMwrsIiKeUWAXEfGMs8BOsovkTpKPuDqniIjE53LGfh2A3Q7PJyIiLXAS2En2A7gIwF0uziciIq2b6eg8twO4AcCJYQeQXANgDQCccMIJbz3jjDMcXVpEpDPs2LHjZTOb2+y4xIGd5MUAXjKzHSTfEXacmW0GsBkABgcHbXh4OOmlRUQ6CsnfRTnORSrmfACrSP4WwLcALCf5DQfnFRGRFiQO7Ga23sz6zWwhgA8BeMzMPpp4ZCIi0hLVsYuIeMbV4ikAwMx+AuAnLs8pIpLExMQExsbG8Nprr2U9lMi6u7vR39+PUqnU0vc7DewiInkzNjaGE088EQsXLgTJrIfTlJnhwIEDGBsbw6JFi1o6h1IxIuK11157DSeffHIhgjoAkMTJJ5+c6B2GAruIeK8oQb0q6XgV2EVEPKPALiKSkueffx7nnXcejj/+eHz5y19u23W0eCoikpI5c+bgjjvuwJYtW9p6HQV2EZEaW3buxaZte7Dv4Djm9/Zg7YrFWL2sz8m5582bh3nz5mHr1q1OzhdGgV1EpGLLzr1Yf/8zGJ+YBADsPTiO9fc/AwDOgnsalGMXEanYtG3PsaBeNT4xiU3b9mQ0otYosIuIVOw7OB7r8SjuvPNODAwMYGBgAPv27Wv5PHEosIuIVMzv7Yn1eBRXX301RkZGMDIygvnz57d8njgU2EVEKtauWIyeUteUx3pKXVi7YrGT87/44ovo7+/HrbfeiltuuQX9/f145ZVXnJy7lhZPRUQqqguk7aqKOfXUUzE2NubkXI0osIuI1Fi9rK9QFTBBlIoREfGMAruIiGcU2EVEPKPALiLimcSBnWQ3yZ+R3EXyOZKfdTEwERFpjYsZ+18BLDezswEMAFhJ8lwH5xUR8cJVV12FefPmYcmSJalcL3Fgt7K/VD4tVf5Y0vOKiPjiyiuvxA9+8IPUruckx06yi+QIgJcAbDezp1ycV0QkdaNDwG1LgA295Y+jQ4lP+fa3vx1z5sxxMLhonAR2M5s0swEA/QDOITnt/QbJNSSHSQ7v37/fxWVFRNwaHQIevhY49AIAK398+FonwT1NTqtizOwggJ8AWBnwtc1mNmhmg3PnznV5WRERN370OWCirpPjxHj58QJxURUzl2Rv5e89AC4E8HzS84qIpO5QSB+XsMdzykWvmDcC+C+SXSi/UAyZ2SMOzisikq7Z/ZU0TMDjBeKiKmbUzJaZ2VIzW2JmxXrPIiJSdcFNQKmu93qpp/x4AldccQXOO+887NmzB/39/bj77rsTna8ZdXcUEalaeln5448+V06/zO4vB/Xq4y269957HQwuOgV2EZFaSy9LHMizpl4xIiKeUWAXEe+ZFWszfNLxKrCLiNe6u7tx4MCBwgR3M8OBAwfQ3d3d8jmUYxcRr/X392NsbAxF2vHe3d2N/v7WSywV2EXEa6VSCYsWLcp6GKlSKkZExDMK7CIinlFgFxHxjAK7iIhnFNhFRDyjwC4i4hkFdhERzyiwi4h4RoFdRMQzCuwiIp5RYBcR8YwCu4iIZxIHdpILSP6Y5G6Sz5G8zsXARESkNS66Ox4B8Gkze5rkiQB2kNxuZr9wcG4REYkp8YzdzP5gZk9X/v5nALsB9CU9r4iItMZpjp3kQgDLADwV8LU1JIdJDhep4b2IVIwOAbctATb0lj+ODmU9IgnhLLCTfAOA7wL4pJm9Uv91M9tsZoNmNjh37lxXlxWRNIwOAQ9fCxx6AYCVPz58rYJ7TjkJ7CRLKAf1e8zsfhfnFPFSO2a9acykf/Q5YGJ86mMT4+XHJXcSL56SJIC7Aew2s1uTD0nEkdGhcuA5NAbM7gcuuAlYelm243n42tcDZHXWC7Q+rnacM8ihsXiPS6ZczNjPB/AxAMtJjlT+vNfBeUVal8fUQTtmvWnNpGeH3Fg57HHJlIuqmMfNjGa21MwGKn++52JwIi3LY+ogdNb7QngKpVmaJa2Z9AU3AaWeqY+VesqPS+5o56n4KY+pg0az26B3FFHedaQ1k156GXDJHcDsBQBY/njJHdmmtiSUArv4KY+pg6BZb636dxRR3nWkOZNeehlw/bPAhoPljwrquaXALn7KY+pgyqw3RO07iijvOjSTlgAuWgqI5E81sOWpKqY6rqWXlfPlh16Y/vXadxSz+5sfU3tOkQoFdvFXngPeBTdNLVMEpr+jiHKMSAClYqR4fNjaHiWFojSLtIhmlvpFBwcHbXh4OPXrigfqN+QA5VmsAp50AJI7zGyw2XGasUux5LE+PU98eDcjiSnHLsWSx/r0vEirvYDknmbsUix5rE/Pi7jvZjS795YCuxRLHuvT8yLOu5k89tIRZxTYpVhUKRIuzrsZrVV4TTl2KZ4816dnKU7du9YqvKYZu4gv4rybaXWtQnn5QtCMXcrydlMKaU3UdzOt7GpV1U1haMYuWkjrRK2sVSgvXxiasUvjX1jNxPwVd61CefnC0Ixd9Asr0WgPQWE4mbGT/BqAiwG8ZGZLXJxTUhS1PWwBbNm5Fxseeg4HxycAACfNKuHmS87E6mV9GY/MA+o2WRiuZuxfB7DS0bkkbZ5s+tmycy/WfnvXsaAOAH96dQJrv7MLW3buzXBk023ZuRfnb3wMi9ZtxfkbH8vd+AJpD0FhOJmxm9lPSS50cS7JQE5vSrFl515s2rYH+w6OY35vD9auWNxw5r1p2x5MHJ3erXRi0rBp257czNq37NyL9fc/g/GJSQDA3oPjWH//MwCQmzGG0h6CQkht8ZTkGgBrAOC0005L67ISVc5+YVsJfvsOjgc+3uxradu0bc+xf1fV+MRkrl58pNhSC+xmthnAZqDcjz2t60q+RJ2FRwl+9efqnVXCn16dmHYuAJjf2+Am0ikLe5HZd3A89rsUkSAqd5S2qwarvQfHQQDVV/VGs/BGwa96zrXf2YWJSTt2rhkEZhCoz8aUuoi1KxY7+/ckNb+3B3sD/n2ze0rFTdFIrqjcUdqqmlKpBjIDsGrG43j8uGvx6+M/jO28GiNbN0/7vrAZdvXxzz783LGgXnXUgO6ZM9DbUzr22EmzStj0gbNzFRjXrliMnlLXlMd6Sl0gEfouJXfUWiDXXJU73gvgHQBOITkG4GYzu9vFuaVNUmohUJ9SWTXjcWws3YVZPAwA6OfLuGHiP4DRM6dcf+2KxVNmr0A5+FVn3mEpl1cnjuLfLl3a1kCeNF1SPbb+HNffNxJ4fJ7WBwCotUABuKqKucLFeSQlKf5i1gelG2YOHQvqVbN4eNou17DgFyWAtpK+iBqsXVW0rF7WN+34arqqXp7WBwBop3IBKBXTiVLs+VEflObz5eADA3a5rl7WhyfWLcdvNl6EJ9YtnxIIa9Mt9eKmL2rTRYbXg3VQbXmjRd2kwlI0eVofAKCdygWgwN6JUvzFrA9W++yU4ANj7nLdsOpMlGYw9Otx0hdhwXrDQ89N20TUbFG3VtxNSKuX9eGLl56Fvt4eEEBfbw++eOlZuVofAKDWAgWgqphOlGILgfqUyl3HfRT/al/FzMnXXj+ohV2u1fN+emgXJm169Wyc9EVYsD44PnFsF2t1Fh9WUll/vVZTNkEpmtxRa4HcU2DvRCn/Yk4NVheVF0odLNxWz9lokTWKsPLDeuMTkzh+5gz0lLqmXI8A3nnG3CnHer0JKac7leV1CuydKOtfTIe7XJMsslYFVeCEOTQ+gY+cexruefL3x+rxDcB3d+zF4JvmHLtu2LuAvZVNSF4EdwXy3KIFvI1tt8HBQRseHk79ulKhuyVNU18V8+rhI4Epl75KyiVoht/X24Mn1i0HAJy/8bHQdwEE8JFzT8Mtq89y9w+QjkByh5kNNjtOi6edRndLClRfgXPzJWeGVqhEWUANqnCpMgD3PPn7YnR0lEJSYO80nt7ezHUb3EYVKs12xVZ1l8J/vQzI547SMNppWijKsXcaD2uQ29UGN6xCpdmu2PrxhMndjtIw2mlaOJqxdxoPa5DbuWkoSLN686DxBMndjtKwWbmn7/J8phl7p/GwBjnOpiFXGtWbR7kugXztKG00K/fwXZ7vFNg7Tdaljm0QVoee1Yy4WV18tSqmlTRR2/q1N5qVe3RP3E6hVEwnWnoZcP2zwIaD5Y8FDupA/nqsBI2n2vygr7cHt10+0FKpY5yeNrE1mpV7ck/cTqLALoWXtx4rQeO57fIB3H75AADg+vtGplTuRK3oaetaQqO1F93EunCUihEvuOixkjTN0ej7wyp3hn/3R3x3x95IFT1tW0sYHQIO/9/0x2tn5dppWigK7J1AO01DtXLbvrDzNCq5DJtt3/vUC9OamIX1lIm1lhD1Oa9fNK3qmQO850v6f1JQSsX4rgN3mkZNbQTdtq9WnDRHszRJ2Kw6qDNl2PGR1xLiPOdBi6YAcNwJCuoFpsDuuw6rQU5604x6UdMczdIkYRU6XQzuKR90fOS1hDjPuUoZveQksJNcSXIPyV+RXOfinOJIh/3ixllgjBK0o5ZMNmszEDbbvuJtC2JV9DS6q9QxcZ7zdm1YUwuCTCUO7CS7ANwJ4D0A3gLgCpJvSXpeccTDnaaNxFlgbBa0GwXY+nTPO8+YO+2OTqUZPPb9YbPtW1af5b6iJ85z3o5Sxg5M/+WNi8XTcwD8ysx+DQAkvwXgfQB+4eDckpSHO00bibPAGNTzpbqA2hfzhtb3/ewFHK0/sC7LUl+5U31xqFbR3Hb5gJsSzTjPeTs2rOlm15lzEdj7ANRuSxsD8Lb6g0iuAbAGAE477TQHl5VIPNxp2kizBl21Wr1JR1C6Z+Lo9EXQiUkLvWOSk8ZlYZUvcZ9z16WMHZb+yyMXgT1o9Wfa/3Iz2wxgM1C+0YaD60pUBalBDqsDj1pfXj1ufGISXSQmzabNvIPOVb05RlRx6sbDjk1867xmHRezfM7VgiBzLgL7GIAFNZ/3A9jn4LzioUbBO8kGnvrvnzQ7NlNvtEno+vtG8Mn7RhqmXupFvUdq9dggjW6dF0me0x0dlv7LIxdVMT8HcDrJRSSPA/AhAA85OK94plEpYqMNPFGqXKJUwwQdU78hKUrflaAKl9IMotQ19c1ro8XXsIBPIFrvlzjpjrQrVNSCIHOJA7uZHQFwDYBtAHYDGDKz55KeV/zTKPgm3cATpRqmWQol6oakoAqXTR88G5s+cHbk6pa1KxaH5jAjbYqKWvmSVYWKZ43misZJSwEz+x6A77k4l/irUfANS29Uc+X16me8UaphoqRQoubPw3rTRF34XL2sD5+8b6T1MURNd0RN2ajthFe081RS02gTT9INPFG22ze6wXSzMbZDX8R7pwaKmu6IkrJR3bl31ARMUtOoFLFR6eHgm+Y0rYqJUrpYe0x906/ascSRpCNko59HpPNGqXyJUqGS54VYaQktJIfZToODgzY8PJz6dSV7zQJW2+4Q1MJYonx/UGCOs3M0aAwAEp/3mKDujaUe4OwPA798tDJzD4sBLOfIJTdI7jCzwabHKbBLqJTzri4CZZrO3/hYYM6+r7cndm18W89b/zye/m5g1zeDuzrWmr2gvPApuRE1sCsVI8GabYBpg8SbdlLWrhtfOD9vfcrmtiXNg7rqzgtNgV2CZZB3TRLQ0kzhVK83I2LFTtxxtv3m3A239lNVMR5QYJdgGfT7aDWgOem7EkP1ekFBvVlHyCjjjNPvpiWhC6pKvfhC5Y4SLIN2v5HvEFSnrTd5jng9oFxz32g9IOo4235z7na06pVc0YxdgmXQ76PVbouuc9LN0iVh5z1q1nCsjfrDLFq3dcq1XNycO1SHdfzsRArsEiyjX/5WAprLnHSUdEmr12u087XaO2ftt3dNuVbbFKTjp7RGqRgJl6TfR4qNp1pN4QSJki5p9XpRdr5OHDVseEitliQZzdh9kIc+H7Vj6DkJOPwXYPJw+WttLpVsNYUTJEpap9Xr1X9f2A6Sg+MTANKv9BF/aINS0YXtLEyzTWrQGIIUoOoibHPQSbNK2HnTu51ea+G6raFfu/3ygUJt1pJ0RN2gpFRM0TWqN89yDEGqpZI5voP92hWLp/VVB4C/vHYkWp/0GE6aVQp9PO1KH/GLAnvR5eH+klGvNbs/950EVy/rwwnHTc9QThw150H15kvOnPYiUuoibr7kzLbtapXOoMBedFHqzds9Q45S214tlczDO4wmDlVy3PVcB9XVy/qm3Zxj0wfOxuplfQ1bHIs0o8BedM02m6QxQw4aw4wS0DMH03qF5+EdRhNpBtXVy/rwxLrl+M3Gi/DEuuXH8ucuK32k86gqpuia1Zun0fMlTs17Ae5g72pLf5KqFpeVPtJ5ElXFkPwggA0A3gzgHDOLVOqiqpgUbehFcL/tjHpt56GKJ4KwoBw1WBetBbEUQ1pte58FcCmA/0x4HmmXLGbIjerqC7KdPWgHbJxmY0VrQSx+SRTYzWw3AJBB91uXXEi750uUPu4F3c4eFKzfNfnfOPfBa4AHX57yIqWqFslSaounJNeQHCY5vH///rQuK1FveuxKAapeWlUflFfNeBwbS3fhVOxH/cK0qlokS01n7CR/CODUgC/daGYPRr2QmW0GsBko59gjj1CSS3OGXICql1bVN/G6YeYQZvHw1IMqL2JrV2xrb091kQaaBnYzuzCNgYgnClD10pLRIWznTeg+/kXss5Px70cuw3y+HHzsoTFVtUimVO4obmXQx73tKusGsybGAQL9fBkbS3fhFZ6IXvx5+vGVF7G29lQXaSBRjp3k+0mOATgPwFaS29wMSwor7Zx+GgLWDWbxMHp7SroTkeRS0qqYBwA84Ggs4ouCVr2EClsfGP8TcOnm9Es3XbdpzkPbZ3FKqRiRZhqtG6T9IhalnDTL80kuqFeMSDN5uvmz63JSj8tTO5kCu0gzeVo3cF1O6nF5aidTKkYkijRSLo98CtjxdcAmAXYBb70SuPjWqce4Lif1tTy1w2nGLpIHj3wKGL67HNSB8sfhu8uP14qaForagz9PaSZxRoFdJA92fD3a41HSQnF68FfP1zPn9cdmqu1B0SkVI5IHNhn98WZpoVZ68B+pOX78j6qMKTjN2EXygF3xHm8k7oKoKmO8o8AukgdvvTLe441EuQ9u1ehQ8OIpoMqYAlMqRuLLcqeir7skq9UvzapiomjUr6f259dzEvDXgF43VaqMKSwFdoknq52Ko0PA9z9Tzv9W+bZL8uJbWwvkVfVBe2ZPue1B9QUQmPrc1f4s66kyptCUipF4ssjHVl9MggKRcsFl9ZUw438sL4heuhm4/tnyC1/Qcxem6I3bOpwCu8STxU7FZgFJueBoL7hRf06zFyioF5wCu8QTZ2HOlWYBSbngaC+4UX9Op787+XgkUwrsEk8WOxUbBSTlgsuivOAGPXdBfvmomzFJZhTYJZ4sGmKFBaSeOcHXjrqd3idRXnDrn7swSm0VnqpiJL60e5BXrxWlzLFT+4tH/RnVPne3LVEDME/RzFK/6ODgoA0PD6d+XckxV/XpocFqQbk6RF5X/yIIlGf5qojJLZI7zGyw2XFJ73m6ieTzJEdJPkCyN8n5pEPFaVrVTJ77i+ctRZSnPvPiVNJUzHYA683sCMkvAVgP4DPJhyUdpZWmVWHy2l88ryki3+5PKwASztjN7FEzO1L59EkASs5JfC5n2XntL65GW5Iil1UxVwH4ftgXSa4hOUxyeP/+/Q4vK4XnsjY+r+mFPKeIxDtNUzEkfwjg1IAv3WhmD1aOuRHAEQD3hJ3HzDYD2AyUF09bGq34qVHTqlbkMb2Q1xSReKlpYDezCxt9neTHAVwM4ALLosRGii9OOWNRuX7xEmkg0eIpyZUoL5b+vZm96mZI0pHyOMt2qRNevCQ3klbFfAXA8QC2kwSAJ83sE4lHJeIj31+8JDcSBXYz+1tXAxERETfUK0ZExDMK7CIinlFgFxHxjAK7iIhnFNhFRDyjwC4i4hkFdhERzyiwi4h4RoFdRMQzCuwiIp5RYBcR8YwCu4iIZxTYRUQ8o8AuIuIZBXYREc8osIuIeEaBXUTEMwrsIiKeSRTYSX6e5CjJEZKPkpzvamAiItKapDP2TWa21MwGADwC4CYHYxIRkQQSBXYze6Xm0xMAWLLhiIhIUjOTnoDkFwD8I4BDAN6ZeEQiIpJI0xk7yR+SfDbgz/sAwMxuNLMFAO4BcE2D86whOUxyeP/+/e7+BSIiMgXN3GRPSL4JwFYzW9Ls2MHBQRseHnZyXRGRTkFyh5kNNjsuaVXM6TWfrgLwfJLziYhIcklz7BtJLgZwFMDvAHwi+ZBERCSJRIHdzP7B1UBERMQN7TwVEfGMAruIiGcU2EVEPKPALiLiGQV2ERHPKLCLiHhGgV1ExDMK7CIinlFgFxHxjAK7iIhnFNhFRDyjwC4i4hkFdhERzyiwi4h4RoFdRMQzCuwiIp5RYBcR8YwCu4iIZxTYRUQ84ySwk/xnkkbyFBfnExGR1iUO7CQXAHgXgN8nH46IiCTlYsZ+G4AbAJiDc4mISEIzk3wzyVUA9prZLpLNjl0DYE3l07+SfDbJtVNyCoCXsx5EBBqnO0UYI6BxulaUcS6OchDNGk+0Sf4QwKkBX7oRwL8AeLeZHSL5WwCDZtb0h0Ny2MwGowwwSxqnW0UYZxHGCGicrvk2zqYzdjO7MOQCZwFYBKA6W+8H8DTJc8zsxZjjFRERR1pOxZjZMwDmVT+PM2MXEZH2yaqOfXNG141L43SrCOMswhgBjdM1r8bZNMcuIiLFop2nIiKeUWAXEfFM5oE97+0ISH6e5CjJEZKPkpyf9ZjqkdxE8vnKOB8g2Zv1mIKQ/CDJ50geJZm70jKSK0nuIfkrkuuyHk8Qkl8j+VLe94GQXEDyxyR3V57z67IeUxCS3SR/RnJXZZyfzXpMYUh2kdxJ8pFmx2Ya2AvSjmCTmS01swEAjwC4KesBBdgOYImZLQXwvwDWZzyeMM8CuBTAT7MeSD2SXQDuBPAeAG8BcAXJt2Q7qkBfB7Ay60FEcATAp83szQDOBXB1Tn+efwWw3MzOBjAAYCXJczMeU5jrAOyOcmDWM/bctyMws1dqPj0BORyrmT1qZkcqnz6J8p6C3DGz3Wa2J+txhDgHwK/M7NdmdhjAtwC8L+MxTWNmPwXwx6zH0YyZ/cHMnq78/c8oB6S+bEc1nZX9pfJpqfInd7/jJPsBXATgrijHZxbYa9sRZDWGqEh+geQLAD6CfM7Ya10F4PtZD6KA+gC8UPP5GHIYiIqI5EIAywA8le1IglVSHCMAXgKw3czyOM7bUZ4EH41ycKJeMc1EaUfQzutH1WicZvagmd0I4EaS6wFcA+DmVAeI5mOsHHMjym+B70lzbLWijDOngpod5W7mVjQk3wDguwA+WffuNzfMbBLAQGVt6gGSS8wsN2sYJC8G8JKZ7SD5jijf09bAXpR2BGHjDPBNAFuRQWBvNkaSHwdwMYALLMPNCTF+lnkzBmBBzef9APZlNBYvkCyhHNTvMbP7sx5PM2Z2kORPUF7DyE1gB3A+gFUk3wugG8DfkPyGmX007BsyScWY2TNmNs/MFprZQpR/qf4ujz1mSJ5e8+kqAM9nNZYwJFcC+AyAVWb2atbjKaifAzid5CKSxwH4EICHMh5TYbE8Y7sbwG4zuzXr8YQhObdaRUayB8CFyNnvuJmtN7P+Sqz8EIDHGgV1IPvF0yLYSPJZkqMop47yWLb1FQAnAtheKcv8atYDCkLy/STHAJwHYCvJbVmPqaqy+HwNgG0oL/QNmdlz2Y5qOpL3AvgfAItJjpH8p6zHFOJ8AB8DsLzyf3KkMuPMmzcC+HHl9/vnKOfYm5YT5p1aCoiIeEYzdhERzyiwi4h4RoFdRMQzCuwiIp5RYBcR8YwCu4iIZxTYRUQ88//z7/tqUSjjgAAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "from numpy import linalg as LA\n",
    "\n",
    "X=2*np.random.rand(2,50)-1\n",
    "L_X=np.zeros(50)-1\n",
    "Y=[]\n",
    "count=0\n",
    "while len(Y)!=50 and count<200:\n",
    "    temp=4*np.random.rand(2,)-2\n",
    "    if LA.norm(temp)>1:\n",
    "        Y.append(temp)\n",
    "\n",
    "Y=np.array(Y).T\n",
    "L_Y=np.ones(50)\n",
    "\n",
    "plt.axis([-4,4,-4,4])\n",
    "plt.scatter(X[0],X[1],label='-1')\n",
    "plt.scatter(Y[0],Y[1],label='1')\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "Z=np.concatenate((X,Y),axis=1)\n",
    "L=np.concatenate((L_X,L_Y))\n",
    "\n",
    "Z=np.reshape(Z,(2,-1)).T\n",
    "\n",
    "C=10\n",
    "\n",
    "delta = 0.01\n",
    "x_1 = np.arange(min(Z[:, 0])- 2,max(Z[:, 0] + 1), delta)\n",
    "x_2 = np.arange(min(Z[:, 1]) - 2,max(Z[:, 1] + 1), delta)\n",
    "X_1, X_2 = np.meshgrid(x_1, x_2)\n",
    "\n",
    "beta,b = SMO_KKT(Z,L,10000,C)\n",
    "\n",
    "fig, ax = plt.subplots()\n",
    "ax.contourf(X_1, X_2, f_func_plot(beta, L, Z, X_1, X_2, b), 1, colors=['moccasin', 'skyblue'])\n",
    "ax.scatter(Z[:50, 0], Z[:50, 1], label='-1')\n",
    "ax.scatter(Z[50:, 0], Z[50:, 1], label='1')\n",
    "ax.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "W=[]\n",
    "for z in Z:\n",
    "    W.append([z[0],z[1],z[0]**2+z[1]**2])\n",
    "\n",
    "W=np.array(W)\n",
    "\n",
    "C=10\n",
    "\n",
    "beta,b = SMO_KKT(W,L,10000,C)\n",
    "\n",
    "def f_func_plot2(beta, y, X, x_1, x_2, b):\n",
    "    summe = 0\n",
    "    for i in range(len(y)):\n",
    "        summe += y[i]*beta[i]*(X[i, 0]*x_1 + X[i, 1]*x_2+X[i,2]*(x_1**2+x_2**2))\n",
    "    summe += b\n",
    "    return summe\n",
    "\n",
    "fig, ax = plt.subplots()\n",
    "ax.contourf(X_1, X_2, f_func_plot2(beta, L, W, X_1, X_2, b), 1, colors=['moccasin', 'skyblue'])\n",
    "ax.scatter(Z[:50, 0], Z[:50, 1], label='-1')\n",
    "ax.scatter(Z[50:, 0], Z[50:, 1], label='1')\n",
    "ax.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Task 2.7"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [],
   "source": [
    "def gaussian(t,x,sigma):\n",
    "    return np.exp(-LA.norm(t-x)**2/(2*sigma**2))\n",
    "\n",
    "def OneStep_gaussian(i, j, beta, y, X, b, C,sigma):\n",
    "    f = func_f(beta, y, X, b)\n",
    "    delta = y[i] * ((f[j] - y[j]) - (f[i] - y[i]))\n",
    "    s = y[i] * y[j]\n",
    "    chi = gaussian(X[i],X[i],sigma)+gaussian(X[j],X[j],sigma)-2*gaussian(X[i],X[j],sigma)\n",
    "    gamma = s * beta[i] + beta[j]\n",
    "    if s == 1:\n",
    "        L = max(0, gamma - C)\n",
    "        H = min(gamma, C)\n",
    "    else:\n",
    "        L = max(0, - gamma)\n",
    "        H = min(C,  C - gamma)\n",
    "    if chi > 0:\n",
    "        beta[i] = min(max(beta[i] + delta / chi, L), H)\n",
    "    elif delta > 0:\n",
    "        beta[i] = L\n",
    "    else:\n",
    "        beta[i] = H\n",
    "    beta[j] = gamma - s * beta[i]\n",
    "    f = func_f(beta, y, X, b)\n",
    "    b = b - 0.5 * (f[i] - y[i] + f[j] - y[j])\n",
    "\n",
    "def SMO_KKT_gaussian(X, y, max_iter, C,sigma):\n",
    "    n = X.shape[0]\n",
    "    beta = np.zeros(X.shape[0])\n",
    "    b = 0\n",
    "    iter = 0\n",
    "    while iter < max_iter:\n",
    "        f = func_f(beta, y, X, b)\n",
    "        for i in range(n):\n",
    "            KKT = (C - beta[i]) * max(0, 1 - y[i] * f[i]) + beta[i] * max(0, y[i] * f[i] - 1)\n",
    "            if KKT > 0:\n",
    "                j = np.random.randint(0, n)\n",
    "                if sum(np.logical_and(beta > 0, beta < C)) > 0:    \n",
    "                    while i == j and (beta[j] < 0 or beta[j] > C):\n",
    "                        j = np.random.randint(0, n)\n",
    "                else:\n",
    "                    while i == j:\n",
    "                        j = np.random.randint(0,n)\n",
    "                break\n",
    "        if KKT == 0:\n",
    "            med = np.median(((beta > 0) * (f - y))[np.nonzero((beta > 0) * (f - y))])\n",
    "            b = b - med\n",
    "            break\n",
    "            return beta, b\n",
    " \n",
    "        OneStep_gaussian(i, j, beta, y, X, b, C,sigma)\n",
    "        iter += 1\n",
    "    if iter == max_iter:\n",
    "        f = func_f(beta, y, X, b)\n",
    "        med = np.median(((beta > 0) * (f - y))[np.nonzero((beta > 0) * (f - y))])\n",
    "        b = b - med\n",
    "        return beta, b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "C=10\n",
    "sigma=1\n",
    "\n",
    "beta,b = SMO_KKT_gaussian(W,L,10000,C,sigma)\n",
    "\n",
    "def f_func_plot3(beta, y, X, x_1, x_2, b):\n",
    "    summe = 0\n",
    "    for i in range(len(y)):\n",
    "        summe += y[i]*beta[i]*(gaussian(X[i,0],X[i,1]))\n",
    "    summe += b\n",
    "    return summe\n",
    "\n",
    "fig, ax = plt.subplots()\n",
    "ax.contourf(X_1, X_2, f_func_plot2(beta, L, W, X_1, X_2, b), 1, colors=['moccasin', 'skyblue'])\n",
    "ax.scatter(Z[:50, 0], Z[:50, 1], label='-1')\n",
    "ax.scatter(Z[50:, 0], Z[50:, 1], label='1')\n",
    "ax.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Task 2.8"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Load MNIST Data\n",
    "import numpy as np\n",
    "import os\n",
    "import gzip\n",
    "from urllib.request import urlretrieve\n",
    "\n",
    "def download(filename , source='http://yann.lecun.com/exdb/mnist/'):\n",
    "    print(\"Downloading %s\" % filename)\n",
    "    urlretrieve(source + filename , filename)\n",
    "\n",
    "def load_mnist_images(filename):\n",
    "    if not os.path.exists(filename):\n",
    "        download(filename)\n",
    "    with gzip.open(filename , 'rb') as f:\n",
    "        data = np.frombuffer(f.read(), np.uint8 , offset=16)\n",
    "    data = data.reshape(-1, 28, 28)\n",
    "    return data / np.float32(256)\n",
    "\n",
    "def load_mnist_labels(filename):\n",
    "    if not os.path.exists(filename):\n",
    "        download(filename)\n",
    "    with gzip.open(filename , 'rb') as f:\n",
    "        data = np.frombuffer(f.read(), np.uint8 , offset=8)\n",
    "    return data\n",
    "\n",
    "X_train = load_mnist_images('train-images-idx3-ubyte.gz')\n",
    "y_train = load_mnist_labels('train-labels-idx1-ubyte.gz')\n",
    "X_test = load_mnist_images('t10k-images-idx3-ubyte.gz')\n",
    "y_test = load_mnist_labels('t10k-labels-idx1-ubyte.gz')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "for gamma=0.1:\n",
      "Model with rank: 1\n",
      "Mean validation score: 0.654 (std: 0.019)\n",
      "Parameters: {'C': 10}\n",
      "\n",
      "Model with rank: 1\n",
      "Mean validation score: 0.654 (std: 0.019)\n",
      "Parameters: {'C': 100}\n",
      "\n",
      "Model with rank: 3\n",
      "Mean validation score: 0.620 (std: 0.022)\n",
      "Parameters: {'C': 1}\n",
      "\n",
      "for gamma=0.01:\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\yanni\\Anaconda3\\lib\\site-packages\\sklearn\\model_selection\\_search.py:841: DeprecationWarning: The default of the `iid` parameter will change from True to False in version 0.22 and will be removed in 0.24. This will change numeric results when test-set sizes are unequal.\n",
      "  DeprecationWarning)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model with rank: 1\n",
      "Mean validation score: 0.900 (std: 0.036)\n",
      "Parameters: {'C': 10}\n",
      "\n",
      "Model with rank: 1\n",
      "Mean validation score: 0.900 (std: 0.036)\n",
      "Parameters: {'C': 100}\n",
      "\n",
      "Model with rank: 3\n",
      "Mean validation score: 0.882 (std: 0.029)\n",
      "Parameters: {'C': 1}\n",
      "\n",
      "for gamma=0.001:\n",
      "Model with rank: 1\n",
      "Mean validation score: 0.882 (std: 0.027)\n",
      "Parameters: {'C': 100}\n",
      "\n",
      "Model with rank: 2\n",
      "Mean validation score: 0.876 (std: 0.033)\n",
      "Parameters: {'C': 10}\n",
      "\n",
      "Model with rank: 3\n",
      "Mean validation score: 0.740 (std: 0.022)\n",
      "Parameters: {'C': 1}\n",
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\yanni\\Anaconda3\\lib\\site-packages\\sklearn\\model_selection\\_search.py:841: DeprecationWarning: The default of the `iid` parameter will change from True to False in version 0.22 and will be removed in 0.24. This will change numeric results when test-set sizes are unequal.\n",
      "  DeprecationWarning)\n"
     ]
    }
   ],
   "source": [
    "from sklearn import svm, datasets\n",
    "from sklearn.model_selection import GridSearchCV\n",
    "\n",
    "ss=500\n",
    "\n",
    "rand=np.arange(ss)\n",
    "\n",
    "np.random.shuffle(rand)\n",
    "\n",
    "A=X_train[rand]\n",
    "B=y_train[rand]\n",
    "\n",
    "A=np.reshape(A,(ss,-1))\n",
    "\n",
    "g=0.1\n",
    "\n",
    "print('for gamma=0.1:')\n",
    "\n",
    "parameters = {'C':[1, 10,100]}\n",
    "svc = svm.SVC(gamma=g)\n",
    "clf = GridSearchCV(svc, parameters, cv=5)\n",
    "clf.fit(A,B)\n",
    "clf.get_params(clf)\n",
    "\n",
    "def report(results, n_top=3):\n",
    "    for i in range(1, n_top + 1):\n",
    "        candidates = np.flatnonzero(results['rank_test_score'] == i)\n",
    "        for candidate in candidates:\n",
    "            print(\"Model with rank: {0}\".format(i))\n",
    "            print(\"Mean validation score: {0:.3f} (std: {1:.3f})\".format(\n",
    "                  results['mean_test_score'][candidate],\n",
    "                  results['std_test_score'][candidate]))\n",
    "            print(\"Parameters: {0}\".format(results['params'][candidate]))\n",
    "            print(\"\")\n",
    "\n",
    "\n",
    "report(clf.cv_results_)\n",
    "\n",
    "\n",
    "g=0.01\n",
    "\n",
    "print('for gamma=0.01:')\n",
    "\n",
    "parameters = {'C':[1, 10,100]}\n",
    "svc = svm.SVC(gamma=g)\n",
    "clf = GridSearchCV(svc, parameters, cv=5)\n",
    "clf.fit(A,B)\n",
    "clf.get_params(clf)\n",
    "\n",
    "def report(results, n_top=3):\n",
    "    for i in range(1, n_top + 1):\n",
    "        candidates = np.flatnonzero(results['rank_test_score'] == i)\n",
    "        for candidate in candidates:\n",
    "            print(\"Model with rank: {0}\".format(i))\n",
    "            print(\"Mean validation score: {0:.3f} (std: {1:.3f})\".format(\n",
    "                  results['mean_test_score'][candidate],\n",
    "                  results['std_test_score'][candidate]))\n",
    "            print(\"Parameters: {0}\".format(results['params'][candidate]))\n",
    "            print(\"\")\n",
    "\n",
    "\n",
    "report(clf.cv_results_)\n",
    "\n",
    "\n",
    "g=0.001\n",
    "\n",
    "print('for gamma=0.001:')\n",
    "\n",
    "parameters = {'C':[1, 10,100]}\n",
    "svc = svm.SVC(gamma=g)\n",
    "clf = GridSearchCV(svc, parameters, cv=5,scoring='accuracy')\n",
    "clf.fit(A,B)\n",
    "clf.get_params(clf)\n",
    "\n",
    "def report(results, n_top=3):\n",
    "    for i in range(1, n_top + 1):\n",
    "        candidates = np.flatnonzero(results['rank_test_score'] == i)\n",
    "        for candidate in candidates:\n",
    "            print(\"Model with rank: {0}\".format(i))\n",
    "            print(\"Mean validation score: {0:.3f} (std: {1:.3f})\".format(\n",
    "                  results['mean_test_score'][candidate],\n",
    "                  results['std_test_score'][candidate]))\n",
    "            print(\"Parameters: {0}\".format(results['params'][candidate]))\n",
    "            print(\"\")\n",
    "\n",
    "\n",
    "report(clf.cv_results_)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 883    3   11    2    6   32   20   11    2   10]\n",
      " [   0 1129    2    1    0    0    1    0    1    1]\n",
      " [  14  197  713   19   29    3    5   15   15   22]\n",
      " [   9   58   35  828    1   13    1    7    4   54]\n",
      " [   1   26    2    0  593    0   12    0    0  348]\n",
      " [  33   83   17  279   26  226   11    8    8  201]\n",
      " [  17   54   67    1  102   44  669    0    0    4]\n",
      " [   2   88   15    0    8    0    0  567    2  346]\n",
      " [  23  123   22  153    8    7    9    8  392  229]\n",
      " [  11   18    7   11   50    1    0   13    0  898]]\n",
      "0.6898\n"
     ]
    }
   ],
   "source": [
    "from sklearn.metrics import confusion_matrix\n",
    "from sklearn.metrics import accuracy_score\n",
    "\n",
    "X_test=np.reshape(X_test,(len(X_test),-1))\n",
    "\n",
    "svc = svm.SVC(gamma=g)\n",
    "svc.fit(A,B)\n",
    "prediction = svc.predict(X_test)\n",
    "\n",
    "print(confusion_matrix(y_test, prediction))\n",
    "print(accuracy_score(y_test, prediction))"
   ]
  }
 ],
 "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.7.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
