{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Stat479: Machine Learning -- L02: kNN in Python"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"STAT 479: Machine Learning (Fall 2018) \n",
"Instructor: Sebastian Raschka (sraschka@wisc.edu) \n",
"Course website: http://pages.stat.wisc.edu/~sraschka/teaching/stat479-fs2018/"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Sebastian Raschka \n",
"last updated: 2018-09-09 \n",
"\n",
"CPython 3.6.6\n",
"IPython 6.5.0\n",
"\n",
"numpy 1.15.0\n",
"scipy 1.1.0\n",
"matplotlib 2.2.2\n",
"sklearn 0.19.1\n"
]
}
],
"source": [
"%load_ext watermark\n",
"%watermark -d -u -a 'Sebastian Raschka' -v -p numpy,scipy,matplotlib,sklearn"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 0 - General Imports"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 1 - Load Dataset into a Pandas DataFrame"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" Id | \n",
" SepalLength[cm] | \n",
" SepalWidth[cm] | \n",
" PetalLength[cm] | \n",
" PetalWidth[cm] | \n",
" Species | \n",
"
\n",
" \n",
" \n",
" \n",
" 145 | \n",
" 146 | \n",
" 6.7 | \n",
" 3.0 | \n",
" 5.2 | \n",
" 2.3 | \n",
" Iris-virginica | \n",
"
\n",
" \n",
" 146 | \n",
" 147 | \n",
" 6.3 | \n",
" 2.5 | \n",
" 5.0 | \n",
" 1.9 | \n",
" Iris-virginica | \n",
"
\n",
" \n",
" 147 | \n",
" 148 | \n",
" 6.5 | \n",
" 3.0 | \n",
" 5.2 | \n",
" 2.0 | \n",
" Iris-virginica | \n",
"
\n",
" \n",
" 148 | \n",
" 149 | \n",
" 6.2 | \n",
" 3.4 | \n",
" 5.4 | \n",
" 2.3 | \n",
" Iris-virginica | \n",
"
\n",
" \n",
" 149 | \n",
" 150 | \n",
" 5.9 | \n",
" 3.0 | \n",
" 5.1 | \n",
" 1.8 | \n",
" Iris-virginica | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" Id SepalLength[cm] SepalWidth[cm] PetalLength[cm] PetalWidth[cm] \\\n",
"145 146 6.7 3.0 5.2 2.3 \n",
"146 147 6.3 2.5 5.0 1.9 \n",
"147 148 6.5 3.0 5.2 2.0 \n",
"148 149 6.2 3.4 5.4 2.3 \n",
"149 150 5.9 3.0 5.1 1.8 \n",
"\n",
" Species \n",
"145 Iris-virginica \n",
"146 Iris-virginica \n",
"147 Iris-virginica \n",
"148 Iris-virginica \n",
"149 Iris-virginica "
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_iris = pd.read_csv('iris.csv')\n",
"df_iris.tail()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 2 - Get Features into a NumPy Array"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[1.4, 0.2],\n",
" [1.4, 0.2],\n",
" [1.3, 0.2],\n",
" [1.5, 0.2],\n",
" [1.4, 0.2]])"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"X = df_iris[['PetalLength[cm]', 'PetalWidth[cm]']].values\n",
"X[:5, :]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 3 - Get Class Labels into a NumPy Array"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" Id | \n",
" SepalLength[cm] | \n",
" SepalWidth[cm] | \n",
" PetalLength[cm] | \n",
" PetalWidth[cm] | \n",
" Species | \n",
" ClassLabel | \n",
"
\n",
" \n",
" \n",
" \n",
" 145 | \n",
" 146 | \n",
" 6.7 | \n",
" 3.0 | \n",
" 5.2 | \n",
" 2.3 | \n",
" Iris-virginica | \n",
" 2 | \n",
"
\n",
" \n",
" 146 | \n",
" 147 | \n",
" 6.3 | \n",
" 2.5 | \n",
" 5.0 | \n",
" 1.9 | \n",
" Iris-virginica | \n",
" 2 | \n",
"
\n",
" \n",
" 147 | \n",
" 148 | \n",
" 6.5 | \n",
" 3.0 | \n",
" 5.2 | \n",
" 2.0 | \n",
" Iris-virginica | \n",
" 2 | \n",
"
\n",
" \n",
" 148 | \n",
" 149 | \n",
" 6.2 | \n",
" 3.4 | \n",
" 5.4 | \n",
" 2.3 | \n",
" Iris-virginica | \n",
" 2 | \n",
"
\n",
" \n",
" 149 | \n",
" 150 | \n",
" 5.9 | \n",
" 3.0 | \n",
" 5.1 | \n",
" 1.8 | \n",
" Iris-virginica | \n",
" 2 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" Id SepalLength[cm] SepalWidth[cm] PetalLength[cm] PetalWidth[cm] \\\n",
"145 146 6.7 3.0 5.2 2.3 \n",
"146 147 6.3 2.5 5.0 1.9 \n",
"147 148 6.5 3.0 5.2 2.0 \n",
"148 149 6.2 3.4 5.4 2.3 \n",
"149 150 5.9 3.0 5.1 1.8 \n",
"\n",
" Species ClassLabel \n",
"145 Iris-virginica 2 \n",
"146 Iris-virginica 2 \n",
"147 Iris-virginica 2 \n",
"148 Iris-virginica 2 \n",
"149 Iris-virginica 2 "
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"label_dict = {'Iris-setosa': 0,\n",
" 'Iris-versicolor': 1,\n",
" 'Iris-virginica': 2}\n",
"\n",
"df_iris['ClassLabel'] = df_iris['Species'].map(label_dict)\n",
"df_iris.tail()"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([0, 0, 0, 0, 0])"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"y = df_iris['ClassLabel'].values\n",
"y[:5]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 4 - Shuffle Dataset and Create Training and Test Subsets"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,\n",
" 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,\n",
" 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,\n",
" 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,\n",
" 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,\n",
" 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,\n",
" 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,\n",
" 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103,\n",
" 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,\n",
" 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129,\n",
" 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142,\n",
" 143, 144, 145, 146, 147, 148, 149])"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"indices = np.arange(y.shape[0])\n",
"indices"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([ 72, 112, 132, 88, 37, 138, 87, 42, 8, 90, 141, 33, 59,\n",
" 116, 135, 104, 36, 13, 63, 45, 28, 133, 24, 127, 46, 20,\n",
" 31, 121, 117, 4, 130, 119, 29, 0, 62, 93, 131, 5, 16,\n",
" 82, 60, 35, 143, 145, 142, 114, 136, 53, 19, 38, 110, 23,\n",
" 9, 86, 91, 89, 79, 101, 65, 115, 41, 124, 95, 21, 11,\n",
" 103, 74, 122, 118, 44, 51, 81, 149, 12, 129, 56, 50, 25,\n",
" 128, 146, 43, 1, 71, 54, 100, 14, 6, 80, 26, 70, 139,\n",
" 30, 108, 15, 18, 77, 22, 10, 58, 107, 75, 64, 69, 3,\n",
" 40, 76, 134, 34, 27, 94, 85, 97, 102, 52, 92, 99, 105,\n",
" 7, 48, 61, 120, 137, 125, 147, 39, 84, 2, 67, 55, 49,\n",
" 68, 140, 78, 144, 111, 32, 73, 47, 148, 113, 96, 57, 123,\n",
" 106, 83, 17, 98, 66, 126, 109])"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"rnd = np.random.RandomState(123)\n",
"shuffled_indices = rnd.permutation(indices)\n",
"shuffled_indices"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"X_shuffled, y_shuffled = X[shuffled_indices], y[shuffled_indices]"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"X_train, y_train = X_shuffled[:100], y_shuffled[:100]\n",
"X_test, y_test = X_shuffled[100:], y_shuffled[100:]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 5 - Doing Steps 1-4 in Scikit-Learn"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"from sklearn.datasets import load_iris\n",
"from sklearn.model_selection import train_test_split\n",
"\n",
"\n",
"iris = load_iris()\n",
"X, y = iris.data[:, 2:], iris.target\n",
"X_train, X_test, y_train, y_test = train_test_split(X, y, \n",
" test_size=0.3,\n",
" random_state=123,\n",
" shuffle=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 6 - Plot Dataset"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAYUAAAEKCAYAAAD9xUlFAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAIABJREFUeJzt3XuYU9XVx/HvYgCHq4igIqhQtXhhYMBRoCiCWAUviLdWtFXQlmpf7/VeS5HWV7TUarWvPCCoIFW8FdFKsYiiUkUGGUAKiKLCAFWEgqAgMKz3j2TiXJKZM5Nkkkx+n+fJM8nJzjkrEbOyz9lrb3N3REREABqkOgAREUkfSgoiIhKhpCAiIhFKCiIiEqGkICIiEUoKIiISoaQgIiIRSgoiIhKhpCAiIhENUx1ATbVp08Y7duyY6jBERDLKwoULv3T3ttW1y7ik0LFjRwoLC1MdhohIRjGzz4K00+kjERGJUFIQEZEIJQUREYnIuGsK0ezevZvi4mJ27tyZ6lAkhXJzc+nQoQONGjVKdSgiGateJIXi4mJatGhBx44dMbNUhyMp4O5s2rSJ4uJiOnXqlOpwRDJWvTh9tHPnTvbff38lhCxmZuy///7qLYrEqV4kBUAJQfRvQCQBknb6yMwOASYDBwF7gfHu/mCFNv2AF4FPwptecPfRyYpJRDJPr6m9+HrP15W2N2vYjHcvebfWr48m6D7rs2T2FPYAv3L3o4FewP+Y2TFR2r3l7vnhW71KCKNGjWLs2LFJ2ffChQvJy8vjiCOO4NprryXWWtsPPPAAkydPBuDdd9+lZ8+e5Ofnc/TRRzNq1Kgqj1FUVMQrr7yS0Lh37dpF37592bNnT0L3K/VXrC/0oF/0QdvVtG19lbSk4O4b3P398P1twHKgfbKOl22uuuoqxo8fz6pVq1i1ahX/+Mc/KrXZs2cPkyZN4uKLLwbgsssuY/z48RQVFfHBBx/wox/9qMpjJCMpNG7cmAEDBjBt2rSE7ldEEqNOrimYWUegOzA/ytO9zWyxmc00s2NjvH6EmRWaWeHGjRvjjmf6onX0GTOHTrf9nT5j5jB90bq49zl58mS6du1Kt27d+OlPf1rp+QkTJnD88cfTrVs3zj//fL755hsAnn32Wbp06UK3bt3o27cvAMuWLeOEE04gPz+frl27smrVqnL72rBhA1999RW9e/fGzLj00kuZPn16pWPOmTOHHj160LBh6CzhF198Qbt27QDIycnhmGNCHbevv/6ayy+/nOOPP57u3bvz4osvsmvXLkaOHMm0adPIz89n2rRpbN68mSFDhtC1a1d69erFkiVLAJg7dy75+fnk5+fTvXt3tm3bxvbt2xkwYAA9evQgLy+PF198MRLXkCFDmDp1arwfuYgkQdKHpJpZc+B54Hp3/6rC0+8Dh7n7djM7A5gOHFlxH+4+HhgPUFBQEP08SUDTF63j9heWsmN3CQDrtuzg9heWAjCke+06MsuWLePuu+9m3rx5tGnThs2bN1dqc9555/Hzn/8cgDvvvJOJEydyzTXXMHr0aGbNmkX79u3ZsmULAOPGjeO6667jkksuYdeuXZSUlJTb17p16+jQoUPkcYcOHVi3rnJimzdvHscdd1zk8Q033EDnzp3p168fAwcO5LLLLiM3N5e7776bU045hUmTJrFlyxZOOOEETj31VEaPHk1hYSEPP/wwANdccw3du3dn+vTpzJkzh0svvZSioiLGjh3LX/7yF/r06cP27dvJzc0F4G9/+xstW7bkyy+/pFevXgwePBgzo0uXLixYsKBWn7WIJFdSewpm1ohQQpjq7i9UfN7dv3L37eH7rwCNzKxNMmP6w6yVkYRQasfuEv4wa2Wt9zlnzhwuuOAC2rQJhd66detKbT744ANOOukk8vLymDp1KsuWLQOgT58+DBs2jAkTJkS+/Hv37s3//u//cu+99/LZZ5/RpEmTcvuKdv0g2sibDRs20Lbtd5Mijhw5ksLCQk477TT++te/MnDgQABeffVVxowZQ35+Pv369WPnzp2sWbOm0v7efvvtSC/olFNOYdOmTWzdupU+ffpw44038uc//5ktW7bQsGFD3J077riDrl27cuqpp7Ju3To+//xzINRLady4Mdu2bav+wxWROpW0pGChb6mJwHJ3vz9Gm4PC7TCzE8LxbEpWTADrt+yo0fYg3L3a4ZDDhg3j4YcfZunSpfz2t7+NjKcfN24cv//971m7di35+fls2rSJiy++mBkzZtCkSRNOP/105syZU25fHTp0oLi4OPK4uLiYgw8+uNIxmzRpUmnc/uGHH85VV13Fa6+9xuLFi9m0aRPuzvPPP09RURFFRUWsWbOGo48+Our7rMjMuO2223j00UfZsWMHvXr1YsWKFUydOpWNGzeycOFCioqKOPDAA8vF8u2330Z6FCJVadawWY2217ZdTdvWV8k8fdQH+Cmw1MyKwtvuAA4FcPdxwAXAVWa2B9gBXOSxhtEkyMGtmrAuSgI4uFWTKK2DGTBgAOeeey433HAD+++/P5s3b67UW9i2bRvt2rVj9+7dTJ06lfbtQ6eqPv74Y3r27EnPnj156aWXWLt2LVu3buV73/se1157LatXr2bJkiWccsopkX21a9eOFi1aREYTTZ48mWuuuaZSXEcffTQfffRR5PHf//53zjjjDMyMVatWkZOTQ6tWrTj99NN56KGHeOihhzAzFi1aRPfu3WnRokW5X/N9+/Zl6tSp/OY3v+GNN96gTZs2tGzZko8//pi8vDzy8vJ45513WLFiBVu3buWAAw6gUaNGvP7663z22Xez9m7atIm2bdtqOgoJJN4hotk+xLSmkpYU3P1toMqfz+7+MPBwsmKI5ubTO5e7pgDQpFEON5/eudb7PPbYY/n1r3/NySefTE5ODt27d+fxxx8v1+Z3v/sdPXv25LDDDiMvLy/yZXvzzTezatUq3J0BAwbQrVs3xowZw5NPPkmjRo046KCDGDlyZKVjPvLIIwwbNowdO3YwaNAgBg0aVKnNoEGDyl30njJlCjfccANNmzalYcOGTJ06lZycHH7zm99w/fXX07VrV9ydjh078vLLL9O/f//IaaXbb7+dUaNGMXz4cLp27UrTpk154okngNCw19dffz1y8XrQoEFs27aNs88+m4KCAvLz8znqqKMicbz++uucccYZtf68JTXirRcIIu+JvJjPLb1saUKOIVWzJP8wT7iCggKvuMjO8uXLo57uiGX6onX8YdZK1m/ZwcGtmnDz6Z1rfZE53Z177rncd999HHlkpev3KXPeeedxzz330Llz7RNxLDX9tyDB1cUXtpJC8pjZQncvqK5dvZgQr6aGdG9fb5NARWPGjGHDhg1pkxR27drFkCFDkpIQRCR+WZkUsknnzp3T6gu4cePGXHrppakOQ0RiqDcT4omISPyUFEREJEJJQUQCibdeQDKDrimISCB1Md5fI4xSTz2FJErm1Nm//vWvOeSQQ2jevHmV7aZPn87o0aN544036N27d7nn9uzZw4EHHsiGDRviimX9+vVccMEFtXptv379qDjEuDoXXXRRpUkCRSQx1FPIUGeffTZXX311tUNN77vvPmbMmEHr1q0pLi7m008/pWPHjgDMnj2bLl26RGZOrc6ePXsiM66WdfDBB/Pcc8/V+D3URklJCVdddRX33XcfEyZMqJNjSs0kelGbuiiaS0epet/Z21PY9h94sBts+zwhu6vLqbMBevXqVe2X+Ycffsg+++xDmzZtaNCgARdeeGG5dQyefvpphg4dCoSm2xg4cCDHHXccJ510EitWrABCczbdeOON9O/fn1tvvTXqNNmffvopXbp0AUJf2jfddBN5eXl07dqVhx56CIDXXnuN7t27k5eXx+WXX863335bKd6nnnqKvLw8unTpwq233hrZ3rx5c0aOHEnPnj155513OOmkk5g9e7YW6klTiV7UJt5FdjJVqt539iaFuffBljUw9964d1U6dfacOXNYvHgxDz74YKU25513HgsWLGDx4sUcffTRTJw4ESAydfbixYuZMWMG8N3U2UVFRRQWFpabJrsm5s2bR48ePSKPhw4dytNPPw2EJqR75ZVXOP/88wEYMWIEDz30EAsXLmTs2LH88pe/jLzuww8/ZPbs2fzxj3+MTJNdVFTEW2+9VWkG1/Hjx/PJJ5+waNEilixZwiWXXMLOnTsZNmwY06ZNY+nSpezZs4dHHnmk3OvWr1/Prbfeypw5cygqKmLBggWRNSK+/vprunTpwvz58znxxBNp0KABRxxxBIsXL67V5yIisWVnUtj2HyiaCr439DfO3kJdT50dVMWps48//ni2b9/OypUrmTlzJr169WK//fZj+/bt/Otf/+LCCy8kPz+fX/ziF+WuM1x44YXk5ORE4q04TXZZs2fP5sorr4xsb926NStXrqRTp058//vfB0IrwL355pvlXrdgwQL69etH27ZtadiwIZdcckmkTU5OTiR5lTrggANYv359rT4XEYktO5PC3PtCCQFCf+PsLdT11NlBRZs6+6KLLuLpp58ud+po7969tGrVKjJ1dlFREcuXL4+8plmz74YcRpsmu7rPIsj8WlW1yc3NjSSlUjt37qx1shSR2LIvKZT2Ekp2hR6X7Iq7tzBgwACeeeYZNm0KLQURbeW1ilNnlyqdOnv06NG0adOGtWvXsnr16sjU2YMHD44se1lTFafOhtAppCeffJI5c+YwePBgAFq2bEmnTp149tlngdAXdKxTM6XTZN96660UFBRUSgqnnXYa48aNi5zv37x5M0cddRSffvppJJYpU6Zw8sknl3tdz549mTt3Ll9++SUlJSU89dRTldqU9eGHH3LssVFXbxWROGRfUijbSygVZ2+h7NTZ3bp148Ybb6zUpnTq7B/+8IflppG++eabIxdX+/btS7du3Zg2bRpdunQhPz+fFStWRJ0r6JZbbqFDhw588803dOjQgVGjRlVq07dvXxYtWlTuV/gxxxxD06ZNOeWUU8r1AKZOncrEiRPp1q0bxx57bLk1lct64IEHIhfGmzRpUmnK7p/97GcceuihkYvuf/3rX8nNzeWxxx7jwgsvJC8vjwYNGnDllVeWe127du2455576N+/P926daNHjx6cc845UWP4/PPPadKkSeBRU1K3Er2oTbYWzaXqfWff1Nl/PAq2RRmX36Id/GpF5e0Z7rrrruPss8/m1FNPTXUoCfOnP/2Jli1bcsUVV1R6TlNni0SnqbNjqYdf/FW54447mD9/fqrDSKhWrVpFHfYrIvHLvqSQZQ488MDItYP6Yvjw4akOQaTeyr5rCiIiEpOSgoiIRCgpiIhIhJKCiIhEKCkkUbKmzv7mm28488wzOeqoozj22GO57bbbYrYNOnX2yJEjmT17do3iKCws5Nprr6223Q9+8IMa7bfUww8/zGOPPVar14pI7Wj0UYa66aab6N+/P7t27WLAgAHMnDmzUiEZBJ86e/To0VGPU1JSUmmKiVIFBQUUFFQ77Jl//etfwd9YGZdffjl9+vTRaCOROpR1SSFZc5RPnjyZsWPHYmZ07dqVKVOmlHt+woQJjB8/nl27dnHEEUcwZcoUmjZtyrPPPstdd91FTk4O++67L2+++SbLli1j+PDh7Nq1i7179/L888+XWzehadOm9O/fH4DGjRvTo0cPiouLK8VUdupsIDJ1dum01GXnPxo2bBhnnXUWF1xwAR07duTyyy/n1Vdf5eqrr+bwww/niiuuoFmzZpx44onMnDmTDz74gDfeeIOxY8fy8ssvM2rUKNasWcPq1atZs2YN119/faQX0bx5c7Zv3w6EktSUKVNo0KABgwYNYsyYMTE/m6ZNm9KxY0fee+89TjjhhFr/t5HUC/r/XbxrMaTT2gvpFEtNZN3po2TMUZ7KqbO3bNnCSy+9xIABAyo9V5OpsyvKzc3l7bff5qKLLmL48OGMGzeOd955J2avAWDFihXMmjWL9957j7vuuovdu3eXe37mzJlMnz6d+fPns3jxYm655ZYqPxsI9UbeeuutmMeUzBD0/7t412JIp7UX0imWmsi6pJAMqZo6e8+ePQwdOpRrr72W733ve5WeDzp1djQ//vGPgVDS2bZtW+S6wMUXXxzzczjzzDMjPZMDDjiAzz8vP8ng7NmzGT58OE2bNi33OcX6bEBTZIvUNSWFBEjV1NkjRozgyCOP5Prrr4/6fNCps6MpnSyvJnNj7bPPPpH7OTk5lVZGi/U5xfpsQFNki9Q1JYUESMXU2XfeeSdbt27lgQceiBlX0Kmzq7LffvvRokUL3n03dA609PRTbZx22mlMmjQpshRp6ecU67OB0HWR0qU+RST5lBQSoK6nzi4uLubuu+/m3//+Nz169CA/P59HH3200jFrMnV2VSZOnMiIESPo3bs37s6+++4b9KMpZ+DAgQwePJiCggLy8/Mjw3VjfTYQui5Sn2Z4FUl3WTd1dqaOCKitREydvX37dpo3bw7AmDFj2LBhQ9SL6Ym2aNEi7r///kojuaqiqbPTk0YfpTYWCD51dtKSgpkdAkwGDgL2AuPd/cEKbQx4EDgD+AYY5u7vV7XfuNdTyDKff/458+fPj2um1GnTpnHPPfewZ88eDjvsMB5//PFyF7CT5Z///CdHHnlkpK4iCP1bEIkuHZJCO6Cdu79vZi2AhcAQd/93mTZnANcQSgo9gQfdvWdV+1VSkKro30Ji1OQXezT1tecdr1T2HoImhaRdU3D3DaW/+t19G7AcaF+h2TnAZA95F2gVTia1OV5c8Urm07+BxIl3LH26j8VPlUyoXaiTC81m1hHoDlRcAqw9sLbM42IqJ45q5ebmsmnTJn0pZDF3Z9OmTeTm5qY6FJGMlvRpLsysOfA8cL27f1Xx6SgvqfTNbmYjgBEAhx56aKUXdOjQgeLiYjZu3Bh/wJKxcnNzq6z+FpHqJTUpmFkjQglhqru/EKVJMXBImccdgErlq+4+HhgPoWsKFZ9v1KgRnTp1SkjMIiLZLGmnj8IjiyYCy939/hjNZgCXWkgvYKu7b0hWTCIiUrVk9hT6AD8FlppZUXjbHcChAO4+DniF0MijjwgNSdUcySJpoFnDZnGPPpLKYn2u6fR51YviNRERqVrQIalZt56CiFQvnsridKvklZrR3EciUkk86xpkwlh8iU1JQUREIpQUREQkQklBREQilBRERCRCSUFEKqnJuPmKbWO9Np3G4ktsGpIqIpXEM3RUw04zm5KCSJZIt1XN6qoWIp64s7HmQqePRLJEPLUHVb2+tvUHdVULEU/c2VhzoaQgIiIRMU8fmdl5AV6/091fSWA8IiKSQlVdU5gAvEj0hXBK9SU006mIiNQDVSWFme5+eVUvNrMnExyPiIikUMxrCu7+k+peHKSNiKSHZnuDT5MfraYg0fUHdVULEU/c2VhzUe16CmaWA5wJdKRMz6KK1dSSSuspiIjUXCLXU3gJ2AksBfbGG5iI1F6dj5vf9h+YdDpc/iq0ODDx+5e0EyQpdHD3rkmPRESqVefj5ufeB1vWwNx74ayUnByQOhakTmGmmZ2W9EhEJL1s+w8UTQXfG/q77fNURyR1IEhSeBf4m5ntMLOvzGybmX2V7MBEJMXm3hdKCBD6O/fe1MYjdSJIUvgj0Bto6u4t3b2Fu7dMclwikkqlvYSSXaHHJbvUW8gSQZLCKuADr26YkojUH2V7CaXUW8gKQS40bwDeMLOZwLelG1M1JFUkmzVr2Czm6KOEWvnKd72EUiW7Qtt1wbleC5IUPgnfGodvIpIidTZd869W1M1xJO1UmxTc/a66CEREaiBo/UAy6gzSoHYhG9c5qCvVXlMws3+aWasyj/czs1nJDUtEqlS2fiAR7ZJx7CTKxnUO6kqQC81t3X1L6QN3/y9wQPJCEpEqBa0fSEadgWoX6r0gSaHEzA4tfWBmhwEaiSSSKkHrB5JRZ6DahXovSFL4NfC2mU0xsynAm8DtyQ1LRKIKWj+QjDoD1S5khWqTgrv/A+gBTAOeAY5zd11TEEmFoPUDyagzUO1CVoiZFMzsoNL77v6lu7/s7i+5+5fR2ohIHaiqfqA27ZJx7DqQjesc1JWY6ymY2fvu3qPKFwdok2haT0FEpOaCrqdQ1emjbuEJ8GLdtgExBymb2SQz+8LMPojxfD8z22pmReHbyOrflkg9su0/8GC32p2Tn/8ojNoXFj5e9f6CHiOeWKReqWo5zpzwBHixbi3cvX0V+34cGFjN8d9y9/zwbXRt3oBIxopnvP/Mm0N/X7qh6v2lsp5BMlKQ0Ue14u5vApuTtX+RjBbPeP/5j/LdIoh7Q72FaPtLZT2DZKykJYWAepvZYjObaWbHxmpkZiPMrNDMCjdu3FiX8YkkRzzj/Ut7CaVeuiH6/lJZzyAZK5VJ4X3gMHfvBjwETI/V0N3Hu3uBuxe0bdu2zgIUSYp4xvuX6yWU2guFj1fY35Ow6MnU1DNIRguUFMwsx8wONrNDS2/xHtjdv3L37eH7rwCNzKxNvPsVSXvxjPev2EuIKKnwcHfoVt0xVHsgFQSZEO8a4HPgn8Dfw7eX4z2wmR1kZha+f0I4lk3x7lck7cU13r9iLyEG31u5bV3VM0hGC7KewnVAZ3ev0Re2mT0F9APamFkx8FugEYC7jwMuAK4ysz3ADuAire4mWSGetQpGbU1cHKB1E6SSIElhLVDjf4nuPrSa5x8GHq7pfkWyzoYlMKE/jJgLB3WJ3S7aOgdBt6UJrZOQelVNc3Gjmd0IrCa0HOftpdvC20WkLrzwc9i7B56/oup2QesU0rgmQeskpF5V1xRahG9rCF1PaFxmW/PkhyYibFgCG8OneDaugP9EnSAgeJ2CahKkGjFPH5Uuw2lmF7r7s2WfM7MLkx2YiBDqJZT1/BXwP/Mrt4tVaxBk21n3Jz5uyVhBhqRGWztB6ymIJFvZXkKpaL2FaLUGi6LUKUTbpt6CVBCzp2Bmg4AzgPZm9ucyT7UE9iQ7MJGsV7GXUKpibyFarUHJbjCq36beglRQVU9hPbAQ2Bn+W3qbAZye/NBEstyXHwbbHq3WgL2VE0W0bWlWk6B1ElIv5noKkQZmjdx9d5WN6pDWUxARqbmg6ylUdfpoKeDh+5Wed/eu8QQoIiLpp6rTR2cBZwP/CN8uCd9eAZ5LfmgidSDRi8t8NCe0+M3qudUfY8MSGL1/+QvH0bYFjVsL5UgCVLXIzmfu/hnQx91vcfel4dtt6JqC1BeJLuR6bnjo7zOXVn+MaEVpiS5UE6mhIENSm5nZiaUPzOwHgK76SOZLdCHXR3Ng55bQ/Z1bQr2FWMeIVpSW6EI1kVoIkhSuAP5iZp+a2afA/wGXJzUqkbqQ6MVlSnsJpZ65NPYxohWlRdsWNG4tlCMJUu3oo0hDs5bh9gmeprFmNPpIEqL0/Puend9ta5gL1y2p3SRxH82BJ8+tvD2ncfnhog1zYejTMGVIsP1eOa/8JHhR494nNCSk5Nvyx6nte5F6Kejoo6omxPtJ+G/pBHg/A67QhHhSLyR6cZmKvYRSFesHfC88Oyz4fiv2FmIVqgVZUEckgKpOH5VeN2gR4yaSuRK9uEzptYTqlOwK3haCFaoFXVBHJIAgxWu57r6zykZ1SKePRERqLu7TR2V8YGbzzGyMmZ1hZvsmID6R+qkmtQJ1UVeg2gWpoWqTgrsfAQwFlhIqaFtsZkXJDkwkI9WkVqAu6gpUuyA1VG1SMLMOQB/gJKA7sAyYluS4RDJPTWoF6qKuQLULUgtBTh+tAa4HZrp7b3c/093vSXJcIpmnJrUCdVFXoNoFqYUgSaE7MBm42MzeMbPJZlZNDb5Ilom20E2sX+c1aVsX8YiUEeSawmLgCeAxYA5wMvCbJMclkllqUveQ6BqJeOMRKSPINYVC4B3gXGAF0NfdOyY5LpHMUpO6h0TXSMQbj0gZQeoU2rr7xjqKp1qqUxARqbmE1SmkU0KQeioTxtJr/QLJEkEuNIskVyaMpdf6BZIllBQktTJhLL3WL5AsUtUazedV9UJ3fyHx4UjWiTaW/qz7UxtTRbHG+6d73CK1EDMpEFqfORYHlBQkPrHG0p98a/qsAxAtxkVPfne/9G+6xS1SSzGTgrvHmCBeJEGqGkufLr+6Y61fYBXapVvcIrUU6JqCmZ1pZreY2cjSW7IDkyyQCWPpo8XI3iiJIs3iFqmlqk4fAWBm44CmQH/gUeAC4L0Ar5tEaFbVL9y9S5TnDXgQOAP4Bhjm7u/XKHrJbL9akeoIqpcJMYokUJCewg/c/VLgv+5+F9AbOCTA6x4HBlbx/CDgyPBtBPBIgH2KVBa0XiDR7RIdn0gaCJIUdoT/fmNmBwO7gU7Vvcjd3wQ2V9HkHGCyh7wLtDKzdgHiESkvaL1AotslOj6RNBAkKbxsZq2APwDvA58CTyfg2O2BtWUeF4e3iQQXtF4g0e0SHZ9ImgiSFO5z9y3u/jxwGHAU8PsEHLvi+A0IDXWt3NBshJkVmlnhxo2adUPKCLpmQKLbJTo+kTQRJCm8U3rH3b91961lt8WhmPLXJjoA66M1dPfx7l7g7gVt27ZNwKGlXgi6ZkCi2yU6PpE0EjMpmNlBZnYc0MTMuptZj/CtH6HRSPGaAVxqIb2Are6+IQH7lWwRdM2ARLdLdHwiaaSqnsLpwFhCv+DvB/4Yvt0A3FHdjs3sKUI9is5mVmxmV5jZlWZ2ZbjJK8Bq4CNgAvDLWr8LyU5B6xwS3S7R8YmkkSDrKZwfvp6QFrSegohIzSVsPQVgnplNNLOZ4R0fozWaRUTqpyBJ4TFgFnBw+PGHwPVJi0hERFImSFJo4+7PAHsB3H0PUJLUqEREJCWCJIWvzWx/wjUEpSOFkhqViIikRLUT4gE3Eho+eriZzQPaEpoUT0RE6plqk4K7v29mJwOdCVUhr3T33UmPTERE6lyQqbNzCdUQnEjoFNJbZjbO3XcmOzgREalbQU4fTQa2AQ+FHw8FpgAXJisoERFJjSBJobO7dyvz+HUzW5ysgEREJHWCjD5aFB5xBICZ9QTmJS8kERFJlSA9hZ6EJq5bE358KLDczJYC7u5dkxadiIjUqSBJoaolNUUEBQtAAAAMZ0lEQVREpB4JMiT1s7oIREREUi/INQUREckSSgoiIhKhpCAiIhFKCiIiEqGkICIiEUoKIiISoaQgIiIRSgoiIhKhpCAiIhFKCiIiEqGkICIiEUEmxJM4TV+0jj/MWsn6LTs4uFUTbj69M0O6t091WCIilSgpJNn0Reu4/YWl7NhdAsC6LTu4/YWlAEoMIpJ2dPooyf4wa2UkIZTasbuEP8xamaKIRERiU1JIsvVbdtRou4hIKikpJNnBrZrUaLuISCopKSTZzad3pkmjnHLbmjTK4ebTO6coIhGR2HShOclKLyZr9JGIZAIlhTowpHt7JQERyQhJPX1kZgPNbKWZfWRmt0V5fpiZbTSzovDtZ8mMJ51MX7SOPmPm0Om2v9NnzBymL1qX6pBERJLXUzCzHOAvwA+BYmCBmc1w939XaDrN3a9OVhzpSLULIpKuktlTOAH4yN1Xu/su4GngnCQeL2OodkFE0lUyk0J7YG2Zx8XhbRWdb2ZLzOw5Mzsk2o7MbISZFZpZ4caNG5MRa51S7YKIpKtkJgWLss0rPH4J6OjuXYHZwBPRduTu4929wN0L2rZtm+Aw655qF0QkXSUzKRQDZX/5dwDWl23g7pvc/dvwwwnAcUmMJ22odkFE0lUyk8IC4Egz62RmjYGLgBllG5hZuzIPBwPLkxhP2hjSvT33nJdH+1ZNMKB9qybcc16eLjKLSMolbfSRu+8xs6uBWUAOMMndl5nZaKDQ3WcA15rZYGAPsBkYlqx40o1qF0QkHZl7xdP86a2goMALCwtTHUZUd05fylPz11LiTo4ZQ3sewu+H5MW1noLWYhCRRDCzhe5eUF07VTQnyJ3Tl/Lku2sij0vcefLdNXyycTvvr9laq5oE1TOISF3ThHgJ8tT8tVG3z/t4c61rElTPICJ1TUkhQUpqeBouSE2C6hlEpK4pKSRIjkUry4gtSE2C6hlEpK4pKSTI0J5Ri7Hpc3jrWtckqJ5BROqakkKC/H5IHj/pdWikx5Bjxk96HcrUn/eudU2C6hlEpK5pSKqISBYIOiRVPQUREYlQnUIA0YrSgErbCg5rHbjQTEVpIpKOdPqoGhWL0qrSANhb5nGTRjlRrwFULEqrqq2ISCLo9FGCxCpKi2ZvhcexCs1UlCYi6UpJoRo1LUqrKFqhmYrSRCRdKSlUo6ZFaRVFKzRTUZqIpCslhWrEKkqLpuKHGavQTEVpIpKuNPqoGr8fkgdUHmkUbVvQ0Uel2zT6SETSjUYfiYhkAa2nUEHQuoBo7Qo/21ypV/DJxu3M+3hz5HV9Dm/N0uKtfPXtd6OKWu6Tw5K7BnLJhHcqtZ36897JfcMiIrWQFT2FoHUB0do1MNgbx0dkQLSXKzGISF1SnUIZQesCorWLJyFA9IQAlOs5iIiki6xICkHrAlQnICLZLiuSQtC6ANUJiEi2y4qkELQuIFq7BvHVrhHr5X0Obx3fjkVEkiArkkLQxWqitbv/R/lRF8+p+KXe5/DWtNynfEJpuU8On4w5M2pbXWQWkXSUFaOPRESyneoUkixaPcOzhWtUjyAiGU09hVqIVs8QixKDiKQD1SkkUbR6hlhUjyAimURJoRZUzyAi9ZWSQi2onkFE6islhVqIVs8Qi+oRRCSTKCnUQrR6hgd+nK96BBHJeEkdfWRmA4EHgRzgUXcfU+H5fYDJwHHAJuDH7v5pVftMh9FHIiKZJuWjj8wsB/gLMAg4BhhqZsdUaHYF8F93PwL4E3BvsuIREZHqJfP00QnAR+6+2t13AU8D51Rocw7wRPj+c8AAM4tztiEREamtZCaF9sDaMo+Lw9uitnH3PcBWYP8kxiQiIlVIZlKI9ou/4gWMIG0wsxFmVmhmhRs3bkxIcCIiUlkyk0IxcEiZxx2A9bHamFlDYF+gUgmwu4939wJ3L2jbtm2SwhURkWQmhQXAkWbWycwaAxcBMyq0mQFcFr5/ATDHM20yJhGReiTZQ1LPAB4gNCR1krvfbWajgUJ3n2FmucAUoDuhHsJF7r66mn1uBD6LI6w2wJdxvD6d6L2kp/r0XqB+vZ9sfi+HuXu1p1oybpbUeJlZYZCxuplA7yU91af3AvXr/ei9VE8VzSIiEqGkICIiEdmYFManOoAE0ntJT/XpvUD9ej96L9XIumsKIiISWzb2FEREJIasSQpmNsnMvjCzD1IdS7zM7BAze93MlpvZMjO7LtUx1ZaZ5ZrZe2a2OPxe7kp1TPEysxwzW2RmL6c6lniY2admttTMiswso6cmNrNWZvacma0I/3+TkXPam1nn8H+P0ttXZnZ9Qo+RLaePzKwvsB2Y7O5dUh1PPMysHdDO3d83sxbAQmCIu/87xaHVWHgCxGbuvt3MGgFvA9e5+7spDq3WzOxGoABo6e5npTqe2jKzT4ECd8/4cf1m9gTwlrs/Gi6mberuW1IdVzzCM1GvA3q6ezy1W+VkTU/B3d8kyhQamcjdN7j7++H724DlVJ5sMCN4yPbww0bhW8b+UjGzDsCZwKOpjkVCzKwl0BeYCODuuzI9IYQNAD5OZEKALEoK9ZWZdSRUET4/tZHUXvh0SxHwBfBPd8/Y90Kogv8WYG+qA0kAB141s4VmNiLVwcThe8BG4LHwab1HzaxZqoNKgIuApxK9UyWFDGZmzYHngevd/atUx1Nb7l7i7vmEJk08wcwy8vSemZ0FfOHuC1MdS4L0cfcehBbK+p/wKdhM1BDoATzi7t2Br4HbUhtSfMKnwAYDzyZ630oKGSp8/v15YKq7v5DqeBIh3KV/AxiY4lBqqw8wOHwu/mngFDN7MrUh1Z67rw///QL4G6GFszJRMVBcpgf6HKEkkckGAe+7++eJ3rGSQgYKX5ydCCx39/tTHU88zKytmbUK328CnAqsSG1UtePut7t7B3fvSKhrP8fdf5LisGrFzJqFBzEQPtVyGpCRI/fc/T/AWjPrHN40AMi4QRkVDCUJp44g1K3KCmb2FNAPaGNmxcBv3X1iaqOqtT7AT4Gl4XPxAHe4+yspjKm22gFPhEdSNACecfeMHspZTxwI/C28Om5D4K/u/o/UhhSXa4Cp4dMuq4HhKY6n1sysKfBD4BdJ2X+2DEkVEZHq6fSRiIhEKCmIiEiEkoKIiEQoKYiISISSgoiIRCgpSL1jZsPM7OAA7R43swuCbk9AXHeUud8xyIy94Vg+MbMrE3D8H5vZR5k+e6skl5KC1EfDgGqTQgrcUX2TqG5293HxHtzdpwE/i3c/Ur8pKUhaC/+iXmFmT5jZkvCc+E3Dzx1nZnPDE7bNMrN24V/4BYQKlYrMrImZjTSzBWb2gZmND1eEBz1+pWOEt79hZveG14L40MxOCm9vambPhGOdZmbzzazAzMYATcIxTQ3vPsfMJoTXkXg1XNFdXTwHmtnfLLT+xGIz+0GZz+jR8Hucamanmtk8M1tlZpk6PYWkgJKCZILOwHh37wp8BfwyPPfTQ8AF7n4cMAm4292fAwqBS9w93913AA+7+/HhdTSaAIHWOIh1jDJNGrr7CcD1wG/D234J/Dcc6++A4wDc/TZgRzimS8JtjwT+4u7HAluA8wOE9Wdgrrt3IzR/z7Lw9iOAB4GuwFHAxcCJwE3UvociWShrprmQjLbW3eeF7z8JXAv8A+gC/DP8wz8H2BDj9f3N7BagKdCa0BfpSwGO27maY5RORLgQ6Bi+fyKhL2fc/QMzW1LF/j9x99JpSsruoyqnAJeG918CbDWz/cL7WgpgZsuA19zdzWxpwP2KAEoKkhkqzsXigAHL3L3KZRXNLBf4P0IriK01s1FAbsDjVneMb8N/S/ju/6XAp6bKvL50H9WePgq4r71lHu9F/59LDej0kWSCQ+27NXWHElqycyXQtnS7mTUys2PDbbYBLcL3SxPAl+H1J2oyqqiqY8TyNvCjcPtjgLwyz+0On5KKx2vAVeH951hoVTGRhFFSkEywHLgsfCqmNaHFUnYR+oK/18wWA0XAD8LtHwfGhWeQ/RaYACwFpgMLgh60mmPE8n+EEskS4FZgCbA1/Nx4YEmZC821cR2h02FLCZ1yqi5JidSIZkmVtGah5UZfDl8kTnvhKcAbuftOMzuc0C/774cTTG329zih9/9cguLrB9zk7oEutkv20blGkcRqCrwePk1kwFW1TQhhW4HfmVmbeGsVzOzHhEZJ1ZflQiUJ1FMQEZEIXVMQEZEIJQUREYlQUhARkQglBRERiVBSEBGRCCUFERGJ+H+hTfzkwSpoOwAAAABJRU5ErkJggg==\n",
"text/plain": [
"