Praktikum-Machine-Learning/ML0101EN-Clas-SVM-cancer.ipynb
2025-11-18 14:38:28 +07:00

1553 lines
102 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<p style=\"text-align:center\">\n",
" <a href=\"https://skills.network\" target=\"_blank\">\n",
" <img src=\"https://cf-courses-data.s3.us.cloud-object-storage.appdomain.cloud/assets/logos/SN_web_lightmode.png\" width=\"200\" alt=\"Skills Network Logo\">\n",
" </a>\n",
"</p>\n",
"\n",
"\n",
"# SVM (Support Vector Machines)\n",
"\n",
"\n",
"Estimated time needed: **15** minutes\n",
" \n",
"\n",
"## Objectives\n",
"\n",
"After completing this lab you will be able to:\n",
"\n",
"* Use scikit-learn to Support Vector Machine to classify\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In this notebook, you will use SVM (Support Vector Machines) to build and train a model using human cell records, and classify cells to whether the samples are benign or malignant.\n",
"\n",
"SVM works by mapping data to a high-dimensional feature space so that data points can be categorized, even when the data are not otherwise linearly separable. A separator between the categories is found, then the data is transformed in such a way that the separator could be drawn as a hyperplane. Following this, characteristics of new data can be used to predict the group to which a new record should belong.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h1>Table of contents</h1>\n",
"\n",
"<div class=\"alert alert-block alert-info\" style=\"margin-top: 20px\">\n",
" <ol>\n",
" <li><a href=\"#load_dataset\">Load the Cancer data</a></li>\n",
" <li><a href=\"#modeling\">Modeling</a></li>\n",
" <li><a href=\"#evaluation\">Evaluation</a></li>\n",
" <li><a href=\"#practice\">Practice</a></li>\n",
" </ol>\n",
"</div>\n",
"<br>\n",
"<hr>\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Requirement already satisfied: scikit-learn in c:\\users\\robib\\appdata\\local\\programs\\python\\python312\\lib\\site-packages (1.7.2)\n",
"Requirement already satisfied: numpy>=1.22.0 in c:\\users\\robib\\appdata\\local\\programs\\python\\python312\\lib\\site-packages (from scikit-learn) (2.3.4)\n",
"Requirement already satisfied: scipy>=1.8.0 in c:\\users\\robib\\appdata\\local\\programs\\python\\python312\\lib\\site-packages (from scikit-learn) (1.16.3)\n",
"Requirement already satisfied: joblib>=1.2.0 in c:\\users\\robib\\appdata\\local\\programs\\python\\python312\\lib\\site-packages (from scikit-learn) (1.5.2)\n",
"Requirement already satisfied: threadpoolctl>=3.1.0 in c:\\users\\robib\\appdata\\local\\programs\\python\\python312\\lib\\site-packages (from scikit-learn) (3.6.0)\n",
"Requirement already satisfied: matplotlib in c:\\users\\robib\\appdata\\local\\programs\\python\\python312\\lib\\site-packages (3.10.7)\n",
"Requirement already satisfied: contourpy>=1.0.1 in c:\\users\\robib\\appdata\\local\\programs\\python\\python312\\lib\\site-packages (from matplotlib) (1.3.3)\n",
"Requirement already satisfied: cycler>=0.10 in c:\\users\\robib\\appdata\\local\\programs\\python\\python312\\lib\\site-packages (from matplotlib) (0.12.1)\n",
"Requirement already satisfied: fonttools>=4.22.0 in c:\\users\\robib\\appdata\\local\\programs\\python\\python312\\lib\\site-packages (from matplotlib) (4.60.1)\n",
"Requirement already satisfied: kiwisolver>=1.3.1 in c:\\users\\robib\\appdata\\local\\programs\\python\\python312\\lib\\site-packages (from matplotlib) (1.4.9)\n",
"Requirement already satisfied: numpy>=1.23 in c:\\users\\robib\\appdata\\local\\programs\\python\\python312\\lib\\site-packages (from matplotlib) (2.3.4)\n",
"Requirement already satisfied: packaging>=20.0 in c:\\users\\robib\\appdata\\local\\programs\\python\\python312\\lib\\site-packages (from matplotlib) (25.0)\n",
"Requirement already satisfied: pillow>=8 in c:\\users\\robib\\appdata\\local\\programs\\python\\python312\\lib\\site-packages (from matplotlib) (12.0.0)\n",
"Requirement already satisfied: pyparsing>=3 in c:\\users\\robib\\appdata\\local\\programs\\python\\python312\\lib\\site-packages (from matplotlib) (3.2.5)\n",
"Requirement already satisfied: python-dateutil>=2.7 in c:\\users\\robib\\appdata\\local\\programs\\python\\python312\\lib\\site-packages (from matplotlib) (2.9.0.post0)\n",
"Requirement already satisfied: six>=1.5 in c:\\users\\robib\\appdata\\local\\programs\\python\\python312\\lib\\site-packages (from python-dateutil>=2.7->matplotlib) (1.17.0)\n",
"Requirement already satisfied: pandas in c:\\users\\robib\\appdata\\local\\programs\\python\\python312\\lib\\site-packages (2.3.3)\n",
"Requirement already satisfied: numpy>=1.26.0 in c:\\users\\robib\\appdata\\local\\programs\\python\\python312\\lib\\site-packages (from pandas) (2.3.4)\n",
"Requirement already satisfied: python-dateutil>=2.8.2 in c:\\users\\robib\\appdata\\local\\programs\\python\\python312\\lib\\site-packages (from pandas) (2.9.0.post0)\n",
"Requirement already satisfied: pytz>=2020.1 in c:\\users\\robib\\appdata\\local\\programs\\python\\python312\\lib\\site-packages (from pandas) (2025.2)\n",
"Requirement already satisfied: tzdata>=2022.7 in c:\\users\\robib\\appdata\\local\\programs\\python\\python312\\lib\\site-packages (from pandas) (2025.2)\n",
"Requirement already satisfied: six>=1.5 in c:\\users\\robib\\appdata\\local\\programs\\python\\python312\\lib\\site-packages (from python-dateutil>=2.8.2->pandas) (1.17.0)\n",
"Requirement already satisfied: numpy in c:\\users\\robib\\appdata\\local\\programs\\python\\python312\\lib\\site-packages (2.3.4)\n"
]
}
],
"source": [
"!pip install scikit-learn\n",
"!pip install matplotlib\n",
"!pip install pandas \n",
"!pip install numpy \n",
"%matplotlib inline"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"import pylab as pl\n",
"import numpy as np\n",
"import scipy.optimize as opt\n",
"from sklearn import preprocessing\n",
"from sklearn.model_selection import train_test_split\n",
"%matplotlib inline \n",
"import matplotlib.pyplot as plt"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h2 id=\"load_dataset\">Load the Cancer data</h2>\n",
"The example is based on a dataset that is publicly available from the UCI Machine Learning Repository (Asuncion and Newman, 2007)[http://mlearn.ics.uci.edu/MLRepository.html]. The dataset consists of several hundred human cell sample records, each of which contains the values of a set of cell characteristics. The fields in each record are:\n",
"\n",
"|Field name|Description|\n",
"|--- |--- |\n",
"|ID|Clump thickness|\n",
"|Clump|Clump thickness|\n",
"|UnifSize|Uniformity of cell size|\n",
"|UnifShape|Uniformity of cell shape|\n",
"|MargAdh|Marginal adhesion|\n",
"|SingEpiSize|Single epithelial cell size|\n",
"|BareNuc|Bare nuclei|\n",
"|BlandChrom|Bland chromatin|\n",
"|NormNucl|Normal nucleoli|\n",
"|Mit|Mitoses|\n",
"|Class|Benign or malignant|\n",
"\n",
"<br>\n",
"<br>\n",
"\n",
"For the purposes of this example, we're using a dataset that has a relatively small number of predictors in each record. To download the data, we will use `!wget` to download it from IBM Object Storage. \n"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
" % Total % Received % Xferd Average Speed Time Time Time Current\n",
" Dload Upload Total Spent Left Speed\n",
"\n",
" 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0\n",
" 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0\n",
" 0 0 0 0 0 0 0 0 --:--:-- 0:00:01 --:--:-- 0\n",
"100 19975 100 19975 0 0 10972 0 0:00:01 0:00:01 --:--:-- 11035\n"
]
}
],
"source": [
"!curl -L -o cell_samples.csv \"https://cf-courses-data.s3.us.cloud-object-storage.appdomain.cloud/IBMDeveloperSkillsNetwork-ML0101EN-SkillsNetwork/labs/Module%203/data/cell_samples.csv\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Load Data From CSV File \n"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>ID</th>\n",
" <th>Clump</th>\n",
" <th>UnifSize</th>\n",
" <th>UnifShape</th>\n",
" <th>MargAdh</th>\n",
" <th>SingEpiSize</th>\n",
" <th>BareNuc</th>\n",
" <th>BlandChrom</th>\n",
" <th>NormNucl</th>\n",
" <th>Mit</th>\n",
" <th>Class</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>1000025</td>\n",
" <td>5</td>\n",
" <td>1</td>\n",
" <td>1</td>\n",
" <td>1</td>\n",
" <td>2</td>\n",
" <td>1</td>\n",
" <td>3</td>\n",
" <td>1</td>\n",
" <td>1</td>\n",
" <td>2</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>1002945</td>\n",
" <td>5</td>\n",
" <td>4</td>\n",
" <td>4</td>\n",
" <td>5</td>\n",
" <td>7</td>\n",
" <td>10</td>\n",
" <td>3</td>\n",
" <td>2</td>\n",
" <td>1</td>\n",
" <td>2</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>1015425</td>\n",
" <td>3</td>\n",
" <td>1</td>\n",
" <td>1</td>\n",
" <td>1</td>\n",
" <td>2</td>\n",
" <td>2</td>\n",
" <td>3</td>\n",
" <td>1</td>\n",
" <td>1</td>\n",
" <td>2</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>1016277</td>\n",
" <td>6</td>\n",
" <td>8</td>\n",
" <td>8</td>\n",
" <td>1</td>\n",
" <td>3</td>\n",
" <td>4</td>\n",
" <td>3</td>\n",
" <td>7</td>\n",
" <td>1</td>\n",
" <td>2</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>1017023</td>\n",
" <td>4</td>\n",
" <td>1</td>\n",
" <td>1</td>\n",
" <td>3</td>\n",
" <td>2</td>\n",
" <td>1</td>\n",
" <td>3</td>\n",
" <td>1</td>\n",
" <td>1</td>\n",
" <td>2</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" ID Clump UnifSize UnifShape MargAdh SingEpiSize BareNuc \\\n",
"0 1000025 5 1 1 1 2 1 \n",
"1 1002945 5 4 4 5 7 10 \n",
"2 1015425 3 1 1 1 2 2 \n",
"3 1016277 6 8 8 1 3 4 \n",
"4 1017023 4 1 1 3 2 1 \n",
"\n",
" BlandChrom NormNucl Mit Class \n",
"0 3 1 1 2 \n",
"1 3 2 1 2 \n",
"2 3 1 1 2 \n",
"3 3 7 1 2 \n",
"4 3 1 1 2 "
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"cell_df = pd.read_csv(\"cell_samples.csv\")\n",
"cell_df.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The ID field contains the patient identifiers. The characteristics of the cell samples from each patient are contained in fields Clump to Mit. The values are graded from 1 to 10, with 1 being the closest to benign.\n",
"\n",
"The Class field contains the diagnosis, as confirmed by separate medical procedures, as to whether the samples are benign (value = 2) or malignant (value = 4).\n",
"\n",
"Let's look at the distribution of the classes based on Clump thickness and Uniformity of cell size:\n"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAjIAAAGwCAYAAACzXI8XAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjcsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvTLEjVAAAAAlwSFlzAAAPYQAAD2EBqD+naQAAMxBJREFUeJzt3Ql4FFW6//E3JEBwCQQQBNliEhZFRAVjUFEngajgdV8COKD+1esGiMuIM3qvoKKOoDIyXFEHUCEM7l4cyA2bC8YQBFwGJQuLGRZREhKQZSTp//Me0zEdQpOETned6u/nefqBOpV0TnV1p345562qCI/H4xEAAAALNQl1BwAAABqKIAMAAKxFkAEAANYiyAAAAGsRZAAAgLUIMgAAwFoEGQAAYK0ocbmKigrZunWrHH/88RIRERHq7gAAgDrQy9zt3r1bOnbsKE2aNAnfIKMhpnPnzqHuBgAAaICioiLp1KlT+AYZHYnxvhAxMTGh7g4AAKiDsrIyMxDhPY6HbZDxTidpiCHIAABglyOVhVDsCwAArEWQAQAA1iLIAAAAa7m+RqauysvL5Zdffgl1NxAgTZs2lcjISF5PAHC5sA8yep769u3bZdeuXaHeFwiwVq1ayYknnsj1gwDAxcI+yHhDTLt27eSYY47hoOeScLp3717ZsWOHWe7QoUOouwQAaCRR4T6d5A0xbdq0CXV3EEAtWrQw/2qY0f3LNBMAuFNYF/t6a2J0JAbu492v1D4BgHuFdZDx4h5M7sR+BQD3I8gAAABrhTTIfPzxx3LZZZeZO1vqX8/vvffeIUWbjz76qCnW1JqH1NRUyc/PD1l/AdRdXl6xLFy4QfLzS6x+2TIzN8qECZ9JVtamUHcFLtofbvl8PPFEtvzud3+Xp576PDyLfX/++Wc5/fTT5eabb5arrrrqkPXPPPOMTJ06VWbPni1xcXHyyCOPSFpamqxbt06io6ND0mc3GzVqlCl+9gbKCy+8UPr27SvPP/98qLsGixQX75Nhwz6UzMzfDjRpad0kI2OoxMba87ktLCyRpKQ5snPn/qq2Nm2iJTd3hMTFtQpp38KRW/aHWz4fS5dultTUN8Xj+XV52bIiefjhT2X58utk4MAu4TMic8kll8jjjz8uV1555SHrdDRGD6B/+tOf5PLLL5c+ffrIa6+9Jlu3bj1k5AaN45133pGJEyc68uXt1q0bAcuh9Jf04sWbfdp0OT19gdik5kFT6XL//m+ErE/hzC37wy2fj9RqIcZLly+8cH7Q++LYGpmNGzeaa7zodJJXy5YtJSkpSbKzsw/7fQcOHDC3/q7+CAa3DBNW17p16yPePh2o+TnQvzTLy31/w+myttvy+dDpi5oHTS9tt31awzZu2R9u+Xw88UT2ISHGS9uDPc3k2CCjIUa1b9/ep12XvetqM2nSJBN4vI/OnTs3+jDhxRe/JT16/E0uvfQd6d79VbNcUlL7hy5QdNrnnnvukbFjx0psbKx5XV5++WUzXXfTTTeZAJKQkCALFy6sumbOLbfcYqbotN6oR48e8sILLxzxZ+jze23btk2GDBlivl+fZ+7cuYeMjGit0yuvvGJG2fT058TERPnggw+q1telHzrFdcUVV8izzz5r6qP0Gj933XVX1WnU2q/NmzfLvffea34eZyc5R2Gh/ytkFxTY8Ys6J2eb3/XZ2VuD1he4Z3+45fOxZMn3ftf/3//5jjiFbZBpqPHjx0tpaWnVo6ioyLXDhFo71LZtW1m5cqUJNXfccYdce+21MmDAAFm9erUMHjxYbrzxRnOV24qKCunUqZO8+eabpsZIi6gffvhhmT+/7sOAv//9783U3vLly+Xtt9+WGTNmVF09t7rHHntMrrvuOvnqq6/k0ksvleHDh0txcbFZV9d+LFu2TAoLC82/up2zZs0yD++Ulz7HhAkTTLjSB5whPt5/rUJCQqzYICnJ/9Wgk5M7Bq0vcM/+cMvnIyXFfw3M4MFdJZgcG2T0Hjnqhx9+8GnXZe+62jRv3lxiYmJ8Hm4dJtRCaa0h0lEPDXBaAK3B5tZbbzVtGhJ27txpAoXeRFEDRr9+/cxoiIYLHbmpa5D57rvvZPHixWbUR6f3zjzzTDPysm/fvkO+VkdU0tPTzYjQk08+KXv27DFhS9W1HzrK9OKLL0rPnj1l6NChZiRoyZIlVVNeeqVeHXXS94K/9wOCq3v31qZwMTIywqddl7U9MdGOX9RpaXGmkLQ22j5oULeg9ymcuWV/uOXz8cc/JkuE7yZU0faHHjonqP1xbJDRg5weoLwHL6X1Ljk5OZKcnCxOEOphQi2A9tIDu07BnHbaaVVt3mk576jJtGnT5KyzzpITTjhBjjvuODOi8v33/ocIvdavXy9RUVEmwHhpUNHA4a9fxx57rAmT1Udu6tKPU0891ee2AjrFVNvoD5xHz75ITfX9i0yXtd0mejZMzYOn9ywZsD/C/fOxfPl1h4QZXdb2sDr9Wv9SLygo8CnwXbt2rfmLu0uXLqY+Q89q0tEF7+nXes0ZrZ9wglAPE+roRnVaK1K9zVs7otM58+bNk/vvv18mT55sgqCOZvz5z382wTAY/dI+qLr2w99zwNn0FNJFi64xI5Ia5vVzYMtfmtXpKb0//XS3KSTVGgydvrDlL383csv+cMvnY+DALlJRcb8p7NWaGJ1OCvZIjCOCzKpVq+Siiy6qWh43bpz5d+TIkaYe4sEHHzTFq7fddpu5vsl5550nixYtcsw1ZLzDhFoTU316SYcJNWE76c25YsUKUztz5513VrVpDUpdaVHuwYMHZc2aNWY0RWkILSkpCWo/vJo1a2YKh+Fc+v530megofRgaeMB063csj/c8vl46KFzQhZgHDG1pGef6PViaj68RZ36V7gWdOpZSvv37zc1Gt27dxcnsWWYUEe1NDhmZmZKXl6eGd3Kzc2t8/drrYqeCq+hUutdNNDo//XMo/qcNXS0/fDSs6X0ytBbtmyRn376qd7fDwBwB8fWyNg2TJiXd4v84x9XmX912WlXaLz99tvN1ZOvv/56U6yrRcDVR0XqQi9IqHU3AwcONKdXa1GxTg3VZ4QsEP1QGnA3bdok8fHxptYGABCeIjw6BOJiWiCs15PRU7FrnsGkozxal6P1N06ZrrLJv/71L3OdHh0pS0lJEadh/wKAO4/fjqmRgV2WLl1qCrT1zCi9dovWMOkUj47QAAAQCgQZ1JleWVcvXrdhwwYzpaRFu3PmzDnkDCMAAIKFIIM60zuP6wMAAKeg2BcAAFiLIAMAAKxFkAEAANYiyAAAAGsRZAAAgLUIMpbS2zvoTTUb06hRoxxzg04AAGrD6dc4rBdeeMHc+woAAKciyOCw9NLQAAA4GVNLAZMnIgtFJF+C5eDBg3L33XebwNG2bVtzJ2nvCMqBAwfk/vvvl5NOOkmOPfZYc4PG5cuXV32v3mG8VatW5i7UvXr1kuOOO04uvvhic+uBw00t7d69W4YPH26er0OHDvLcc88dMsWltyx48skn5eabbzZX/+3SpYvMmDEjaK8JACC8EGSOWrGIXCwiPUTkUhHpXrlcIo1t9uzZEhUVJStXrjTTQFOmTJFXXnnFrNOAk52dLfPmzZOvvvpKrr32WhNU8vN/C1p79+6VZ599Vl5//XX5+OOP5fvvvzfh53DGjRsnK1askA8++ECysrLkk08+kdWrVx/ydZMnT5Z+/frJmjVrzJ2t77jjDlm/fn0jvQoAgLDmcbnS0lIdojD/1rRv3z7PunXrzL8Nl+bxeCJ1IKTaI7KyvfFccMEFnl69enkqKiqq2v7whz+Yts2bN3siIyM9W7Zs8fmelJQUz/jx483/Z86caV6XgoKCqvXTpk3ztG/fvmp55MiRnssvv9z8v6yszNO0aVPPm2++WbV+165dnmOOOcYzZsyYqrauXbt6RowYUbWs/WvXrp1n+vTpnmALzP4FADjt+F0dNTJHPZ2UWUt7eWW7jn4kSmM555xzJCIiomo5OTnZjIZ8/fXXUl5eLt276+jQb3S6qU2bNlXLxxxzjMTHx1ct63TRjh07av1ZeqNIvWnk2WefXdWmU1o9euhIlK8+ffpU/V/7d+KJJx72eQEAOBoEmaNSeIT1BY0aZA5nz549EhkZKV988YX5tzqthfGqeddqDR2BOEuptuetqKg46ucFAKAmgsxR+W00o3YJ0phycnJ8lj///HNJTEyUM844w4zI6CjI+eefH5CfdfLJJ5uAkpubawp4VWlpqeTl5cnAgQMD8jMAAKgvin2Pik7dpImI76jHr8tpjT4ao8W5WoCrhbQZGRnyl7/8RcaMGWOmlPTsot///vfyzjvvyMaNG01B8KRJk+TDDz9s0M/SM5BGjhwpDzzwgCxbtkz++c9/yi233CJNmjTxmd4CACCYGJE5ahkikl6jVia1sr1xaVDZt2+fqVvRKSQNMbfddptZN3PmTHn88cflvvvuky1btpjTs7WmZujQoQ3+eXpW1H/+53+a54iJiZEHH3xQioqKJDo6OoBbBQBA3UVoxa+4WFlZmSlK1WkQPfhWt3//fjNaERcXF4CDcX5lTUxCSOpiQuHnn38216nRAmMdnXGawO5fAIBTjt/VMSITMImuDzB6XZjvvvvOjADpG2vChAmm/fLLLw911wAAYYogg3rRC+hpTU6zZs3krLPOMhfF02krAABCgSCDOtOzofSUbgAAnIKzlgAAgLUIMr/epiHU+wGNgP0KAO4X1kHGewVavXki3Me7X2teaRgA4B5hXSOj115p1apV1X2A9N5DXNzNHSMxGmJ0v+r+rXmbBgCAe4R1kFF6Q0PFTQ3dR0OMd/8CANwp7IOMjsDoXZ/btWtn7u4Md9DpJEZiAMD9wj7IeOlBjwMfAAB2CetiXwAAYDeCDAAAsBZBBgAAWIsgAwAArEWQAQAA1iLIAAAAaxFkAACAtQgyAADAWgQZAABgLYIMAACwFkEGAABYiyADAACsRZABAADWIsgAAABrEWQAAIC1CDIAAMBaBBkAAGAtggwAALAWQQYAAFiLIAMAAKxFkAEAANYiyAAAAGsRZAAAgLUIMgAAwFoEGQAAYC2CDAAAsBZBBgAAWIsgAwAArEWQAQAA1iLIAAAAaxFkAACAtQgyAADAWo4OMuXl5fLII49IXFyctGjRQuLj42XixIni8XhC3TUAYSNPRBaKSL7YLC+vWBYu3CD5+SWh7goQUFHiYE8//bRMnz5dZs+eLaeeeqqsWrVKbrrpJmnZsqWMHj061N0D4GrFIjJMRDKrtaWJSIaIxIotiov3ybBhH0pm5qaqtrS0bpKRMVRiY6ND2jfA9SMyn332mVx++eUyZMgQ6datm1xzzTUyePBgWblyZai7BsD1NMQsrtGmy+liEw0xixdv9mnT5fT0BSHrExA2QWbAgAGyZMkSycvToV2RL7/8Uj799FO55JJLDvs9Bw4ckLKyMp8HANRPXuVITHmN9vLK9nxrppN0JKa83Hc6Xpe1nWkmuIGjp5YeeughE0R69uwpkZGRpmbmiSeekOHDhx/2eyZNmiSPPfZYUPsJwG0Kj7C+QEQSxekKC3f5XV9QUCKJifZMkwHWjcjMnz9f5syZI3PnzpXVq1ebWplnn33W/Hs448ePl9LS0qpHUVFRUPsMwA3ij7A+QWwQH9/K7/qEBEIM7OfoEZkHHnjAjMrccMMNZvm0006TzZs3m1GXkSNH1vo9zZs3Nw8AaLjulYW9i2tML0WKSKoVozGqe/fWprBXa2KqTy9FRkZIampXRmPgCo4ekdm7d680aeLbRZ1iqqioCFmfAISLjMrQUl1qZbs99OwkDS3V6bK2A27g6BGZyy67zNTEdOnSxZx+vWbNGpkyZYrcfPPNoe4aANfTaZdFlYW9BZXTSXaMxFSnp1gvWnSNKezVmhidTqIuBm4S4XHw1eV2795tLoj37rvvyo4dO6Rjx46Snp4ujz76qDRr1qxOz6HFwnrdGa2XiYmJafQ+AwCAo1fX47ejg0wgEGQAAHDv8dvRNTIAAAD+EGQAAIC1CDIAAMBaBBkAAGAtggwAALAWQQYAAFiLIAMAAKxFkAEAANYiyAAAAGsRZAAAgLUIMgAAwFoEGQAAYC2CDAAAsBZBBgAAWIsgAwAArEWQAQAA1iLIAAAAaxFkAACAtQgyAADAWgQZAABgLYIMAACwFkEGAABYiyADAACsRZABAADWIsgAAABrEWQAAIC1okLdASBQ8vKKpbBwlyQkxEpiYiwvLOBCfM6dJTNzo+TkbJPk5I4yaFC3kPSBIAPrFRfvk2HDPpTMzE1VbWlp3SQjY6jExkaHtG8AAoPPubMUFpZIUtIc2blzf1VbmzbRkps7QuLiWgW1L0wtwXoaYhYv3uzTpsvp6QtC1icAgcXn3FmSaoQYpcv9+78R9L4QZGD9MLOOxJSXe3zadVnb8/NLQtY3AIHB59x500k7a4QYL23PyvptdDwYCDKwmtbE+FNQQJABbMfn3Flycrb5XZ+dvVWCiSADq8XH+5+L1cJfAHbjc+4sSUkd/K7Xwt9gIsjAat27tzaFvZGRET7tuqztnL0E2I/PubOkpcWZwt7aaHuwz14iyMB6enZSampXnzZd1nYA7sDn3Flyc0ccEma8Zy0FW4TH4/GtknSZsrIyadmypZSWlkpMTEyou4NGpIW9WhPDdWQA9+Jz7ixZWZtMTUxjXEemrsdvggwAAHCcugYZppYAAIC1CDIAAMBaBBkAAGAtggwAALAWQQYAAFiLIAMAAKxFkAEAANYiyAAAAGsRZAAAgLUIMgAAwFoEGQAAYC2CDAAAsBZBBgAAWIsgAwAArEWQAQAA1iLIAAAAaxFkAACAtQgyAADAWgQZAABgLYIMAACwFkEGAABYiyADAACsRZABAADWIsgAAABrEWQAAIC1CDIAACD8gsyuXbvklVdekfHjx0txcbFpW716tWzZsiWQ/QMAADisKGmAr776SlJTU6Vly5ayadMmufXWW6V169byzjvvyPfffy+vvfZaQ54WOCp5ecVSWLhLEhJiJTExllczxNyzP/JEpFBEEkQkMdSdgUu45fORmblRcnK2SXJyRxk0qJs9QWbcuHEyatQoeeaZZ+T444+var/00ktl2LBhgeyfGeH5wx/+IAsXLpS9e/dKQkKCzJw5U/r16xfQnwN7FRfvk2HDPpTMzE1VbWlp3SQjY6jExkaHtG/hyD37Q0ea9fdZZrW2NBHJEBF7DzwILbd8PgoLSyQpaY7s3Lm/qq1Nm2jJzR0hcXGtnD+1lJubK7fffvsh7SeddJJs375dAqWkpETOPfdcadq0qQky69atk8mTJ0tsLL9E8Bv9pbB48Wafl0SX09MX8DKFgHv2h4aYxTXadDk9RP2BG7jl85FUI8QoXe7f/w07RmSaN28uZWVlh7Tn5eXJCSecIIHy9NNPS+fOnc0IjFdcXJzf7zlw4IB5eNXWT7hreLb6XzZe5eUe056fX2L1sK1t3LM/8mqMxHiVV7bnM82EsP18ZGZuPCTEeGl7VtamoE4zNWhE5j/+4z9kwoQJ8ssvv5jliIgIUxujU0BXX311wDr3wQcfmCmka6+9Vtq1aydnnHGGvPzyy36/Z9KkSaZ2x/vQIAT30jlmfwoKSoLWF7hpf2hNjD8FQeoH3MQtn4+cnG1+12dnb5VgalCQ0emdPXv2mHCxb98+ueCCC0ztitbLPPHEEwHr3IYNG2T69OmSmJgomZmZcscdd8jo0aNl9uzZh/0ePYuqtLS06lFUVBSw/sB54uP9z8VqIR2Cxz37I/4I67XwFwjPz0dSUge/67XwN5giPB6Pp6Hf/Omnn5ozmDTUnHnmmeZMpkBq1qyZGZH57LPPqto0yGiNTnZ2dp2eQ6eWdGRGQ01MTExA+wdnuPjit8wcsw7PekVGRkhqaldZtOiakPYtHLlnf1xcWROj00lekSKiv+cWhbBfsJlbPh9t275Y6/SSFvz+9NPdAfkZdT1+N2hERqeRtA7lvPPOkzvvvFMefPBBE2I0E+m6QOnQoYOccsopPm29evUK6M+A/bTaX38JVKfL2g72x1G8sypDi887q7IdCO/fV7m5I0xoqc571lKwNWhEpkmTJiZQaA1LfPxvQ7A//PCDdOzYUcrLq/8F03B6KrdODX3yySdVbffee6/k5OT4jNL4w4hM+NBCOZ1jtv26DG7hnv2RX1kTw3VkEMB3lUs+H1lZm0xNTGNcR6aux+8GB5mrrrpKli1bJvPnz5eUlJSqIKOjKBUVFRIIOoU0YMAAeeyxx+S6666TlStXmovvzZgxQ4YPH16n5yDIAABgn0adWtKzlP7617/Kn/70JxkyZIhMnTrVZ12g9O/fX959913JyMiQ3r17y8SJE+X555+vc4gBAADu1qDryHgHcXSap2fPnpKeni5ff/21PProo4HunwwdOtQ8AAAAAhJkqrvkkktMvYpeW0anfgAAAIKlQVNLet0YPTXaS88s0gLcVq1aVY3WAAAAOPo6Mjag2BcAAPcev6Pq84TeJzrS/Yu48BwAAAiGOgcZveP0tm3bzG0JdAqptrOTdHBH2wN1HRkAAICABJmlS5dK69atzf/1+jEAAAChRo0MAAAIjwvi/fTTT7J582aftn/+859y0003mSvvzp07t+E9BgAAqKd6BZl77rnH5yq+O3bskPPPP9/cSkBvIjlq1Ch5/fXX69sHAACAxg8yn3/+ubnwnddrr71m6mbWrl0r77//vjz55JMybdq0hvUEAACgMYPM9u3bpVu3bj4FwHrzyKioX2uGNeTk5+udYgEAABwWZLTYZteuXVXLekuCpKSkqmU99VqnmAAAABwXZM455xxTI1NRUSFvvfWW7N69W373u99Vrc/Ly5POnTs3Rj8BAACO7qaREydOlJSUFHnjjTfk4MGD8vDDD5sL5XnNmzfP3IcJAADAcUGmT58+8u2338qKFSvkxBNP9JlWUjfccIO5gSQAAICjppb07CS9jkzbtm3NGUq1BZYhQ4ZIXFxcoPsIAABwdEHm3//+d9XNImfPni379++v67cCAACEdmopOTlZrrjiCjnrrLPMzSFHjx4tLVq0qPVr//a3vwWyjwAAAEcXZLTA97nnnpPCwkJzmrXe+4BRGQAAYN1NI7UOZtWqVdKmTRtxy02nAACAfcfvep215LVx48aj6RsAAEBA1DnI6IXwbrvtNomOjva5cWRttH4GAADAMVNL1aeT/J1irfUzGzZsEKdgagkAAPsEfGqp+nQSU0sAAMC6ey0BAAA4SYOKfcvLy2XWrFmyZMkS2bFjh7mJZHVLly4NVP8AAAACG2TGjBljgozekqB3796mLgb2yssrlsLCXZKQECuJib/dBNQ2btkOt2B/OAv7w1kyMzdKTs42SU7uKIMGdRNbZTpgOxoUZPQu1/Pnz5dLL7008D1C0BQX75Nhwz6UzMxNVW1pad0kI2OoxMZGW7Mn3LIdbsH+cBb2h7MUFpZIUtIc2bnzt9v8tGkTLbm5IyQurpXYotBB29GgGplmzZpJQkJC4HuDoNKD/+LFm33adDk9fYFVe8It2+EW7A9nYX84S82Dv9Ll/v3fEJskOWg7GhRk7rvvPnnhhRfMPZdg7zCzjmCUl/vuQ13W9vz8ErGBW7bDLdgfzsL+cN40TM2Dv5e2Z2X9NqrsZJkO244GTS19+umnsmzZMlm4cKGceuqp0rRpU5/177zzTqD6h0aitST+FBSUWFFn4pbtcAv2h7OwP5xFa0n8yc7eakW9TI7DtqNBQaZVq1Zy5ZVXBr43CJr4eP9zmFowawO3bIdbsD+chf3hLElJHfyu14JZGyQ5bDsaFGRmzpwZ+J4gqLp3b20KYrWWpPq0TGRkhKSmdrVmFMMt2+EW7A9nYX84S1panCmIrW1aRtttGI1x4nbUq0YmNjZWWrdufchDb1mQlpYmWVlZjddTBJye1aMH++p0Wdtt4pbtcAv2h7OwP5xFz+rRg3113rN9bJLroO2o872W1OzZs2tt37Vrl3zxxRfy97//Xd566y257LLLxCm419KRaUGs1pLYfv0Vt2yHW7A/nIX94SxaEKu1JLZfRyarEbejrsfvegWZI5kyZYoJMp999pk4BUEGAAD71PX4HdB7LQ0dOlS+++67QD4lAABAcILMgQMHzMXyAAAArAsyr776qvTt2zeQTwkAABCY06/HjRtXa7vOX61evVry8vLk448/rs9TAgAABCfIrFmzptZ2LcIZNGiQuaKvnooNAADguCCjtyUAAABwZY0MAABAMBFkAACAtQgyAADAWgQZAABgLYIMAACwFkEGAABYiyADAACsRZABAADWIsgAAABrEWQAAIC1CDIAAMBaBBkAAGAtggwAALAWQQYAAFiLIAMAAKxFkAEAANYiyAAAAGsRZAAAgLUIMgAAwFoEGQAAYC2CDAAAsJZVQeapp56SiIgIGTt2bKi7AuAINm5cKbm5f5NNm1bxWjlAXl6xLFy4QfLzS8RmbIezZGZulAkTPpOsrE0h60OUWCI3N1deeukl6dOnT6i7AsCPkpItUlg4RPr1+1Li4n5tW7XqdElIWCitWnXgtQuy4uJ9MmzYh5KZ+duBJi2tm2RkDJXY2Ghr9gfb4SyFhSWSlDRHdu7cX9XWpk205OaOkLi4VkHtixUjMnv27JHhw4fLyy+/LLGxsaHuDgA/NMT07fuVT5suFxRcwusWAhpiFi/e7NOmy+npC6zaH2yHsyTVCDFKl/v3fyPofbEiyNx1110yZMgQSU1NPeLXHjhwQMrKynweAII3naQjMVFRHp92XdZ2ppmCPw2jIzHl5b77Q5e13ZZpJrbDedNJO2uEGC9tD/Y0k+ODzLx582T16tUyadKkOn29fl3Lli2rHp07d270PgL41U8/feP3pfjxR9+RGjSuwsJdftcXFNgRZNgOZ8nJ2eZ3fXb2VgkmRweZoqIiGTNmjMyZM0eio+s2lzt+/HgpLS2teuhzAAiOtm17+11/wgnUuAVTfLz/WoWEBDum6tkOZ0lK8l/rlpzcUYLJ0UHmiy++kB07dsiZZ54pUVFR5vHRRx/J1KlTzf/Ly8sP+Z7mzZtLTEyMzwNAcMTFnW0Kew8ejPBp12Vt79atH7siiLp3b20KeyMjffeHLmt7YqIdQYbtcJa0tDhT2FsbbR80qFtQ++PoIJOSkiJff/21rF27turRr18/U/ir/4+MjAx1FwHUoGcnrV3rO/Kiy9qO4NOzk1JTu/q06bK224TtcJbc3BGHhBnvWUvBFuHxeHyrwBzuwgsvlL59+8rzzz9fp6/XYl+tldFpJkZngODRwl6tidHpJEZiQk8Le7UmRqeTbBmJqQ3b4SxZWZtMTYxOJwV6JKaux2+CDAAAcJy6BhlrLojntXz58lB3AQAAOISja2QAAAD8IcgAAABrEWQAAIC1CDIAAMBaBBkAAGAtggwAALAWQQYAAFiLIAMAAKxFkAEAANYiyAAAAGsRZAAAgLUIMgAAwFoEGQAAYC2CDAAAsBZBBgAAWIsgAwAArEWQAQAA1iLIAAAAaxFkAACAtQgyAADAWgQZAABgLYIMAACwFkEGAABYiyADAACsRZABAADWIsgAAABrRYW6A/bKE5FCEUkQkUSxWV5esRQW7pKEhFhJTIwVW7llO9xi+vS/y+bNayQu7iy5/fZrxVZueV9lZm6UnJxtkpzcUQYN6ia2csv+cItMB7yvCDL1Viwiw3T3VWtLE5EMEbHrQ1VcvE+GDftQMjM3VbWlpXWTjIyhEhsbLbZwy3a4xccffyl7914nd9yhYf9XixZ1l5iYt2TAgNPEFm55XxUWlkhS0hzZuXN/VVubNtGSmztC4uJaiS3csj/cotBB7yumlupNQ8ziGm26nC620V8Kixdv9mnT5fT0BWITt2yHW2iISU3N92nT5bKya8Qmbnlf1TzYKF3u3/8NsYlb9odbJDnofUWQqZe8ypGY8hrt5ZXtvr+8nT48q3/ZlJd7fNp1Wdvz80vEBm7ZDjdNJ118cZ5ERfnuD13W9pdeelNs4Jb3lQ771zzYeGl7VtZvoxtO5pb94RaZDntfEWTqRWti/CkQW+gcsz8FBXb8YnDLdriF1sT4s3HjF2IDt7yvtHbBn+zsrWIDt+wPt8hx2PuKIFMv8UdYr4W/doiP9z+HqYV0NnDLdrhF165n+F2vhb82cMv7Kimpg9/1WqBpA7fsD7dIctj7iiBTL90rC3sja7RHVrbbc/ZS9+6tTaFcZGSET7sua7stZwO4ZTvc4o47rjeFvQcP+u4PXdZ2W85ecsv7Ki0tzhRg1kbbbTl7yS37wy3SHPa+IsjUm56dlFqjLbWy3S5a7Z+a2tWnTZe13SZu2Q630LOTFi/2DfW6rO02ccv7Ss8iqXnQ8Z5dYhO37A+3yHXQ+yrC4/H4Vk+5TFlZmbRs2VJKS0slJiYmgM+cX1kTY/91ZLRQTueYbb8ug1u2wy20sFdrYmy/joxb3ldagKm1C7ZfR8Yt+8MtshrxfVXX4zdBBgAAOE5dgwxTSwAAwFoEGQAAYC2CDAAAsBZBBgAAWIsgAwAArEWQAQAA1iLIAAAAaxFkAACAtQgyAADAWgQZAABgLYIMAACwFkEGAABYiyADAACsRZABAADWIsgAAABrEWQAAIC1CDIAAMBaBBkAAGAtggwAALAWQQYAAFiLIAMAAKxFkAEAANYiyAAAAGsRZAAAgLUIMgAAwFoEGQAAYC2CDAAAsBZBBgAAWMvRQWbSpEnSv39/Of7446Vdu3ZyxRVXyPr160PdLRfKE5GFIpIvdmM7nOSTT5bI3LmTZcWKZWI3t7yv3CEzc6NMmPCZZGVtCnVX4BBR4mAfffSR3HXXXSbMHDx4UB5++GEZPHiwrFu3To499thQd88FikVkmP5qqNaWJiIZIhIr9mA7nGTjxg2yYcNQSUn5tqptyZJekpDwD+natZvYwy3vK3coLCyRpKQ5snPn/qq2Nm2iJTd3hMTFtQpp3xBaER6PxyOW+PHHH83IjAacgQMH1ul7ysrKpGXLllJaWioxMTGN3ke7XCwii0WkvFpbpIikisgisQfb4SRLlpwiF1zwnURF/far5eDBCPnoo56SkrJO7OGW95U7tG37ok+IqR5mfvrp7pD0CY2rrsdvR08t1aQbo1q3bn3Yrzlw4IDZ+OoPHG64PLPGL2mpXM60aBid7XDadJKOxFQPMUqXtd2eaSa3vK/cM51UW4hR2s40U3izJshUVFTI2LFj5dxzz5XevXv7ravRBOd9dO7cOaj9tEfhEdYXiB3YDicpKlrrd/3mzavFDm55X7lDTs42v+uzs7cGrS9wHmuCjNbKfPPNNzJv3jy/Xzd+/HgzcuN9FBUVBa2Pdok/wvoEsQPb4SSdO/f1u75r1zPFDm55X7lDUlIHv+uTkzsGrS9wHiuCzN133y0LFiyQZcuWSadOnfx+bfPmzc1cWvUHatO9snBR5/yri6xsT7TkZWM7nOT881NMYa/WxFSny9p+7rkXiR3c8r5yh7S0OFMLUxttHzTIpiJyhFWQ0TpkDTHvvvuuLF26VOLi4kLdJZfJqCxcrC61st0mbIeT6NlJWthbnS5ru13c8r5yBz07qWaY8Z61hPDm6LOW7rzzTpk7d668//770qNHj6p2rX1p0aJFnZ6Ds5bqIr9yzj/B8r802Q4n0cJerYnR6SR7RmLc/L5yBy3s1ZoYnU5iJMbd6nr8dnSQiYjwHZ72mjlzpowaNapOz0GQAQDAPnU9fjv6gngOzlgAAMABHF0jAwAA4A9BBgAAWIsgAwAArEWQAQAA1iLIAAAAaxFkAACAtQgyAADAWgQZAABgLYIMAACwFkEGAABYiyADAACsRZABAADWIsgAAABrEWQAAIC1CDIAAMBaBBkAAGAtggwAALAWQQYAAFiLIAMAAKxFkAEAANYiyAAAAGsRZAAAgLUIMgAAwFoEGQAAYC2CDAAAsBZBBgAAWIsg02CdK1++LmK/ASJyrIicJ3a7UkTai8g1Yje3bMerInKjiMwSu+WJyEIRyQ91RwDUgiBTbyNFJEJE/iUiHhEpqly+TewzobLv2SKyV0RWVC4/JXaZXtnv90Rkh4i8XbmsB1KbuGU7vhCRZiLy/0TkDRG5qXJ5rdilWEQuFpEeInKpiHSvXC4JdccAVBPh8Xj0aOxaZWVl0rJlSyktLZWYmJgAPKMeWA7HtpfSLdvCdjiLhpZfamlvKiL/FntoaFksIuXV2iJFJFVEFoWwX0B4KKvj8ZsRmXpPJ/nTxbLpJH/Os2gaxh9bpmfcsh2vHibESGX7LIumkzJrhBipXNZ2ppkApyDI1MuWI6zX6SZbfHmE9WvEDp8dYf0nYge3bMfyI6xfInYoPML6giD1A8CREGTq5aQjrO8k9jj9COvPEHeMLJ0vdnDLdlx4hPUpYof4I6xPCFI/ABwJNTL15pZ6DDdtC9vhLNTIADh61Mg0mlvr2e5kk+rZ7lSv1LPdqdyyHSsrC3ura1rZbpOMysLe6lIr2wE4BSMyDdalsiZGp5O+F7udV1kTo9NJn4q9rqmsJdFpmLfEXm7ZjlmVNTE6nTRK7JVfWROj00mJoe4MEDbK6njWEkEGAAA4DlNLAADA9ThrCQAAWIsgAwAArEWQAQAA1iLIAAAAaxFkAACAtQgyAADAWgQZAABgLYIMAACwFkEGAABYK0pczuPxVF3qGAAA2MF73PYex8M2yOzevdv827lz51B3BQAANOA4rjePDNubRlZUVMjWrVvl+OOPl4iIiFB3x7GpV4NeUVGR3zuMgv0Rjvh8OAv7I3z2h8fjMSGmY8eO0qRJk/AdkdGN79SpU6i7YQV9ExJknIP94SzsD2dhf4TH/mjpZyTGi2JfAABgLYIMAACwFkEG0rx5c/mv//ov8y9Cj/3hLOwPZ2F/OEtzBxw/XF/sCwAA3IsRGQAAYC2CDAAAsBZBBgAAWIsgAwAArEWQCVOTJk2S/v37myset2vXTq644gpZv359qLuFSk899ZS5EvXYsWN5TUJoy5YtMmLECGnTpo20aNFCTjvtNFm1ahX7JATKy8vlkUcekbi4OLMv4uPjZeLEiUe8Dw8C4+OPP5bLLrvMXGVXfze99957Put1Pzz66KPSoUMHs39SU1MlPz9fgoEgE6Y++ugjueuuu+Tzzz+XrKws+eWXX2Tw4MHy888/h7prYS83N1deeukl6dOnT9i/FqFUUlIi5557rjRt2lQWLlwo69atk8mTJ0tsbCz7JQSefvppmT59urz44ovy7bffmuVnnnlG/vKXv7A/gkCPDaeffrpMmzat1vW6L6ZOnSr/8z//Izk5OXLsscdKWlqa7N+/v9H7xunXMH788UczMqMBZ+DAgbwqIbJnzx4588wz5a9//as8/vjj0rdvX3n++efZHyHw0EMPyYoVK+STTz7h9XeAoUOHSvv27eXVV1+tarv66qvNX/9vvPFGSPsWbiIiIuTdd981I/ne0Rgdqbnvvvvk/vvvN22lpaVmf82aNUtuuOGGRu0PIzKoetOp1q1b84qEkI6SDRkyxAzLIrQ++OAD6devn1x77bUm5J9xxhny8ssvs1tCZMCAAbJkyRLJy8szy19++aV8+umncskll7BPQmzjxo2yfft2n99beo+kpKQkyc7ObvSf7/qbRqJudwjXWgwdRu/duzcvWYjMmzdPVq9ebaaWEHobNmwwUxnjxo2Thx9+2OyX0aNHS7NmzWTkyJGh7l5YjpDpnZZ79uwpkZGRpmbmiSeekOHDh4e6a2Fv+/bt5jXQEZjqdNm7rjERZGBGAb755hvz1w1Co6ioSMaMGWPqlaKjo9kNDgn4OiLz5JNPmmUdkdHPidYAEGSCb/78+TJnzhyZO3eunHrqqbJ27VrzB5hOabA/whtTS2Hu7rvvlgULFsiyZcukU6dOoe5O2Priiy9kx44dpj4mKirKPLReSYvn9P/61yeCS8++OOWUU3zaevXqJd9//z27IgQeeOABMyqj9RZ69tiNN94o9957rzkDE6F14oknmn9/+OEHn3Zd9q5rTASZMKXFWRpitGBr6dKl5pRGhE5KSop8/fXX5q9M70NHA3TYXP+vQ+kILp1qrXlJAq3P6Nq1K7siBPbu3StNmvgesvRzoSNnCC09fmhg0RomL50G1LOXkpOTG/3nM7UUxtNJOkT7/vvvm2vJeOcxtUBLzwJAcOk+qFmfpKcv6vVLqFsKDf1rXwtMdWrpuuuuk5UrV8qMGTPMA8Gn1zDRmpguXbqYqaU1a9bIlClT5Oabb2Z3BOmMyoKCAp8CX/0jS08Q0X2i03x6pmViYqIJNnrNH532857Z1Kj07tcIP7rra3vMnDkz1F1DpQsuuMAzZswYXo8Q+t///V9P7969Pc2bN/f07NnTM2PGDPZHiJSVlZnPQ5cuXTzR0dGek08+2fPHP/7Rc+DAAfZJECxbtqzWY8bIkSPN+oqKCs8jjzziad++vfm8pKSkeNavXx+Mrnm4jgwAALAWNTIAAMBaBBkAAGAtggwAALAWQQYAAFiLIAMAAKxFkAEAANYiyAAAAGsRZAAAgLUIMgAcJSIiQt57771QdwOAJQgyAIJK7+t1zz33yMknnyzNmzeXzp07m/voVL/hHADUFTeNBBA0mzZtMneVbtWqlfz5z3+W0047TX755RfJzMw0NzL97rvv2BsA6oURGQBBc+edd5qpI72T9NVXXy3du3c3dzIeN26cfP7554d8/fLly83X79q1q6pN77irbRqK1KxZs0wwWrBggfTo0UOOOeYYueaaa2Tv3r0ye/Zs6datm8TGxsro0aOlvLy86nm0feLEiZKenm7uNH7SSSfJtGnTgvRKAAgUggyAoCguLpZFixaZkRcNDjVpGGkoDS1Tp06VefPmmZ+hAejKK6+Uf/zjH+bx+uuvy0svvSRvvfWWz/fpqNDpp58ua9askYceekjGjBkjWVlZDe4HgOBjaglAUBQUFIjH45GePXsG/Ll1emr69OkSHx9vlnVERsPLDz/8IMcdd5yccsopctFFF8myZcvk+uuvr/o+nebSAKN0dGjFihXy3HPPyaBBgwLeRwCNgxEZAEGhIaax6HSSN8So9u3bm6kjDTHV23bs2OHzfcnJyYcsf/vtt43WTwCBR5ABEBSJiYmmtqU+Bb1NmjQ5JATp6EtNTZs29VnWn1NbW0VFRQN6DsDJCDIAgqJ169aSlpZmCmp//vnnQ9ZXL+j1OuGEE8y/27Zt8yn2DZSaBca63KtXr4A9P4DGR5ABEDQaYvTMobPPPlvefvttyc/PN1M5Wqhbc5pHJSQkmOvM/Pd//7f52g8//FAmT54csP5oTcwzzzwjeXl5pm9vvvmmKfgFYA+CDICg0YvgrV692hTe3nfffdK7d29TWKsXw9Ni3Zp0eigjI8NMR/Xp00eefvppefzxxwPWH+3DqlWr5IwzzjDPO2XKFDNqBMAeEZ7GrMADAIfSYuCxY8eaBwB7MSIDAACsRZABAADWYmoJAABYixEZAABgLYIMAACwFkEGAABYiyADAACsRZABAADWIsgAAABrEWQAAIC1CDIAAEBs9f8BllQG/dMq798AAAAASUVORK5CYII=",
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"ax = cell_df[cell_df['Class'] == 4][0:50].plot(kind='scatter', x='Clump', y='UnifSize', color='DarkBlue', label='malignant');\n",
"cell_df[cell_df['Class'] == 2][0:50].plot(kind='scatter', x='Clump', y='UnifSize', color='Yellow', label='benign', ax=ax);\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Data pre-processing and selection\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's first look at columns data types:\n"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"ID int64\n",
"Clump int64\n",
"UnifSize int64\n",
"UnifShape int64\n",
"MargAdh int64\n",
"SingEpiSize int64\n",
"BareNuc object\n",
"BlandChrom int64\n",
"NormNucl int64\n",
"Mit int64\n",
"Class int64\n",
"dtype: object"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"cell_df.dtypes"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"It looks like the __BareNuc__ column includes some values that are not numerical. We can drop those rows:\n"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"ID int64\n",
"Clump int64\n",
"UnifSize int64\n",
"UnifShape int64\n",
"MargAdh int64\n",
"SingEpiSize int64\n",
"BareNuc int64\n",
"BlandChrom int64\n",
"NormNucl int64\n",
"Mit int64\n",
"Class int64\n",
"dtype: object"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"cell_df = cell_df[pd.to_numeric(cell_df['BareNuc'], errors='coerce').notnull()]\n",
"cell_df['BareNuc'] = cell_df['BareNuc'].astype('int')\n",
"cell_df.dtypes"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 5, 1, 1, 1, 2, 1, 3, 1, 1],\n",
" [ 5, 4, 4, 5, 7, 10, 3, 2, 1],\n",
" [ 3, 1, 1, 1, 2, 2, 3, 1, 1],\n",
" [ 6, 8, 8, 1, 3, 4, 3, 7, 1],\n",
" [ 4, 1, 1, 3, 2, 1, 3, 1, 1]])"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"feature_df = cell_df[['Clump', 'UnifSize', 'UnifShape', 'MargAdh', 'SingEpiSize', 'BareNuc', 'BlandChrom', 'NormNucl', 'Mit']]\n",
"X = np.asarray(feature_df)\n",
"X[0:5]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We want the model to predict the value of Class (that is, benign (=2) or malignant (=4)).\n"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([2, 2, 2, 2, 2])"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"y = np.asarray(cell_df['Class'])\n",
"y [0:5]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Train/Test dataset\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We split our dataset into train and test set:\n"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Train set: (546, 9) (546,)\n",
"Test set: (137, 9) (137,)\n"
]
}
],
"source": [
"X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=4)\n",
"print ('Train set:', X_train.shape, y_train.shape)\n",
"print ('Test set:', X_test.shape, y_test.shape)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h2 id=\"modeling\">Modeling (SVM with Scikit-learn)</h2>\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The SVM algorithm offers a choice of kernel functions for performing its processing. Basically, mapping data into a higher dimensional space is called kernelling. The mathematical function used for the transformation is known as the kernel function, and can be of different types, such as:\n",
"\n",
" 1.Linear\n",
" 2.Polynomial\n",
" 3.Radial basis function (RBF)\n",
" 4.Sigmoid\n",
"Each of these functions has its characteristics, its pros and cons, and its equation, but as there's no easy way of knowing which function performs best with any given dataset. We usually choose different functions in turn and compare the results. Let's just use the default, RBF (Radial Basis Function) for this lab.\n"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<style>#sk-container-id-1 {\n",
" /* Definition of color scheme common for light and dark mode */\n",
" --sklearn-color-text: #000;\n",
" --sklearn-color-text-muted: #666;\n",
" --sklearn-color-line: gray;\n",
" /* Definition of color scheme for unfitted estimators */\n",
" --sklearn-color-unfitted-level-0: #fff5e6;\n",
" --sklearn-color-unfitted-level-1: #f6e4d2;\n",
" --sklearn-color-unfitted-level-2: #ffe0b3;\n",
" --sklearn-color-unfitted-level-3: chocolate;\n",
" /* Definition of color scheme for fitted estimators */\n",
" --sklearn-color-fitted-level-0: #f0f8ff;\n",
" --sklearn-color-fitted-level-1: #d4ebff;\n",
" --sklearn-color-fitted-level-2: #b3dbfd;\n",
" --sklearn-color-fitted-level-3: cornflowerblue;\n",
"\n",
" /* Specific color for light theme */\n",
" --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));\n",
" --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, white)));\n",
" --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));\n",
" --sklearn-color-icon: #696969;\n",
"\n",
" @media (prefers-color-scheme: dark) {\n",
" /* Redefinition of color scheme for dark theme */\n",
" --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));\n",
" --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, #111)));\n",
" --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));\n",
" --sklearn-color-icon: #878787;\n",
" }\n",
"}\n",
"\n",
"#sk-container-id-1 {\n",
" color: var(--sklearn-color-text);\n",
"}\n",
"\n",
"#sk-container-id-1 pre {\n",
" padding: 0;\n",
"}\n",
"\n",
"#sk-container-id-1 input.sk-hidden--visually {\n",
" border: 0;\n",
" clip: rect(1px 1px 1px 1px);\n",
" clip: rect(1px, 1px, 1px, 1px);\n",
" height: 1px;\n",
" margin: -1px;\n",
" overflow: hidden;\n",
" padding: 0;\n",
" position: absolute;\n",
" width: 1px;\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-dashed-wrapped {\n",
" border: 1px dashed var(--sklearn-color-line);\n",
" margin: 0 0.4em 0.5em 0.4em;\n",
" box-sizing: border-box;\n",
" padding-bottom: 0.4em;\n",
" background-color: var(--sklearn-color-background);\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-container {\n",
" /* jupyter's `normalize.less` sets `[hidden] { display: none; }`\n",
" but bootstrap.min.css set `[hidden] { display: none !important; }`\n",
" so we also need the `!important` here to be able to override the\n",
" default hidden behavior on the sphinx rendered scikit-learn.org.\n",
" See: https://github.com/scikit-learn/scikit-learn/issues/21755 */\n",
" display: inline-block !important;\n",
" position: relative;\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-text-repr-fallback {\n",
" display: none;\n",
"}\n",
"\n",
"div.sk-parallel-item,\n",
"div.sk-serial,\n",
"div.sk-item {\n",
" /* draw centered vertical line to link estimators */\n",
" background-image: linear-gradient(var(--sklearn-color-text-on-default-background), var(--sklearn-color-text-on-default-background));\n",
" background-size: 2px 100%;\n",
" background-repeat: no-repeat;\n",
" background-position: center center;\n",
"}\n",
"\n",
"/* Parallel-specific style estimator block */\n",
"\n",
"#sk-container-id-1 div.sk-parallel-item::after {\n",
" content: \"\";\n",
" width: 100%;\n",
" border-bottom: 2px solid var(--sklearn-color-text-on-default-background);\n",
" flex-grow: 1;\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-parallel {\n",
" display: flex;\n",
" align-items: stretch;\n",
" justify-content: center;\n",
" background-color: var(--sklearn-color-background);\n",
" position: relative;\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-parallel-item {\n",
" display: flex;\n",
" flex-direction: column;\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-parallel-item:first-child::after {\n",
" align-self: flex-end;\n",
" width: 50%;\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-parallel-item:last-child::after {\n",
" align-self: flex-start;\n",
" width: 50%;\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-parallel-item:only-child::after {\n",
" width: 0;\n",
"}\n",
"\n",
"/* Serial-specific style estimator block */\n",
"\n",
"#sk-container-id-1 div.sk-serial {\n",
" display: flex;\n",
" flex-direction: column;\n",
" align-items: center;\n",
" background-color: var(--sklearn-color-background);\n",
" padding-right: 1em;\n",
" padding-left: 1em;\n",
"}\n",
"\n",
"\n",
"/* Toggleable style: style used for estimator/Pipeline/ColumnTransformer box that is\n",
"clickable and can be expanded/collapsed.\n",
"- Pipeline and ColumnTransformer use this feature and define the default style\n",
"- Estimators will overwrite some part of the style using the `sk-estimator` class\n",
"*/\n",
"\n",
"/* Pipeline and ColumnTransformer style (default) */\n",
"\n",
"#sk-container-id-1 div.sk-toggleable {\n",
" /* Default theme specific background. It is overwritten whether we have a\n",
" specific estimator or a Pipeline/ColumnTransformer */\n",
" background-color: var(--sklearn-color-background);\n",
"}\n",
"\n",
"/* Toggleable label */\n",
"#sk-container-id-1 label.sk-toggleable__label {\n",
" cursor: pointer;\n",
" display: flex;\n",
" width: 100%;\n",
" margin-bottom: 0;\n",
" padding: 0.5em;\n",
" box-sizing: border-box;\n",
" text-align: center;\n",
" align-items: start;\n",
" justify-content: space-between;\n",
" gap: 0.5em;\n",
"}\n",
"\n",
"#sk-container-id-1 label.sk-toggleable__label .caption {\n",
" font-size: 0.6rem;\n",
" font-weight: lighter;\n",
" color: var(--sklearn-color-text-muted);\n",
"}\n",
"\n",
"#sk-container-id-1 label.sk-toggleable__label-arrow:before {\n",
" /* Arrow on the left of the label */\n",
" content: \"▸\";\n",
" float: left;\n",
" margin-right: 0.25em;\n",
" color: var(--sklearn-color-icon);\n",
"}\n",
"\n",
"#sk-container-id-1 label.sk-toggleable__label-arrow:hover:before {\n",
" color: var(--sklearn-color-text);\n",
"}\n",
"\n",
"/* Toggleable content - dropdown */\n",
"\n",
"#sk-container-id-1 div.sk-toggleable__content {\n",
" display: none;\n",
" text-align: left;\n",
" /* unfitted */\n",
" background-color: var(--sklearn-color-unfitted-level-0);\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-toggleable__content.fitted {\n",
" /* fitted */\n",
" background-color: var(--sklearn-color-fitted-level-0);\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-toggleable__content pre {\n",
" margin: 0.2em;\n",
" border-radius: 0.25em;\n",
" color: var(--sklearn-color-text);\n",
" /* unfitted */\n",
" background-color: var(--sklearn-color-unfitted-level-0);\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-toggleable__content.fitted pre {\n",
" /* unfitted */\n",
" background-color: var(--sklearn-color-fitted-level-0);\n",
"}\n",
"\n",
"#sk-container-id-1 input.sk-toggleable__control:checked~div.sk-toggleable__content {\n",
" /* Expand drop-down */\n",
" display: block;\n",
" width: 100%;\n",
" overflow: visible;\n",
"}\n",
"\n",
"#sk-container-id-1 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {\n",
" content: \"▾\";\n",
"}\n",
"\n",
"/* Pipeline/ColumnTransformer-specific style */\n",
"\n",
"#sk-container-id-1 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
" color: var(--sklearn-color-text);\n",
" background-color: var(--sklearn-color-unfitted-level-2);\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-label.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
" background-color: var(--sklearn-color-fitted-level-2);\n",
"}\n",
"\n",
"/* Estimator-specific style */\n",
"\n",
"/* Colorize estimator box */\n",
"#sk-container-id-1 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
" /* unfitted */\n",
" background-color: var(--sklearn-color-unfitted-level-2);\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-estimator.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
" /* fitted */\n",
" background-color: var(--sklearn-color-fitted-level-2);\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-label label.sk-toggleable__label,\n",
"#sk-container-id-1 div.sk-label label {\n",
" /* The background is the default theme color */\n",
" color: var(--sklearn-color-text-on-default-background);\n",
"}\n",
"\n",
"/* On hover, darken the color of the background */\n",
"#sk-container-id-1 div.sk-label:hover label.sk-toggleable__label {\n",
" color: var(--sklearn-color-text);\n",
" background-color: var(--sklearn-color-unfitted-level-2);\n",
"}\n",
"\n",
"/* Label box, darken color on hover, fitted */\n",
"#sk-container-id-1 div.sk-label.fitted:hover label.sk-toggleable__label.fitted {\n",
" color: var(--sklearn-color-text);\n",
" background-color: var(--sklearn-color-fitted-level-2);\n",
"}\n",
"\n",
"/* Estimator label */\n",
"\n",
"#sk-container-id-1 div.sk-label label {\n",
" font-family: monospace;\n",
" font-weight: bold;\n",
" display: inline-block;\n",
" line-height: 1.2em;\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-label-container {\n",
" text-align: center;\n",
"}\n",
"\n",
"/* Estimator-specific */\n",
"#sk-container-id-1 div.sk-estimator {\n",
" font-family: monospace;\n",
" border: 1px dotted var(--sklearn-color-border-box);\n",
" border-radius: 0.25em;\n",
" box-sizing: border-box;\n",
" margin-bottom: 0.5em;\n",
" /* unfitted */\n",
" background-color: var(--sklearn-color-unfitted-level-0);\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-estimator.fitted {\n",
" /* fitted */\n",
" background-color: var(--sklearn-color-fitted-level-0);\n",
"}\n",
"\n",
"/* on hover */\n",
"#sk-container-id-1 div.sk-estimator:hover {\n",
" /* unfitted */\n",
" background-color: var(--sklearn-color-unfitted-level-2);\n",
"}\n",
"\n",
"#sk-container-id-1 div.sk-estimator.fitted:hover {\n",
" /* fitted */\n",
" background-color: var(--sklearn-color-fitted-level-2);\n",
"}\n",
"\n",
"/* Specification for estimator info (e.g. \"i\" and \"?\") */\n",
"\n",
"/* Common style for \"i\" and \"?\" */\n",
"\n",
".sk-estimator-doc-link,\n",
"a:link.sk-estimator-doc-link,\n",
"a:visited.sk-estimator-doc-link {\n",
" float: right;\n",
" font-size: smaller;\n",
" line-height: 1em;\n",
" font-family: monospace;\n",
" background-color: var(--sklearn-color-background);\n",
" border-radius: 1em;\n",
" height: 1em;\n",
" width: 1em;\n",
" text-decoration: none !important;\n",
" margin-left: 0.5em;\n",
" text-align: center;\n",
" /* unfitted */\n",
" border: var(--sklearn-color-unfitted-level-1) 1pt solid;\n",
" color: var(--sklearn-color-unfitted-level-1);\n",
"}\n",
"\n",
".sk-estimator-doc-link.fitted,\n",
"a:link.sk-estimator-doc-link.fitted,\n",
"a:visited.sk-estimator-doc-link.fitted {\n",
" /* fitted */\n",
" border: var(--sklearn-color-fitted-level-1) 1pt solid;\n",
" color: var(--sklearn-color-fitted-level-1);\n",
"}\n",
"\n",
"/* On hover */\n",
"div.sk-estimator:hover .sk-estimator-doc-link:hover,\n",
".sk-estimator-doc-link:hover,\n",
"div.sk-label-container:hover .sk-estimator-doc-link:hover,\n",
".sk-estimator-doc-link:hover {\n",
" /* unfitted */\n",
" background-color: var(--sklearn-color-unfitted-level-3);\n",
" color: var(--sklearn-color-background);\n",
" text-decoration: none;\n",
"}\n",
"\n",
"div.sk-estimator.fitted:hover .sk-estimator-doc-link.fitted:hover,\n",
".sk-estimator-doc-link.fitted:hover,\n",
"div.sk-label-container:hover .sk-estimator-doc-link.fitted:hover,\n",
".sk-estimator-doc-link.fitted:hover {\n",
" /* fitted */\n",
" background-color: var(--sklearn-color-fitted-level-3);\n",
" color: var(--sklearn-color-background);\n",
" text-decoration: none;\n",
"}\n",
"\n",
"/* Span, style for the box shown on hovering the info icon */\n",
".sk-estimator-doc-link span {\n",
" display: none;\n",
" z-index: 9999;\n",
" position: relative;\n",
" font-weight: normal;\n",
" right: .2ex;\n",
" padding: .5ex;\n",
" margin: .5ex;\n",
" width: min-content;\n",
" min-width: 20ex;\n",
" max-width: 50ex;\n",
" color: var(--sklearn-color-text);\n",
" box-shadow: 2pt 2pt 4pt #999;\n",
" /* unfitted */\n",
" background: var(--sklearn-color-unfitted-level-0);\n",
" border: .5pt solid var(--sklearn-color-unfitted-level-3);\n",
"}\n",
"\n",
".sk-estimator-doc-link.fitted span {\n",
" /* fitted */\n",
" background: var(--sklearn-color-fitted-level-0);\n",
" border: var(--sklearn-color-fitted-level-3);\n",
"}\n",
"\n",
".sk-estimator-doc-link:hover span {\n",
" display: block;\n",
"}\n",
"\n",
"/* \"?\"-specific style due to the `<a>` HTML tag */\n",
"\n",
"#sk-container-id-1 a.estimator_doc_link {\n",
" float: right;\n",
" font-size: 1rem;\n",
" line-height: 1em;\n",
" font-family: monospace;\n",
" background-color: var(--sklearn-color-background);\n",
" border-radius: 1rem;\n",
" height: 1rem;\n",
" width: 1rem;\n",
" text-decoration: none;\n",
" /* unfitted */\n",
" color: var(--sklearn-color-unfitted-level-1);\n",
" border: var(--sklearn-color-unfitted-level-1) 1pt solid;\n",
"}\n",
"\n",
"#sk-container-id-1 a.estimator_doc_link.fitted {\n",
" /* fitted */\n",
" border: var(--sklearn-color-fitted-level-1) 1pt solid;\n",
" color: var(--sklearn-color-fitted-level-1);\n",
"}\n",
"\n",
"/* On hover */\n",
"#sk-container-id-1 a.estimator_doc_link:hover {\n",
" /* unfitted */\n",
" background-color: var(--sklearn-color-unfitted-level-3);\n",
" color: var(--sklearn-color-background);\n",
" text-decoration: none;\n",
"}\n",
"\n",
"#sk-container-id-1 a.estimator_doc_link.fitted:hover {\n",
" /* fitted */\n",
" background-color: var(--sklearn-color-fitted-level-3);\n",
"}\n",
"\n",
".estimator-table summary {\n",
" padding: .5rem;\n",
" font-family: monospace;\n",
" cursor: pointer;\n",
"}\n",
"\n",
".estimator-table details[open] {\n",
" padding-left: 0.1rem;\n",
" padding-right: 0.1rem;\n",
" padding-bottom: 0.3rem;\n",
"}\n",
"\n",
".estimator-table .parameters-table {\n",
" margin-left: auto !important;\n",
" margin-right: auto !important;\n",
"}\n",
"\n",
".estimator-table .parameters-table tr:nth-child(odd) {\n",
" background-color: #fff;\n",
"}\n",
"\n",
".estimator-table .parameters-table tr:nth-child(even) {\n",
" background-color: #f6f6f6;\n",
"}\n",
"\n",
".estimator-table .parameters-table tr:hover {\n",
" background-color: #e0e0e0;\n",
"}\n",
"\n",
".estimator-table table td {\n",
" border: 1px solid rgba(106, 105, 104, 0.232);\n",
"}\n",
"\n",
".user-set td {\n",
" color:rgb(255, 94, 0);\n",
" text-align: left;\n",
"}\n",
"\n",
".user-set td.value pre {\n",
" color:rgb(255, 94, 0) !important;\n",
" background-color: transparent !important;\n",
"}\n",
"\n",
".default td {\n",
" color: black;\n",
" text-align: left;\n",
"}\n",
"\n",
".user-set td i,\n",
".default td i {\n",
" color: black;\n",
"}\n",
"\n",
".copy-paste-icon {\n",
" background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0NDggNTEyIj48IS0tIUZvbnQgQXdlc29tZSBGcmVlIDYuNy4yIGJ5IEBmb250YXdlc29tZSAtIGh0dHBzOi8vZm9udGF3ZXNvbWUuY29tIExpY2Vuc2UgLSBodHRwczovL2ZvbnRhd2Vzb21lLmNvbS9saWNlbnNlL2ZyZWUgQ29weXJpZ2h0IDIwMjUgRm9udGljb25zLCBJbmMuLS0+PHBhdGggZD0iTTIwOCAwTDMzMi4xIDBjMTIuNyAwIDI0LjkgNS4xIDMzLjkgMTQuMWw2Ny45IDY3LjljOSA5IDE0LjEgMjEuMiAxNC4xIDMzLjlMNDQ4IDMzNmMwIDI2LjUtMjEuNSA0OC00OCA0OGwtMTkyIDBjLTI2LjUgMC00OC0yMS41LTQ4LTQ4bDAtMjg4YzAtMjYuNSAyMS41LTQ4IDQ4LTQ4ek00OCAxMjhsODAgMCAwIDY0LTY0IDAgMCAyNTYgMTkyIDAgMC0zMiA2NCAwIDAgNDhjMCAyNi41LTIxLjUgNDgtNDggNDhMNDggNTEyYy0yNi41IDAtNDgtMjEuNS00OC00OEwwIDE3NmMwLTI2LjUgMjEuNS00OCA0OC00OHoiLz48L3N2Zz4=);\n",
" background-repeat: no-repeat;\n",
" background-size: 14px 14px;\n",
" background-position: 0;\n",
" display: inline-block;\n",
" width: 14px;\n",
" height: 14px;\n",
" cursor: pointer;\n",
"}\n",
"</style><body><div id=\"sk-container-id-1\" class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>SVC()</pre><b>In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. <br />On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.</b></div><div class=\"sk-container\" hidden><div class=\"sk-item\"><div class=\"sk-estimator fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-1\" type=\"checkbox\" checked><label for=\"sk-estimator-id-1\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow\"><div><div>SVC</div></div><div><a class=\"sk-estimator-doc-link fitted\" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.7/modules/generated/sklearn.svm.SVC.html\">?<span>Documentation for SVC</span></a><span class=\"sk-estimator-doc-link fitted\">i<span>Fitted</span></span></div></label><div class=\"sk-toggleable__content fitted\" data-param-prefix=\"\">\n",
" <div class=\"estimator-table\">\n",
" <details>\n",
" <summary>Parameters</summary>\n",
" <table class=\"parameters-table\">\n",
" <tbody>\n",
" \n",
" <tr class=\"default\">\n",
" <td><i class=\"copy-paste-icon\"\n",
" onclick=\"copyToClipboard('C',\n",
" this.parentElement.nextElementSibling)\"\n",
" ></i></td>\n",
" <td class=\"param\">C&nbsp;</td>\n",
" <td class=\"value\">1.0</td>\n",
" </tr>\n",
" \n",
"\n",
" <tr class=\"default\">\n",
" <td><i class=\"copy-paste-icon\"\n",
" onclick=\"copyToClipboard('kernel',\n",
" this.parentElement.nextElementSibling)\"\n",
" ></i></td>\n",
" <td class=\"param\">kernel&nbsp;</td>\n",
" <td class=\"value\">&#x27;rbf&#x27;</td>\n",
" </tr>\n",
" \n",
"\n",
" <tr class=\"default\">\n",
" <td><i class=\"copy-paste-icon\"\n",
" onclick=\"copyToClipboard('degree',\n",
" this.parentElement.nextElementSibling)\"\n",
" ></i></td>\n",
" <td class=\"param\">degree&nbsp;</td>\n",
" <td class=\"value\">3</td>\n",
" </tr>\n",
" \n",
"\n",
" <tr class=\"default\">\n",
" <td><i class=\"copy-paste-icon\"\n",
" onclick=\"copyToClipboard('gamma',\n",
" this.parentElement.nextElementSibling)\"\n",
" ></i></td>\n",
" <td class=\"param\">gamma&nbsp;</td>\n",
" <td class=\"value\">&#x27;scale&#x27;</td>\n",
" </tr>\n",
" \n",
"\n",
" <tr class=\"default\">\n",
" <td><i class=\"copy-paste-icon\"\n",
" onclick=\"copyToClipboard('coef0',\n",
" this.parentElement.nextElementSibling)\"\n",
" ></i></td>\n",
" <td class=\"param\">coef0&nbsp;</td>\n",
" <td class=\"value\">0.0</td>\n",
" </tr>\n",
" \n",
"\n",
" <tr class=\"default\">\n",
" <td><i class=\"copy-paste-icon\"\n",
" onclick=\"copyToClipboard('shrinking',\n",
" this.parentElement.nextElementSibling)\"\n",
" ></i></td>\n",
" <td class=\"param\">shrinking&nbsp;</td>\n",
" <td class=\"value\">True</td>\n",
" </tr>\n",
" \n",
"\n",
" <tr class=\"default\">\n",
" <td><i class=\"copy-paste-icon\"\n",
" onclick=\"copyToClipboard('probability',\n",
" this.parentElement.nextElementSibling)\"\n",
" ></i></td>\n",
" <td class=\"param\">probability&nbsp;</td>\n",
" <td class=\"value\">False</td>\n",
" </tr>\n",
" \n",
"\n",
" <tr class=\"default\">\n",
" <td><i class=\"copy-paste-icon\"\n",
" onclick=\"copyToClipboard('tol',\n",
" this.parentElement.nextElementSibling)\"\n",
" ></i></td>\n",
" <td class=\"param\">tol&nbsp;</td>\n",
" <td class=\"value\">0.001</td>\n",
" </tr>\n",
" \n",
"\n",
" <tr class=\"default\">\n",
" <td><i class=\"copy-paste-icon\"\n",
" onclick=\"copyToClipboard('cache_size',\n",
" this.parentElement.nextElementSibling)\"\n",
" ></i></td>\n",
" <td class=\"param\">cache_size&nbsp;</td>\n",
" <td class=\"value\">200</td>\n",
" </tr>\n",
" \n",
"\n",
" <tr class=\"default\">\n",
" <td><i class=\"copy-paste-icon\"\n",
" onclick=\"copyToClipboard('class_weight',\n",
" this.parentElement.nextElementSibling)\"\n",
" ></i></td>\n",
" <td class=\"param\">class_weight&nbsp;</td>\n",
" <td class=\"value\">None</td>\n",
" </tr>\n",
" \n",
"\n",
" <tr class=\"default\">\n",
" <td><i class=\"copy-paste-icon\"\n",
" onclick=\"copyToClipboard('verbose',\n",
" this.parentElement.nextElementSibling)\"\n",
" ></i></td>\n",
" <td class=\"param\">verbose&nbsp;</td>\n",
" <td class=\"value\">False</td>\n",
" </tr>\n",
" \n",
"\n",
" <tr class=\"default\">\n",
" <td><i class=\"copy-paste-icon\"\n",
" onclick=\"copyToClipboard('max_iter',\n",
" this.parentElement.nextElementSibling)\"\n",
" ></i></td>\n",
" <td class=\"param\">max_iter&nbsp;</td>\n",
" <td class=\"value\">-1</td>\n",
" </tr>\n",
" \n",
"\n",
" <tr class=\"default\">\n",
" <td><i class=\"copy-paste-icon\"\n",
" onclick=\"copyToClipboard('decision_function_shape',\n",
" this.parentElement.nextElementSibling)\"\n",
" ></i></td>\n",
" <td class=\"param\">decision_function_shape&nbsp;</td>\n",
" <td class=\"value\">&#x27;ovr&#x27;</td>\n",
" </tr>\n",
" \n",
"\n",
" <tr class=\"default\">\n",
" <td><i class=\"copy-paste-icon\"\n",
" onclick=\"copyToClipboard('break_ties',\n",
" this.parentElement.nextElementSibling)\"\n",
" ></i></td>\n",
" <td class=\"param\">break_ties&nbsp;</td>\n",
" <td class=\"value\">False</td>\n",
" </tr>\n",
" \n",
"\n",
" <tr class=\"default\">\n",
" <td><i class=\"copy-paste-icon\"\n",
" onclick=\"copyToClipboard('random_state',\n",
" this.parentElement.nextElementSibling)\"\n",
" ></i></td>\n",
" <td class=\"param\">random_state&nbsp;</td>\n",
" <td class=\"value\">None</td>\n",
" </tr>\n",
" \n",
" </tbody>\n",
" </table>\n",
" </details>\n",
" </div>\n",
" </div></div></div></div></div><script>function copyToClipboard(text, element) {\n",
" // Get the parameter prefix from the closest toggleable content\n",
" const toggleableContent = element.closest('.sk-toggleable__content');\n",
" const paramPrefix = toggleableContent ? toggleableContent.dataset.paramPrefix : '';\n",
" const fullParamName = paramPrefix ? `${paramPrefix}${text}` : text;\n",
"\n",
" const originalStyle = element.style;\n",
" const computedStyle = window.getComputedStyle(element);\n",
" const originalWidth = computedStyle.width;\n",
" const originalHTML = element.innerHTML.replace('Copied!', '');\n",
"\n",
" navigator.clipboard.writeText(fullParamName)\n",
" .then(() => {\n",
" element.style.width = originalWidth;\n",
" element.style.color = 'green';\n",
" element.innerHTML = \"Copied!\";\n",
"\n",
" setTimeout(() => {\n",
" element.innerHTML = originalHTML;\n",
" element.style = originalStyle;\n",
" }, 2000);\n",
" })\n",
" .catch(err => {\n",
" console.error('Failed to copy:', err);\n",
" element.style.color = 'red';\n",
" element.innerHTML = \"Failed!\";\n",
" setTimeout(() => {\n",
" element.innerHTML = originalHTML;\n",
" element.style = originalStyle;\n",
" }, 2000);\n",
" });\n",
" return false;\n",
"}\n",
"\n",
"document.querySelectorAll('.fa-regular.fa-copy').forEach(function(element) {\n",
" const toggleableContent = element.closest('.sk-toggleable__content');\n",
" const paramPrefix = toggleableContent ? toggleableContent.dataset.paramPrefix : '';\n",
" const paramName = element.parentElement.nextElementSibling.textContent.trim();\n",
" const fullParamName = paramPrefix ? `${paramPrefix}${paramName}` : paramName;\n",
"\n",
" element.setAttribute('title', fullParamName);\n",
"});\n",
"</script></body>"
],
"text/plain": [
"SVC()"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from sklearn import svm\n",
"clf = svm.SVC(kernel='rbf')\n",
"clf.fit(X_train, y_train) "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"After being fitted, the model can then be used to predict new values:\n"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([2, 4, 2, 4, 2])"
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"yhat = clf.predict(X_test)\n",
"yhat [0:5]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h2 id=\"evaluation\">Evaluation</h2>\n"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [],
"source": [
"from sklearn.metrics import classification_report, confusion_matrix\n",
"import itertools"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [],
"source": [
"def plot_confusion_matrix(cm, classes,\n",
" normalize=False,\n",
" title='Confusion matrix',\n",
" cmap=plt.cm.Blues):\n",
" \"\"\"\n",
" This function prints and plots the confusion matrix.\n",
" Normalization can be applied by setting `normalize=True`.\n",
" \"\"\"\n",
" if normalize:\n",
" cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]\n",
" print(\"Normalized confusion matrix\")\n",
" else:\n",
" print('Confusion matrix, without normalization')\n",
"\n",
" print(cm)\n",
"\n",
" plt.imshow(cm, interpolation='nearest', cmap=cmap)\n",
" plt.title(title)\n",
" plt.colorbar()\n",
" tick_marks = np.arange(len(classes))\n",
" plt.xticks(tick_marks, classes, rotation=45)\n",
" plt.yticks(tick_marks, classes)\n",
"\n",
" fmt = '.2f' if normalize else 'd'\n",
" thresh = cm.max() / 2.\n",
" for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):\n",
" plt.text(j, i, format(cm[i, j], fmt),\n",
" horizontalalignment=\"center\",\n",
" color=\"white\" if cm[i, j] > thresh else \"black\")\n",
"\n",
" plt.tight_layout()\n",
" plt.ylabel('True label')\n",
" plt.xlabel('Predicted label')"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" precision recall f1-score support\n",
"\n",
" 2 1.00 0.94 0.97 90\n",
" 4 0.90 1.00 0.95 47\n",
"\n",
" accuracy 0.96 137\n",
" macro avg 0.95 0.97 0.96 137\n",
"weighted avg 0.97 0.96 0.96 137\n",
"\n",
"Confusion matrix, without normalization\n",
"[[85 5]\n",
" [ 0 47]]\n"
]
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAioAAAHpCAYAAACspBc0AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjcsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvTLEjVAAAAAlwSFlzAAAPYQAAD2EBqD+naQAAVDNJREFUeJzt3Qm8jHX7x/HrPpZjJ7IWSfayFJFSIZFKpD1FkpZHCmnxlK2S0kLK0qpUWihKC39ZsyWKNjxElqwle5Y4/9f31zPzzBwHZ+Zst/t83r3u1zlzzz0z94xp5jrX7/pdPy8pKSnJAAAAfCghq08AAADgSAhUAACAbxGoAAAA3yJQAQAAvkWgAgAAfItABQAA+BaBCgAA8C0CFQAA4FsEKgAAwLcIVAAc0fLly61Zs2ZWuHBh8zzPxo8fn66v1q+//uru94033uBfIZny5cvbLbfcwuuCbI9ABfC5X375xe644w6rUKGC5cmTxwoVKmTnnXeePf/88/bXX39l6GO3b9/efvjhB+vfv7+99dZbVrdu3Qx9vCD6+eefrW/fvi4oAxA7j7V+AP/67LPP7JprrrHExERr166dnXHGGbZ//36bNWuWffjhh+4v7pdffjlDHltBUL58+ezhhx+2xx9/PEMeQ0uN7du3z3LlymU5cuSwIBo7dqz7N5w2bZo1atQo1bfT65KQkOBeGyA7y5nVJwAgZatWrbLrr7/eTjnlFJs6daqVLl06fF3nzp1txYoVLpDJKFu2bHE/ixQpkmGPoWEfZYnwv8Bt7969ljdvXhecAqBGBfCtgQMH2q5du+y1116LClJCKlasaPfee2/48t9//22PPfaYnXbaae5LTjUO//73v91f5pG0//LLL3dZmXr16rlAQcNKo0aNCh+joQoFSHL//fe7gEK3E2VxQr9H0m10XKTJkydbw4YNXbBToEABq1KlijunY9WoKDA7//zzLX/+/O62rVq1siVLlqT4eArYdE46TrU0HTp0sD179hzz9VV2Qxmq77//3i688EKXPdJrqgyIzJgxw+rXr++CBp33l19+GXX71atX27/+9S93nY4pVqyYy5xEDvHoeWmfNG7c2J2vtunTp0f9W0yaNMkNq+l+XnrppcNqVBTA6PbFixe3zZs3h+9f2bUaNWq4f/Pdu3cf8zkDxyNqVACfmjBhggsgzj333FQdf9ttt1nv3r3trLPOskGDBrkv3wEDBrisTHL6cr/66qvt4osvtmeffdZOOOEE96X4008/uevbtGnj7kNuuOEGV58yePDgmM5f96UvYQVKjz76qHucK664wmbPnn3U2ykgaN68uftCVjDSvXt3mzNnjqvLSanO49prr7WdO3e656rfFRz069cvVef4559/unNUQKLAUAGeXq/333/f/bz00kvtySefdEGAXi89Tsg333zjzkvHDRkyxO68806bMmWKC4BCgdIFF1xg99xzj/tdAZpeR23VqlUL38+yZcvca6x/C9Ud1a5d+7DzVHDz+uuvu2yLHiekT58+7nUeOXKkC+qAQFKNCgB/2b59e5L+92zVqlWqjl+0aJE7/rbbbova36NHD7d/6tSp4X2nnHKK2zdz5szwvs2bNyclJiYm3XfffeF9q1atcsc9/fTTUffZvn17dx/J9enTxx0fMmjQIHd5y5YtRzzv0GOMHDkyvK927dpJJUqUSPrjjz/C+xYvXpyUkJCQ1K5du8Me79Zbb426zyuvvDKpWLFiScdy4YUXutuPHj06vG/p0qVunx5r3rx54f2TJk067Dz37Nlz2H3OnTvXHTdq1KjwvjFjxrh906ZNO+z40L/FxIkTU7xOr3Wkl156yR3/9ttvu/PLkSNHUteuXY/5XIHjGRkVwId27NjhfhYsWDBVx3/++efup7IPke677z73M3ktS/Xq1d3QSoiGFDSEsXLlSksvodqWjz/+2A4dOpSq22zYsMEWLVrksjtFixYN769Zs6bLOISeZ6TIDIPoef3xxx/h1/BoNBwVmXHSa6DzVsZDWZaQ0O+Rr4+GaUIOHDjgHlNDR7r9t99+a6l16qmnugxSatx+++3u2C5dutjNN9/shnyeeOKJVD8WcDwiUAF8SFOQJXKo4WhUL6EZIvqijFSqVCn3xanrI5UrV+6w+9Dwj4ZC0st1113nhms0JFWyZEkXEHzwwQdHDVpC56mAITkFD7///vthtRjJn4ueh6TmuZx88smH1dWozqVs2bKH7Ut+n5oVpaE2HashoxNPPNEFfNu2bbPt27dbLIFKLFSzpKEl9bjRMFdkwAQEEYEK4NNApUyZMvbjjz/GdLvkX7pHcqSpwCrajPcxDh48GHVZX6AzZ850NSf6619FqwpelBlJfmxapOW5HOm2qblPZTXUX0Z1MQrA/u//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dsL/AuycOfhaOK55FNMCMLNzalWwT2d8bxNn/eRejzUbttq1l9S1uqefEvX67N//t236YyevGXwrR84cVrJkqaw+DaQTL4AZFWpUgDjMW7zSGterYhXLlXCXa1Q+yRrUruCGdiKdX7eSrZ4ywBaP62XP//s6K1o4P683fGXVLyvsjErlrG6NynZnx5tt3do1WX1KQBRyfHEoX768de3a1W3p7eabb7Zq1arZv//971Qd//vvv1v16tXt22+/tZNPPjndzwcpe2bkZCtUII8tHveIHTyYZDlyeNZn6Kf23hcLwsdMnrPEPp662H797Q+rcPKJ1q9LS/v4xbvswvbP2qFDKa82CmSms+rWsyEjXrOKlSrbpo0b7ZkBj1nL5o3tq68XWYGCBfnHOA55ZFT87ZZbbgn/I2krVqyYXXLJJfb999+n6+N88803dvvtt1t6W7x4sX3++ed2zz33uMsHDhywBx980GrUqGH58+e3MmXKWLt27Wz9+vXh25x44oluX58+fdL9fHBkVzc7y65vcbbd8u83rcGNT9ltvd+yrjdfZG1b1g8fM2bSQvtsxg/204r1NmH699bmnhFW94zydkHdSry08IWmzS6xVldebaefUdOaNG1m7344wbZv32bjPxqT1aeGOHn6z4tz82nHt8AN/Sgw2bBhg9umTJliOXPmtMsvvzxdH6N48eKWL18+S28vvPCCXXPNNVagQAF3ec+ePS5T0qtXL/fzo48+smXLltkVV1wRdbsOHTrYO++8Y1u3bk33c0LKnuja2mVVFIwoEHn3s2/shXem2v0dLj7iS6bMypY/d9ppZYvzssKXChcpYqdVrGSrVv6S1aeCOHnxBilpyMRktMAFKomJiVaqVCm31a5d2x566CFbu3atbdmyxV2v36+99lorUqSIFS1a1Fq1amW//vprVFamdevW9swzz1jp0qVdVqZz584uuxE59DN48ODw5aVLl1rDhg0tT548bhjmyy+/dP/g48ePd9fr/nVZgUbjxo1dkFOrVi2bO3du+D4OHjxoY8eOtZYtW4b3FS5c2CZPnuzOt0qVKnbOOefYiy++aAsXLrQ1a/43jnz66ae7bMu4ceMy8JVFpLx5ctuhpENR+w4eSrKEhCP/L3VSiSJWrHB+2/j7Dl5M+NKuXbvs11UrrWQpimvhH4ELVJL/T/f2229bxYoVXcChYKN58+ZWsGBB++qrr2z27Nkue6EszP79+8O3mzZtmv3yyy/u55tvvmlvvPGG21KiAEOBjYKPr7/+2l5++WV7+OGHUzxW+3v06GGLFi2yypUr2w033GB///3PdFUNT23fvt3q1q171OekYxT0KNCKVK9ePfecjmbfvn22Y8eOqA3x+XzmD/Zgx+Z2ScPTrVzponZF45p2z02N7ZOpi931+fPmdlmXejXKu+sb1atsHwy63X5Z+7urXQH8oM+/H7DZs2bamtW/2vx5c+yWG6+2HAk5rM3V12f1qSGt05O9ODcfClwx7aeffhoeOtm9e7fLimif/tIdPXq0HTp0yF599dVwimvkyJHuS3/69OnWrFkzt++EE05wmYscOXJY1apV7bLLLnPDSJ06dTrs8ZTxUFCj2yuLI/3797eLLz58CEBBiu5L+vXr5zIhK1ascI+xevVq93glSvwziyQle/fudTUrCnAKFSoUdZ0yKt99991RX5sBAwa4x0XadX9qjPX51+VuJk/xEwq4hm+vjZ1tT7z8RTi7ckalk1zNSpGCed31X85dao8O+9T2H6CXCvxh/frf7I4ON9mfW/+wYicWt/oNzrMvps6yE4szPHm88gJYTBu4QEVDK8OHD3e///nnnzZs2DBr0aKFzZ8/3xWrKjBQRiV5AKBgI0QBhIKGEAU7P/zwQ4qPp5qRsmXLhoOUUHYjJTVr1oy6T9m8ebMLVP766y83bHWkN4qyQRoCSkpKCj+/SHnz5nU1LUfTs2dP6969e/iyMio6d8Ru1559dv8zH7otJXv3HbArOg/lpYWvvfLGO1l9CkhnHoGK/2l2jIZ6QpQ9Ua3HK6+84oaC6tSp4wpPUyqQDcmVK9dh//DKxKRV5P2GApLQ/Wr2jgINDUHlzp07xSBFWZepU6celk0RFdJGPoeUKBDSBgDA8SJwGZXkFBBo2EcZi7POOsvef/99N7yS0pd9PFTkqgLdTZs2WcmSJcPTl2Olwl/5+eefw79HBinLly93NTOqtUnJjz/+aI0aNYr7eQAAjn+e988W7239KHDFtCoY3bhxo9uWLFliXbp0cZkUzaZp27aty1xopo8KT1etWuVqS9S3ZN26dXE9nmpRTjvtNGvfvr0riFWB7iOPPBLzeJ+yIQqkZs2aFRWkXH311bZgwQKXBVLhbui5RRb/KhOjmUChGhsAQHYOVLw4N/OlwAUqEydOdPUf2urXr++yG2PGjHHZBs3MmTlzppUrV87atGnjOsB27NjR1ajEm2FRLYumISsYOvvss+22224Lz/rRdOVY6LaRw1K//fabffLJJy6IUpYl9Ly0zZkzJ3zcxx9/7J7T+eefH9dzAADAr7wkVWciXSmror4qKtxVtiW1NDyloSQNTzVo0CDVt1N/FWWFbrzxxpjOU8W0qt9JrNHJvBzRdTGAX6396n89jAA/27ljh1U4qZhrK5Fe5QbH+jyvcM9Yy5EY35piB/fttpVDrs6U841F4GtUMoMarWlKdKVKlVxwcu+999p5550XU5ASmrkzatQot35PaulYZYc0ZRkAkL15zPpBSnbu3On6m6hbrGpgmjZtas8++2xcL1asBbF6vAceeIB/GACABbGYloxKOtCigNoAAED6IlABACAgEhLUkiO+1EhSnLfLaIGb9QMAQHYf+vHi3GKl2ak33XST6/GlOssaNWq4lhohmq/Tu3dvN1tV16s0Qn3BYkGgAgBAQHhx91CJfY0gLVOjiSPquv7FF1+4hqWqz9R6eSEDBw60IUOG2IgRI9zCveoer8WB1RYktRj6AQAAMXvqqafcenFa3Dfk1FNPjcqmDB482DVBVaNV0cxWdXFX/7Hrr0/dKt1kVAAACAgvHYZ+1JMlclPH95SoIWndunXtmmuucUvTnHnmmW5dvRB1f1cndQ33hKjXi5qxzp07N9XPiUAFAICA8NJh6EdZEgUUoW3AgAEpPtbKlStt+PDhrofYpEmT7K677nLNR9988013vYIUCa2DF6LLoetSg6EfAAACwkuHhm9aaDeyM21iYmKKxx86dMhlVJ544gl3WRkVLZCrehStf5deyKgAAIAwBSmR25ECFc3kqV69etQ+raGn5qdSqlQp93PTpk1Rx+hy6LrUIFABACAgvEycnqwZP8uWLYva95///MdOOeWUcGGtApIpU6aEr1fNi2b/xLKeHUM/AAAEhGdpGPqx2G7XrVs3O/fcc93Qz7XXXmvz58+3l19+2W3u/jzPunbtao8//rirY1Hg0qtXLytTpoy1bt061Y9DoAIAQEB4mbjWz9lnn+0W5e3Zs6c9+uijLhDRdOS2bduGj9FadLt377bbb7/dtm3bZg0bNrSJEydanjx5Uv04BCoAACAul19+uduORFkVBTHa4kWgAgBAQHjpMOvHbwhUAAAICC8Th34yC4EKAAAB4QUwo8L0ZAAA4FtkVAAACAiPoR8AAOBXXgCHfsioAAAQFF4aimL9GadQowIAAPyLjAoAAAHhMfQDAAD8ygtgMS3TkwEAgG8x9AMAQEB4DP0AAAC/8gI49ENGBQCAgPACmFGhRgUAAPgWGRUAAALCC2BGhUAFAICA8KhRAQAAfuUFMKNCjQoAAPAthn4AAAgIj6EfAADgV14Ah37IqAAAEBBeGhq3+TNMoUYFAAD4GBkVAAACIsHz3Bbvbf2IQAUAgIDwKKYFAAB+5QWwmJY+KgAAwLcY+gEAICASvH+2eG/rRwQqAAAEhZeGIRwCFQAAkJG8ABbTUqMCAABi1rdv33DxbmirWrVq+Pq9e/da586drVixYlagQAG76qqrbNOmTTE/DoEKAAAB4aXxv1idfvrptmHDhvA2a9as8HXdunWzCRMm2JgxY2zGjBm2fv16a9OmTcyPQY0KAAABkZDJxbQ5c+a0UqVKHbZ/+/bt9tprr9no0aOtSZMmbt/IkSOtWrVqNm/ePDvnnHNS/xipOeiTTz5J9R1eccUVqT4WAAD4q4/Kjh07ovYnJia6LSXLly+3MmXKWJ48eaxBgwY2YMAAK1eunC1cuNAOHDhgTZs2DR+rYSFdN3fu3PQPVFq3bp3qJ3nw4MFUPzgAAPCXsmXLRl3u06ePq0dJrn79+vbGG29YlSpV3LBPv3797Pzzz7cff/zRNm7caLlz57YiRYpE3aZkyZLuulikKlA5dOhQTHcKAACOz1k/a9eutUKFCoX3Hymb0qJFi/DvNWvWdIHLKaecYh988IHlzZvX0kuaimlV0QsAAPy1KGFCnJsoSIncjhSoJKfsSeXKlW3FihWubmX//v22bdu2qGM06yelmpajPqeYjjZzQzuPPfaYnXTSSW660cqVK93+Xr16ucIZAACQ/ezatct++eUXK126tNWpU8dy5cplU6ZMCV+/bNkyW7NmjatlydBApX///m5MauDAgW78KeSMM86wV199Nda7AwAA6Tz048W5xaJHjx5u2vGvv/5qc+bMsSuvvNJy5MhhN9xwgxUuXNg6duxo3bt3t2nTprni2g4dOrggJZZC2rimJ48aNcpefvllu+iii+zOO+8M769Vq5YtXbo01rsDAADH4erJ69atc0HJH3/8YcWLF7eGDRu6qcf6XQYNGmQJCQmu0du+ffusefPmNmzYsJjPK+ZA5bfffrOKFSumWHCrqUgAACD4LfTfe++9o16vKctDhw51W1rEPPRTvXp1++qrrw7bP3bsWDvzzDPTdDIAAABpyqj07t3b2rdv7zIryqJ89NFHrkBGQ0KffvpprHcHAADSSULE7J14butHMWdUWrVq5Xr3f/nll5Y/f34XuCxZssTtu/jiizPmLAEAwDF5adz8KK61ftR5bvLkyel/NgAA4Lgops0scS9KuGDBApdJCdWtaM40AABAlgYqoelIs2fPDvfwV+e5c88911UAn3zyyel6ggAAwJ+rJ/uyRuW2225z05CVTdm6davb9LsKa3UdAADI2qEfL84tEBkVdaFTBzqtlhii31944QVXuwIAALKO5894I/MyKlr+OaXGbloDqEyZMul1XgAAALEHKk8//bR16dLFFdOG6Pd7773XnnnmGV5SAACyiJddh35OOOGEqCewe/duq1+/vuXM+c/N//77b/f7rbfeaq1bt864swUAANmqmDZVgcrgwYMz/kwAAECaeNm1j4pa5gMAABw3Dd9k7969tn///qh9hQoVSus5AQCAOHhpaIXvBaWYVvUpd999t5UoUcKt9aP6lcgNAABk7aKECXFugQhUHnjgAZs6daoNHz7cEhMT7dVXX7V+/fq5qclaQRkAAGQNz0vbFoihH62SrICkUaNG1qFDB9fkrWLFinbKKafYO++8Y23bts2YMwUAANlOzBkVtcyvUKFCuB5Fl6Vhw4Y2c+bM9D9DAACQbfuoxByoKEhZtWqV+71q1ar2wQcfhDMtoUUKAQBA5vMCOPQTc6Ci4Z7Fixe73x966CEbOnSo5cmTx7p162b3339/RpwjAADIpsW0MdeoKCAJadq0qS1dutQWLlzo6lRq1qyZ3ucHAACysTT1UREV0WoDAABZy0vDEI5PEyqpC1SGDBmS6ju855570nI+AAAgTl52baE/aNCgVD9JApXjz5rpz9BRGMeNW99dlNWnAKTKgb928UplVqASmuUDAAD8KyGeWTIRtw1kjQoAAPAHL7sO/QAAAP/zPE1Rjv+2fuTXTA8AAAAZFQAAgiIhDRmVeG+X0Rj6AQAgILwA1qjENfTz1Vdf2U033WQNGjSw3377ze176623bNasWel9fgAAIMaMSrxbWjz55JMu2OnatWt43969e61z585WrFgxK1CggF111VW2adOmjA1UPvzwQ2vevLnlzZvXvvvuO9u3b5/bv337dnviiSdivTsAAHCc++abb+yll146bCkdLbujRYvHjBljM2bMsPXr11ubNm0yNlB5/PHHbcSIEfbKK69Yrly5wvvPO+88+/bbb2O9OwAAcByvnrxr1y5r27atiwtOOOGE8H4lMF577TV77rnnrEmTJlanTh0bOXKkzZkzx+bNm5dxgcqyZcvsggsuOGx/4cKFbdu2bbHeHQAA8NHqyTt27IjaQiMnR6Khncsuu8wtVBxJCxYfOHAgan/VqlWtXLlyNnfu3NQ/p1hfhFKlStmKFSsO26/6lAoVKsR6dwAAIJ070ybEuUnZsmVd8iG0DRgw4IiP995777nRlJSO2bhxo+XOnduKFCkStb9kyZLuugyb9dOpUye799577fXXX3dFMxpvUmTUo0cP69WrV6x3BwAAfGTt2rVR678lJiYe8TjFA5MnT7Y8efJk2PnEHKg89NBDdujQIbvoootsz549bhhIT0KBSpcuXTLmLAEAwDGlpdYkdDsFKZGBypFoaGfz5s121llnhfcdPHjQZs6caS+++KJNmjTJ9u/f78pCIrMqmvWj0ZkMC1SURXn44Yft/vvvd0NAKqKpXr26m3YEAACyToL9r9YkntvGQgmLH374IWpfhw4dXB3Kgw8+6IaQNOlmypQpblpyqM51zZo1rr1Jhjd807iTAhQAABCcjEpqFSxY0M4444yoffnz53c9U0L7O3bsaN27d7eiRYu6LI1GXhSknHPOORkXqDRu3Pio3eumTp0a610CAIAAGjRokCUkJLiMimYPqQ/bsGHDYrqPmAOV2rVrR13W1KNFixbZjz/+aO3bt4/17gAAQEDW+pk+fXrUZRXZDh061G3xyhlPdJSSvn37unoVAACQNTwXqMS71o8FZ62flGjtH01ZBgAA2acz7XETqKiXSkbOowYAANlPzEM/yRcTSkpKsg0bNtiCBQto+AYAQDauUfFFoKJ2upFUzVulShV79NFHrVmzZul5bgAAIAbef/+LR7y381Wgoo5zauZSo0aNqBUSAQBA1ksIYEYlphqVHDlyuKwJqyQDAABfFtOq29zKlSsz5mwAAECaMyoJcW6BCFQef/xxtwDhp59+6opod+zYEbUBAICs4XlemrbjukZFxbL3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NdaxY0c79dRTo4KV77//3p555hnbvn27PfXUU1a1atWsPmXgiBYvXmxnnnmmyw5+9tln1qxZs/BMHwUk2q/391lnnWVly5Z1xwBHQpUekMVef/11u+GGG+ytt96y999/333AazxfQYqGgqRmzZrWvn17W7Vqlc2YMcPtC10H+I0yJHXr1rV27drZdddd52b8qBZFW2hoU+/vF1980bZs2WLjx4/P6lOGjxGoAFlowoQJ9sADD9igQYNs0qRJtmTJEjdm37VrVxeIRKbCL7roIrv55putT58+ruA2spYF8JOCBQu696+KwK+66ioXiGsIU6ZMmWL79+8PB+CnnHKKzZ07N4vPGH5GoAJkkT/++MMVE95111129dVXW758+dxfmRdffLH9/vvvLhAJzYgIpc3vueceq1OnjpvyCfhJqA5FQzp58uRxQzoVK1Z0dVWaltyiRQsrUaKEffzxx+EC2yJFirj3vzIqGvYEUkKgAmQyFcVKsWLF3DBP5cqVo66vVauWmxGxe/duN0tCQgFLYmKilSxZ0n788Uf+3eALd955p23atCmc/VOwnTt3bheUKHty0kknuRlr2r9t2zY799xzXSAjClb0/4Cuz58/fxY/E/jVP5V6ADLFq6++at99950bv5d///vfhx2jTEoog5IrVy73U6lxfaDrA/7ZZ591hbeAH/z6669u5o5moynwCNWiKPBQwC0a+qlQoYLrm6JGhnnz5rVWrVq560444QRr3bq1C9yBlJBRATKRZvOMGTPGfvrppyOufaIsigKU0F+YF1xwgT344IMumxL6YD/vvPP4d4MvnHzyyTZ27Fj3u7IqofeyAhEVf2uGmhq8qQbr0UcftUaNGtnw4cOjhovKlSuXhc8AfkegAmQiFcqqBmXatGlRwUlkd0592Ovynj177JJLLnH1Kl9++SUdPOEroffvQw89ZFOnTnWdZiU0BKSaq/fee8/Kly/vgnPVo+h3FY5//vnnUccCR8O7BMhEyopUqlTJnn76adu4cWO4+DCSPuC1Tw2xNE1ZPSk05p/8OCCrAhS9F0PBtQpm1TH5o48+sm+++SZ8XL169ezbb7910+5VVxWZgVGAwqKESC0CFSCT/wLt27ev+7C+/PLL3WUVGUYGITt27HDj/vowX7p0qRsGimz+BmSlXbt2hd+Lyozs3LnTBSrqMqsarMj6qdq1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",
"text/plain": [
"<Figure size 640x480 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Compute confusion matrix\n",
"cnf_matrix = confusion_matrix(y_test, yhat, labels=[2,4])\n",
"np.set_printoptions(precision=2)\n",
"\n",
"print (classification_report(y_test, yhat))\n",
"\n",
"# Plot non-normalized confusion matrix\n",
"plt.figure()\n",
"plot_confusion_matrix(cnf_matrix, classes=['Benign(2)','Malignant(4)'],normalize= False, title='Confusion matrix')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can also easily use the __f1_score__ from sklearn library:\n"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"0.9639038982104676"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from sklearn.metrics import f1_score\n",
"f1_score(y_test, yhat, average='weighted') "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's try the jaccard index for accuracy:\n"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"0.9444444444444444"
]
},
"execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from sklearn.metrics import jaccard_score\n",
"jaccard_score(y_test, yhat,pos_label=2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h2 id=\"practice\">Practice</h2>\n",
"Can you rebuild the model, but this time with a __linear__ kernel? You can use __kernel='linear'__ option, when you define the svm. How the accuracy changes with the new kernel function?\n"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Avg F1-score: 0.9639\n",
"Jaccard score: 0.9444\n"
]
}
],
"source": [
"clf2 = svm.SVC(kernel='linear')\n",
"clf2.fit(X_train, y_train) \n",
"yhat2 = clf2.predict(X_test)\n",
"print(\"Avg F1-score: %.4f\" % f1_score(y_test, yhat2, average='weighted'))\n",
"print(\"Jaccard score: %.4f\" % jaccard_score(y_test, yhat2,pos_label=2))\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<details><summary>Click here for the solution</summary>\n",
"\n",
"```python\n",
"clf2 = svm.SVC(kernel='linear')\n",
"clf2.fit(X_train, y_train) \n",
"yhat2 = clf2.predict(X_test)\n",
"print(\"Avg F1-score: %.4f\" % f1_score(y_test, yhat2, average='weighted'))\n",
"print(\"Jaccard score: %.4f\" % jaccard_score(y_test, yhat2,pos_label=2))\n",
"\n",
"```\n",
"\n",
"</details>\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Thank you for completing this lab!\n",
"\n",
"\n",
"## Author\n",
"\n",
"Saeed Aghabozorgi\n",
"\n",
"\n",
"### Other Contributors\n",
"\n",
"<a href=\"https://www.linkedin.com/in/joseph-s-50398b136/\" target=\"_blank\">Joseph Santarcangelo</a>\n",
"\n",
"## <h3 align=\"center\"> © IBM Corporation 2020. All rights reserved. <h3/>\n",
"\n",
"<!--\n",
"## Change Log\n",
"\n",
"\n",
"| Date (YYYY-MM-DD) | Version | Changed By | Change Description |\n",
"|---|---|---|---|\n",
"| 2021-01-21 | 2.2 | Lakshmi | Updated sklearn library |\n",
"| 2020-11-03 | 2.1 | Lakshmi | Updated URL of csv |\n",
"| 2020-08-27 | 2.0 | Lavanya | Moved lab to course repo in GitLab |\n",
"| | | | |\n",
"| | | | |\n",
"--!>\n",
"\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"PUTRA AL RIFKI (202310715112)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"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.12.0"
},
"prev_pub_hash": "33c7dcfb268d8bbcaef711e72c89e89dc7bc1929452f1913b971040b140900c5"
},
"nbformat": 4,
"nbformat_minor": 4
}