{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# TP Apprentissage supervisé: Classification / Discrimination\n", "\n", "Dans ce tp, on fait de la Classification / Discrimination, c'est-à-dire que l'on connaît les \"vrais\" labels de nos classes. \n", "\n", "On va utiliser les données Breast cancer dataset (classification).\n", "\n", "Une description de ces données est disponible à l'adresse https://scikit-learn.org/stable/datasets/index.html#breast-cancer-wisconsin-diagnostic-dataset. Jetez un coup d'oeil pour comprendre la problématique.\n", "\n", "Importez les libraries de ce matin: numpy et scikit datasets." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "from sklearn import datasets\n", "from matplotlib import pyplot as plt" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "breast_cancer = datasets.load_breast_cancer()" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "X = breast_cancer.data\n", "y = breast_cancer.target\n", "feature_names = breast_cancer.feature_names" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(569, 30) (569,)\n", "[0 0 0 0 0]\n", "['mean radius' 'mean texture' 'mean perimeter' 'mean area'\n", " 'mean smoothness' 'mean compactness' 'mean concavity'\n", " 'mean concave points' 'mean symmetry' 'mean fractal dimension'\n", " 'radius error' 'texture error' 'perimeter error' 'area error'\n", " 'smoothness error' 'compactness error' 'concavity error'\n", " 'concave points error' 'symmetry error' 'fractal dimension error'\n", " 'worst radius' 'worst texture' 'worst perimeter' 'worst area'\n", " 'worst smoothness' 'worst compactness' 'worst concavity'\n", " 'worst concave points' 'worst symmetry' 'worst fractal dimension']\n" ] } ], "source": [ "print(X.shape, y.shape)\n", "print(y[:5])\n", "print(feature_names)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([2.057e+01, 1.777e+01, 1.329e+02, 1.326e+03, 8.474e-02])" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X[1][:5]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Chargez les données depuis datasets.load_boston. Que renvoie cette fonction ? Chargez vos données dans des variables appelées X et y pour avoir, respectivement, les données et les labels." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Formatage du jeu de données\n", "Pour entraîner nos algorithmes, on va splitter notre jeu de données en 3 sous-jeux de données: \n", "- train\n", "- validation\n", "- test\n", "\n", "Pourquoi est-ce nécessaire?\n", "\n", "Pour cela, utilisez la fonction scikit-learn sklearn.model_selection.train_test_split. Importez cette méthode, appliquer là à nos données.\n", "\n", "On utilise 2 fois train_test_split, afin de séparer 2 fois l'ensemble: une fois entre train_validation d'une part, unee fois entre train et validation." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "from sklearn.model_selection import train_test_split" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "X_tv,X_test, y_tv,y_test = train_test_split(X,y,test_size=.2, random_state=42)\n", "X_train,X_validation,y_train,y_validation = train_test_split(X_tv,y_tv,test_size=.25,random_state=42)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# K-NNs\n", "On va lancer les k-nns sur ce dataset. Essayez K = 1, puis K = n (n est le nombre de samples). Observez dans $R^2$. Commentez." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "from sklearn.neighbors import KNeighborsClassifier \n", "from sklearn.metrics import confusion_matrix, accuracy_score" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1 0.9298245614035088\n", "[[40 4]\n", " [ 4 66]]\n", "4 0.9210526315789473\n", "[[40 4]\n", " [ 5 65]]\n", "7 0.9385964912280702\n", "[[40 4]\n", " [ 3 67]]\n", "10 0.9385964912280702\n", "[[40 4]\n", " [ 3 67]]\n", "13 0.9298245614035088\n", "[[39 5]\n", " [ 3 67]]\n", "16 0.9210526315789473\n", "[[39 5]\n", " [ 4 66]]\n", "19 0.9298245614035088\n", "[[39 5]\n", " [ 3 67]]\n" ] } ], "source": [ "# hyperparamter\n", "K_max = 20\n", "for K in range(1,K_max,3):\n", " # declare classifier with hyperparameters\n", " knn = KNeighborsClassifier(n_neighbors=K)\n", " # train (aka fit) the classifier on the train dataset\n", " knn.fit(X_train,y_train)\n", " # predict the validation dataset\n", " y_validation_hat = knn.predict(X_validation)\n", " # check the result\n", " print(K,accuracy_score(y_pred=y_validation_hat,y_true=y_validation))\n", " print(confusion_matrix(y_pred=y_validation_hat,y_true=y_validation))\n", " # Now, adjust hyperparamaeters" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Comment choisir K? Essayez différents K, regardez les résultats.\n", "\n", "Notre objectif est de minimiseer le taux d'erreur. On va tracer 1 - accuracy en fonction de K, et choisir le K le plus faibble:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[]" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAX0AAAD8CAYAAACb4nSYAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvOIA7rQAAIABJREFUeJzt3Xl8XNV99/HPTzPSyNbIRpvFYsuWQTY4ISxRDAmEsAQwNAmU8MpjkjYkpSFtQ9KSJi00KVDnSZMnTdOkqZ+m0FISniaGLC1OQwEn2AkhECzjBWyQvILlVba8SV60/Z4/5mo82qwZW9Jo7nzfr9e8fO+558785mr8mzPnnnuuuTsiIpIfCrIdgIiIjB0lfRGRPKKkLyKSR5T0RUTyiJK+iEgeUdIXEckjSvoiInlESV9EJI8o6YuI5JFoOpXMbB7wLSAC/Ku7f7Xf9unAw0AV0Ar8nrs3B9u6gVeCqm+6+wdO9FqVlZU+Y8aMTN6DiEjeW7FixR53rxqung03DYOZRYAm4FqgGVgO3Obu61Lq/BD4b3f/rpldDXzc3X8/2Nbm7vF0A6+vr/eGhoZ0q4uICGBmK9y9frh66XTvzAU2uPsmd+8AFgE39aszB/hFsLx0kO0iIjIOpJP0zwK2pqw3B2WpVgMfDJZ/Fyg1s4pgvdjMGszsRTO7ebAXMLM7gzoNLS0tGYQvIiKZSCfp2yBl/fuEPge8x8xWAu8BtgFdwbaa4CfHh4FvmtnZA57M/UF3r3f3+qqqYbukRETkJKVzIrcZmJayPhXYnlrB3bcDtwCYWRz4oLsfSNmGu28ys2XARcDGU45cREQylk5LfzlQZ2a1ZlYEzAcWp1Yws0oz632ue0mM5MHMysws1lsHuAxYh4iIZMWwSd/du4C7gKeB14DH3X2tmS0ws97hl1cCjWbWBFQDXw7KzwMazGw1iRO8X00d9SMiImNr2CGbY01DNkVEMpfukM20Ls7KJR1dPfzXym3c+vapbNrTxuLVO8Cdq8+rZueBI1w4rYzTJxeP+Ou+uu0Az6zdCcAN55/BeWdMGvHXEBE5VaFL+g89t4m/e7qRaMT4ZVMLT6xKnHNe8tpuXttxkE+8u5Yv/M6cEX/drz/TyLLGxHDTTXva+acPXzziryEicqpCl/T3H+4AYPehYzTuPMRVs6s4ffIEfvDSmwA07moblddt2nmImy88k237j7Cn7diovIaIyKkK3YRrRdHEWzp8rItNLe3Mqi5lVvXxWSDW7zo04q956Ggn2w8cpa66lIqSGHvbOkb8NURERkLokn5hJPGW1u9uo6O7h7rqUuqmlCa37zhwlINHO0f0NdfvTvx6mFVdSnm8iNZ2JX0RGZ9C073T1d3Dlr2H2XngKAAvv7kPgFnVcU6flDhxawbusKyxhfNOT3wRVMRjTCyKsLX1cPK5CiMFTK+YyMGjXUyeUAjA0c5uALp7nFi0gGikgOZ9hznS0c0LG/cmX+uV5v3sO9zBgcOdlBZHKSgY7ILm4w4c6WRScbTPa/U6dLSTiUVRIsM8h4hIukKT9FsPd/Deb/wyub7rYKJf/ZwpcSYURqiMx5hz5iR+1dTCZ36wMllv8oRCLqkt55l1u/o8321za/hhw1aWfu5KppVP5M8WraKzu4fXdx7iQ/XTuHJ2FTctfD5ZPx6LMq1sIuUlRfQ4XLDgGT5//Ww+ddU5Q8a8eU877/3GL/nIJTU83rCV5//yairiMSAxCumKry3lM9fU8fHLakfkGImIhCbpl08sGlA2rXwCE4sSb/HxT15K2cQiXt95iL3tiS+Ehi37eOQ3W1jW2MI7Z1bwkUtrcIc//+Fqfryima4eZ3XzfqaVT6ThjX0cPNJJR3cPDW+0UlaSaJV/9ZbziRdHmVFRQkGBJZM2wFOv7jxh0l+1dR/dPc6il7bS0d3Duh0HeXddYu6hTXva2He4kxVv7FPSF5ERE5qkH40UcNrEQvYfPt5fPyulL39mVeJk7jvPrkiWTSubyCO/2UJHdw+X11XyvredCcDCpRt4fWfihG/Trjb2tXf0GZGzflcb0ysmUhqL8r/eMQ2z490vFSXHv3zKSwZ+EaVqCkYSdXT3JNd7k37vtvWjNNpIRPJTqE7kVvRLsnXVpUPUTDhnyvFRPbNS6qYur991iKZ+I352HjzKijf2U1cd75PwgT4t/Vj0xIe3/0ii1PXe5U172ugMvhRERE5VyJJ+rM966lDNwZTEokwtmzCgbupy065DNO0e2Np+bcfBPl8OvVJb9/sOn3gUz/p+z5v65dK73NntvLG3/YTPIyKSrtB07wBUxPu29AdLyv3Nqi5lT9sxppVNTJadE3QLTS2bwKY97XxzSRPxWGIUTWlxlOZ9R4DBf0mUTTw+AueVbQe4eeHzyZE/qT76zhm82XqYaeUT2Np6hKllE1jTfIB53/wVAFv2tjO1bALN+47w8UeWU1I0+J/qM9fUceP5ZyTXl76+m2fW7eIrt5zPl3+2jufW7wES1y984t0zeei5TXR09f3lYGb8xfWzuercKcMeLxHJbaFK+r2t7GvOnUJddSnnnj580v/Dd9dy1eyqPkMr311Xyccvm8H73nYmD/96M109PVxSW8HEogjVk4v59fo97D50jHlvPX3A80UjBfzVjefyP6/uZOWb+1m1dT9Xzq7q09Xz0uZWvrGkCXf4kyvPoWnXIW48/wz+/fnNdPckJsCbUVHCRy6t4alXdw55he8LG/fyxKptfZL+T1Zu46ert/MX18/mP377JqdPLubsqjhL1u3ib366lj1tHVw3p5rUXqmljS0sbdytpC+SB0KV9Hv79M+ZEueeG85Na593nV3Ju86u7FNWEoty//vfAsDbp5cN2Oeq2SdOjndecTZHOnpY+eZ+IgXGv93+jj5j7e9+bBX/uXIbAO+YUc5tc2uSy/31ntgdzCcfbRhworf3XMAvm1o43NHNHZfX8pFLplP/v3/OnrZjnD6pmAc/2ncivqv/fpmuIhbJE6Hq048XJ77DunqyP110b1dT2cSiARdX1QXnDIoiBcyomDhg33TNqi5ly972ZPdRV3cPm1oS/f//vWZHsk7i33if1+4Ta0lRchiriIRbqJJ+UTAFw7GugX3oY633V0f/EUVwfCjpzKoSopGT/xPUVZfS4yQT/Za9h5PDP3/+2q4+r3U8+Q/s8tJ8QSL5I1TdO0XRCMCAE5XZ0DvxW/+TywCzg3MNww0pHc7sYP9/+dVG6qbE2bQnkfwnFkU43NFN9aQYk4MTy73JfvZgI47iRby0pYMnVm3j+recTnFh5JTiEpHxK1Qt/cvPSfTN33Lx1CxHAm85czIAf/SeswdsO+u0CZx7einvrqscsC0TtZUlnDm5mCdWbefrzzTxk5e3MaU0xoeDcwSXnXP8+S+ZWU5lPMY7ageeN6gsSUwS96eLVvGdX+qe9SJhptsl5rieHqc75W8YMaOgwOjs7iFaYAMuHhvMI89v5oGfJm5dfMfltfz1+0b+JjMiMrry9naJ+aagwChgYGIvzOBcQepVxMWFofrxJyL96H+49DnZ3No+svcaEJHxJa2kb2bzzKzRzDaY2T2DbJ9uZr8wszVmtszMpqZsu93M1geP20cyeBkZqS391vZjHOnI/ugnERkdwyZ9M4sAC4EbgDnAbWbWv9P368D33P1twALgK8G+5cD9wCXAXOB+Mxt4tZNkVeoIo6fX7uK8+55i98GjWYxIREZLOi39ucAGd9/k7h3AIuCmfnXmAL8IlpembL8eWOLure6+D1gCzDv1sGUkVcZj/ORP3sW1c6qTZTsOKOmLhFE6Sf8sYGvKenNQlmo18MFg+XeBUjOrSHNfGQcurinjrNMmJNeHmyFURHJTOkl/sDF//cd5fg54j5mtBN4DbAO60twXM7vTzBrMrKGlpSWNkGQ0lPc5oaukLxJG6ST9ZmBayvpUYHtqBXff7u63uPtFwBeCsgPp7BvUfdDd6929vqpq6AnGZHSlDtfUtAwi4ZRO0l8O1JlZrZkVAfOBxakVzKzSzHqf617g4WD5aeA6MysLTuBeF5TJOHSs8/j0FY81bOVvn3wti9GIyGgYNum7exdwF4lk/RrwuLuvNbMFZvaBoNqVQKOZNQHVwJeDfVuBL5H44lgOLAjKZBz66Dtn8HuX1lBaHGXD7jb+9blNg94ARkRyl6ZhkAFu/NZzrNtxEICffeby5DxCIjJ+pTsNg67IlQFKYsdn2ex/kxYRyW1K+jLA/sPHp2JIvVm7iOQ+JX0ZYG8wXHNCYYT/u2wj67YnunrcnZ+t2UFnd/bvVyAiJ0dJXwb41FXnAHDzRYnr6B746VoAGt7Yx6e+/zJPvboza7GJyKnR1MoywB2X13LH5bW4O4c7uvhlUwvuzuvByd3GnYd4/wVZDlJETopa+jIkM+OCqaex/3Ane9o6aApO6qqfXyR3KenLCfXez3f9rkPJZL9+t0b0iOQqde/ICdVVxwF4+c19yWT/xt523tx7mMLo8LdiHA8mFkaTN4jv7klclxIpyI3YRUaakr6cUFU8RkVJEV9/pgmAubXlvLS5lSv+bmmWI0tfpMD4xWffw4zKEj7/o9UcONzJv33sHdkOSyQrlPTlhMyMh26vp2nnIaKRAt573hSWNbbkzPQMe9s7+LunG1ndvJ8ZlSW8tLmVA4c7cfe0bhovEjZK+jKsi2vKuLjm+A3Peody5oJjXd18Y0kT63e10X6si+Z9RwDYefAoZ0yeMMzeIuGjE7kSarFohBkVE2nadYgNKSegmzS9hOQpJX0JvVnVpazf3dZnqOl6DTuVPKXuHQm9uupSnlq7k2/+fD1F0QLisSgPPbcp61cWXzy9jL+68bysxiD5R0lfQu93zj+D1Vv309XTw61vn0o8FmVZ0+6sxtS87wgP/3ozn7tuNkVR/eCWsaOkL6E3+/RSvvsHc/uUfeKKmVmKJuG/Vm7jzx5bxeY97ckL4ETGgpoYIlnQe9GbprSQsaakL5IFZ1fFKTCdUJaxp+4dkSwoLowwvaKEZU0tVMRjw9a/vK6SXQeO8pYzJyenlBA5GUr6Ilkyd0Y5jzVsZU3zgWHrXlRzGqu27uczV9dx97WzxiA6CSslfZEs+cot5/OXN5w7bL2/fuJVfrZmBwCv7zw42mFJyCnpi2RJQYFRXlI0bL05Z0xKJn3dqF5OVVoncs1snpk1mtkGM7tnkO01ZrbUzFaa2RozuzEon2FmR8xsVfD4zki/AZGwm1V9fEjnlr3tOTPZnYxPw7b0zSwCLASuBZqB5Wa22N3XpVT7IvC4u/+zmc0BngRmBNs2uvuFIxu2SP6YFQzvBOhxWLV1P3VT4pTEohQXRrIYmeSidLp35gIb3H0TgJktAm4CUpO+A5OC5cnA9pEMUiSfTSubSElRhDlnTmL5ln3Mf/BFACYVR3nh3msoiamXVtKXzqflLGBrynozcEm/Og8Az5jZp4ES4L0p22rNbCVwEPiiuz/X/wXM7E7gToCampq0gxfJBwUFxqN/eAlnnTaB5VtaaW3vYMPuNr73whs07TrERSnTXosMJ50+/cHuNOH91m8DHnH3qcCNwKNmVgDsAGrc/SLgs8D3zWxSv31x9wfdvd7d66uqqjJ7ByJ54OKaMqonFfO+t53JR985gz+4rBbQiV3JXDpJvxmYlrI+lYHdN3cAjwO4+wtAMVDp7sfcfW9QvgLYCGiQscgpmlY+kVi0QNM4SMbSSfrLgTozqzWzImA+sLhfnTeBawDM7DwSSb/FzKqCE8GY2UygDtg0UsGL5KtIgXHOlDhNu9XSl8wM26fv7l1mdhfwNBABHnb3tWa2AGhw98XAnwMPmdndJLp+PububmZXAAvMrAvoBv7I3VtH7d2I5JFZ1aU89epOPvzQiwO2TSyK8LVbL0jrOgDJL2md9nf3J0kMw0wtuy9leR1w2SD7/Rj48SnGKCKD+ODFU9m2/wid3T19yo919fCbjXt5fsMe3n/BmVmKTsYrjfUSyVGX11VyeV3lgPKjnd3Mue8pzeApg9LUyiIhU1wYYUZFiW7+LoNS0hcJobrqOE271dKXgZT0RUJoVnUpm1raWbJuV7ZDkXFGSV8khC6enrhK9xPfa6DtWFeWo5HxRElfJISumj2FL/7OeQDsOXQsy9HIeKKkLxJS50xJzM65t70jy5HIeKKkLxJSFSWJe+/ubVNLX45T0hcJqYp44mrcVrX0JYWSvkhI9U7BoO4dSaWkLxJSxYUR4rEoe9uU9OU4JX2RECsvKWJvu/r05TglfZEQKy8pUp++9KGkLxJilfEi9qh7R1Jolk2RECsvKeK59Xv42L+/NGSdGRUl3P/+OZgNdmdUCRslfZEQm/fW02nc1ca+Ibp49rR1sKyxhbuvncXkCYVjHJ1kg5K+SIhdfW41V59bPeT2/1zZzN2Praa1vUNJP0+oT18kj5Xrqt28o6QvkscqdAFX3lHSF8ljvVM16AKu/KGkL5LHeqdqaNUFXHkjraRvZvPMrNHMNpjZPYNsrzGzpWa20szWmNmNKdvuDfZrNLPrRzJ4ETk1sWiE0lhUY/nzyLCjd8wsAiwErgWageVmttjd16VU+yLwuLv/s5nNAZ4EZgTL84G3AGcCPzezWe7ePdJvREROTkVcV+3mk3Ra+nOBDe6+yd07gEXATf3qODApWJ4MbA+WbwIWufsxd98MbAieT0TGCU3VkF/SSfpnAVtT1puDslQPAL9nZs0kWvmfzmBfEcmiiniMHQeO4O7ZDkXGQDpJf7Brs/t/Om4DHnH3qcCNwKNmVpDmvpjZnWbWYGYNLS0taYQkIiOlqjTGxpZ2PvnoimyHImMgnaTfDExLWZ/K8e6bXncAjwO4+wtAMVCZ5r64+4PuXu/u9VVVVelHLyKn7JNXzATglW0HshyJjIV0kv5yoM7Mas2siMSJ2cX96rwJXANgZueRSPotQb35ZhYzs1qgDhh65icRGXPTK0r45BUzaW3vUBdPHhh29I67d5nZXcDTQAR42N3XmtkCoMHdFwN/DjxkZneT6L75mCc+PWvN7HFgHdAFfEojd0TGn4p4Ece6emjv6CYe05RcYZbWX9fdnyRxgja17L6U5XXAZUPs+2Xgy6cQo4iMst45eFrbOpT0Q05X5IpIcjqGPboyN/SU9EUkOfFaq67MDT0lfRGhIh5MsayWfugp6YuIpljOI0r6IkJxYYSSooimWM4DSvoiAkB5vIifvNzMHt1FK9SU9EUEgBkVJew73Mk3f96U7VBkFCnpiwgAD/5+PdEC4+CRrmyHIqNISV9EAJhQFOGcKXGOduqi+TBT0heRpFhhhKNdPdkOQ0aRkr6IJMWiBRxTSz/UlPRFJKlYLf3QU9IXkSS19MNPSV9EkooLIxxTSz/UlPRFJKlYLf3QU9IXkaRYYYH69ENOSV9EkoqjEY3TDzklfRFJihUWqE8/5JT0RSSpOBqhu8fp7FbiDyslfRFJKi6MAKi1H2JK+iKSFCtMpAT164dXWknfzOaZWaOZbTCzewbZ/g9mtip4NJnZ/pRt3SnbFo9k8CIysoqjaumHXXS4CmYWARYC1wLNwHIzW+zu63rruPvdKfU/DVyU8hRH3P3CkQtZREaLWvrhl05Lfy6wwd03uXsHsAi46QT1bwN+MBLBicjYigUtfSX98Eon6Z8FbE1Zbw7KBjCz6UAt8GxKcbGZNZjZi2Z280lHKiKjrjho6at7J7yG7d4BbJAyH6LufOBH7p7aTKhx9+1mNhN41sxecfeNfV7A7E7gToCampo0QhKR0aCWfvil09JvBqalrE8Ftg9Rdz79unbcfXvw7yZgGX37+3vrPOju9e5eX1VVlUZIIjIa1NIPv3SS/nKgzsxqzayIRGIfMArHzGYDZcALKWVlZhYLliuBy4B1/fcVkfEhOU5fLf3QGrZ7x927zOwu4GkgAjzs7mvNbAHQ4O69XwC3AYvcPbXr5zzgX8ysh8QXzFdTR/2IyPgSi6qlH3bp9Onj7k8CT/Yru6/f+gOD7Pcb4PxTiE9ExlBvS199+uGlK3JFJKm3pX+0Uy39sFLSF5Gk43PvqKUfVkr6IpLU29L/2ydfZ932g3zjmUbNuBkyafXpi0h+iEYKuGJWFb9qauHGf3wOgPPOmMQN55+R5chkpKilLyJ9fO8P5nLWaROS673z8Ug46K8pIgPMqo4nlw93qH8/TJT0RWSAWdWlyeVDR7uyGImMNCV9ERmgLiXptynph4qSvogMcMHUycnlQ8eU9MNESV9EBqirLuXFe68hHoty6GhntsOREaSkLyKDOn1yMaXFUXXvhIySvogMKdHSV9IPEyV9ERlSvDhKm/r0Q0VJX0SGVFpcqBO5IaOkLyJDKtWJ3NBR0heRIcVjOpEbNkr6IjKkUvXph46SvogMKV4c5XBHN12aXjk0lPRFZEjxWGL29W/9Yn2WI5GRoqQvIkO6qOY0AL797AbdNzcklPRFZEhvn17OV245H4DW9o4sRyMjQUlfRE6ooqQIgL1tSvphkFbSN7N5ZtZoZhvM7J5Btv+Dma0KHk1mtj9l2+1mtj543D6SwYvI6KuIB0m//ViWI5GRMOw9cs0sAiwErgWageVmttjd1/XWcfe7U+p/GrgoWC4H7gfqAQdWBPvuG9F3ISKjpqIkBqilHxbptPTnAhvcfZO7dwCLgJtOUP824AfB8vXAEndvDRL9EmDeqQQsImOrPGjpq08/HNJJ+mcBW1PWm4OyAcxsOlALPJvpviIyPpXGohRFCtij7p1QSCfp2yBlPkTd+cCP3L13bFda+5rZnWbWYGYNLS0taYQkImPFzCgvKaJV3TuhkE7SbwampaxPBbYPUXc+x7t20t7X3R9093p3r6+qqkojJBEZSxXxIvaqeycU0kn6y4E6M6s1syISiX1x/0pmNhsoA15IKX4auM7MysysDLguKBORHFJeoqQfFsMmfXfvAu4ikaxfAx5397VmtsDMPpBS9TZgkbt7yr6twJdIfHEsBxYEZSKSQyrjMVZv3c/9T7ya7VDkFFlKjh4X6uvrvaGhIdthiEiKNc37+cA/Pc+Mioks+/xV2Q5HBmFmK9y9frh6uiJXRIb1tqmn8bF3zVAXTwgo6YtIWspLijh0tItjXZp4LZcp6YtIWnqnY9jXrtsn5jIlfRFJS+/Ea4++uIXGnYeyHI2cLCV9EUlLRTwxB8/CpRt5/z/9OsvRyMlS0heRtJQHLX2Aji7dPjFXKemLSFoqg9k2AWZUTMxiJHIqlPRFJC2TJhyfiX16RUkWI5FToaQvImkxOz5/YmFEqSNX6S8nIhnr7Faffq5S0heRtDV88b3Mqo7rRG4OU9IXkbRVxmNUxmNq6ecwJX0RyUhhpEBJP4cp6YtIRoqiBXR0j6/ZeSV9SvoikpEitfRzmpK+iGSkMGJK+jlMSV9EMlIYKaBTo3dylpK+iGSkMFpAh1r6OUtJX0QyUhQp0Dj9HKakLyIZKYoW0KnROzlLSV9EMqITubktraRvZvPMrNHMNpjZPUPU+ZCZrTOztWb2/ZTybjNbFTwWj1TgIpIdhZECunqcnh619nNRdLgKZhYBFgLXAs3AcjNb7O7rUurUAfcCl7n7PjObkvIUR9z9whGOW0SypHeGzc6eHmIFkSxHI5lKp6U/F9jg7pvcvQNYBNzUr84ngIXuvg/A3XePbJgiMl4UBUlfJ3NzUzpJ/yxga8p6c1CWahYwy8yeN7MXzWxeyrZiM2sIym8+xXhFJMsKI4l59XUyNzcN270D2CBl/f/aUaAOuBKYCjxnZm919/1AjbtvN7OZwLNm9oq7b+zzAmZ3AncC1NTUZPgWRGQsFUaD7h2dzM1J6bT0m4FpKetTge2D1HnC3TvdfTPQSOJLAHffHvy7CVgGXNT/Bdz9QXevd/f6qqqqjN+EiIwdde/ktnSS/nKgzsxqzawImA/0H4XzX8BVAGZWSaK7Z5OZlZlZLKX8MmAdIpKzitTSz2nDdu+4e5eZ3QU8DUSAh919rZktABrcfXGw7TozWwd0A593971m9i7gX8ysh8QXzFdTR/2ISO5Jjt5Rn35OSqdPH3d/EniyX9l9KcsOfDZ4pNb5DXD+qYcpIuPF8aSvln4u0hW5IpKR3tE7x9Snn5OU9EUkI0Vq6ec0JX0RyYiGbOY2JX0RyYha+rlNSV9EMlKYHKev0Tu5SElfRDJSFO2dhkEt/VykpC8iGdGQzdympC8iGSnUNAw5TUlfRDKiln5uU9IXkYz0zr3ToWkYcpKSvohkpHfI5us7DpKYgUVyiZK+iGSkMGKYwQ9XNPPTNTuyHY5kSElfRDISjRTwkz9+FwBrtu7PcjSSKSV9EcnYRTVlvOXMSTTtbst2KJIhJX0ROSmzqktZv+tQtsOQDCnpi8hJqauOs+PAUQ4e7cx2KJKBtG6iIiLS36wppQC8/9u/To7okVNz7hmT+PZtA24jPqKU9EXkpLzz7Ao+VD+VtmNd2Q4lNKaVTRj111DSF5GTUhKL8rVbL8h2GJIh/SYTEckjSvoiInlESV9EJI+klfTNbJ6ZNZrZBjO7Z4g6HzKzdWa21sy+n1J+u5mtDx63j1TgIiKSuWFP5JpZBFgIXAs0A8vNbLG7r0upUwfcC1zm7vvMbEpQXg7cD9QDDqwI9t038m9FRESGk05Lfy6wwd03uXsHsAi4qV+dTwALe5O5u+8Oyq8Hlrh7a7BtCTBvZEIXEZFMpZP0zwK2pqw3B2WpZgGzzOx5M3vRzOZlsC9mdqeZNZhZQ0tLS/rRi4hIRtJJ+jZIWf9JtKNAHXAlcBvwr2Z2Wpr74u4Punu9u9dXVVWlEZKIiJyMdC7OagampaxPBbYPUudFd+8ENptZI4kvgWYSXwSp+y470YutWLFij5m9kUZcg6kE9pzkvtmimEdfrsULinmshCnm6ensbMPd+cbMokATcA2wDVgOfNjd16bUmQfc5u63m1klsBK4kODkLXBxUPVl4O3u3ppOcJkyswZ3rx+N5x4tinn05Vq8oJjHSj7GPGxL3927zOwu4GkgAjzs7mvNbAHQ4O6Lg23Xmdk6oBv4vLvvDQL8EokvCoAFo5XwRURkeGnNvePuTwJP9iu7L2XVJd+hAAAEhUlEQVTZgc8Gj/77Pgw8fGphiojISAjbFbkPZjuAk6CYR1+uxQuKeazkXczD9umLiEh4hK2lLyIiJxCKpJ/O3EDjgZltMbNXzGyVmTUEZeVmtiSYm2iJmZVlOcaHzWy3mb2aUjZojJbwj8FxX2NmFw/9zGMe8wNmti041qvM7MaUbfcGMTea2fVZinmamS01s9eC+ar+NCgfl8f6BPGO2+NsZsVm9pKZrQ5i/pugvNbMfhsc48fMrCgojwXrG4LtM8ZRzI+Y2eaU43xhUJ7558Ldc/pBYkTRRmAmUASsBuZkO64hYt0CVPYr+xpwT7B8D/B/shzjFSSG2L46XIzAjcD/kLgI71Lgt+Mo5geAzw1Sd07wGYkBtcFnJ5KFmM8ALg6WS0kMi54zXo/1CeIdt8c5OFbxYLkQ+G1w7B4H5gfl3wH+OFj+E+A7wfJ84LEsfC6GivkR4NZB6mf8uQhDSz+duYHGs5uA7wbL3wVuzmIsuPuvgP7DaoeK8Sbge57wInCamZ0xNpEeN0TMQ7kJWOTux9x9M7CBxGdoTLn7Dnd/OVg+BLxGYoqScXmsTxDvULJ+nINj1RasFgYPB64GfhSU9z/Gvcf+R8A1ZjbYrAKj5gQxDyXjz0UYkn5a8/uMEw48Y2YrzOzOoKza3XdA4j8WMCVr0Q1tqBjH+7G/K/jJ+3BKt9m4iznoRriIRKtu3B/rfvHCOD7OZhYxs1XAbhITPm4E9rt77419U+NKxhxsPwBUjG3EA2N2997j/OXgOP+DmcX6xxwY9jiHIemnNb/POHGZu18M3AB8ysyuyHZAp2g8H/t/Bs4mcWX4DuDvg/JxFbOZxYEfA3/m7gdPVHWQsjGPe5B4x/Vxdvdud7+QxBQwc4HzBqsW/DsuYzazt5KYuv5c4B1AOfCXQfWMYw5D0k9nbqBxwd23B//uBv6TxIdwV+/PseDf3UM/Q9YMFeO4Pfbuviv4z9MDPMTxroVxE7OZFZJIoP/h7j8JisftsR4s3lw4zgDuvp/EvF+XkugC6b0wNTWuZMzB9smk32044lJinhd0r7m7HwP+nVM4zmFI+suBuuCMfBGJEzCLsxzTAGZWYmalvcvAdcCrJGLtvaPY7cAT2YnwhIaKcTHw0WAEwaXAgd6uiWzr16/5uySONSRinh+M1KglMTHgS1mIz4B/A15z92+kbBqXx3qoeMfzcTazKkvM9ouZTQDeS+JcxFLg1qBa/2Pce+xvBZ714GzpWBki5tdTGgJG4hxE6nHO7HMx1menR+NB4gx2E4n+ui9kO54hYpxJYjTDamBtb5wk+gx/AawP/i3Pcpw/IPEzvZNEK+KOoWIk8dNyYXDcXwHqx1HMjwYxrQn+Y5yRUv8LQcyNwA1ZivlyEj/D1wCrgseN4/VYnyDecXucgbeRmPxxTZAk7wvKZ5L4AtoA/BCIBeXFwfqGYPvMcRTzs8FxfhX4fxwf4ZPx50JX5IqI5JEwdO+IiEialPRFRPKIkr6ISB5R0hcRySNK+iIieURJX0Qkjyjpi4jkESV9EZE88v8B1Sg3Y6MqafQAAAAASUVORK5CYII=\n", "text/plain": [ "