{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Uczenie maszynowe UMZ 2019/2020\n",
"### 21 kwietnia 2020\n",
"# 6. Naiwny klasyfikator bayesowski"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"* Naiwny klasyfikator bayesowski jest algorytmem dla problemu klasyfikacji wieloklasowej.\n",
"* Naszym celem jest znalezienie funkcji uczącej $f \\colon x \\mapsto y$, gdzie $y$ oznacza jedną ze zdefiniowanych wcześniej klas.\n",
"* Klasyfikacja probabilistyczna polega na wskazaniu klasy o najwyższym prawdopodobieństwie:\n",
"$$ \\hat{y} = \\mathop{\\arg \\max}_y P( y \\,|\\, x ) $$\n",
"* Naiwny klasyfikator bayesowski należy do rodziny klasyfikatorów probabilistycznych"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"\n",
"**Thomas Bayes** (wymowa: /beɪz/) (1702–1761) – angielski matematyk i duchowny"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"### Twierdzenie Bayesa – wzór ogólny\n",
"\n",
"$$ P( Y \\,|\\, X ) = \\frac{ P( X \\,|\\, Y ) \\cdot P( Y ) }{ P ( X ) } $$"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "notes"
}
},
"source": [
"Twierdzenie Bayesa opisuje związek między prawdopodobieństwami warunkowymi dwóch zdarzeń warunkujących się nawzajem."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"### Twierdzenie Bayesa\n",
"(po zastosowaniu wzoru na prawdopodobieństwo całkowite)\n",
"\n",
"$$ \\underbrace{P( y_k \\,|\\, x )}_\\textrm{ prawd. a posteriori } = \\frac{ \\overbrace{ P( x \\,|\\, y_k )}^\\textrm{ model klasy } \\cdot \\overbrace{P( y_k )}^\\textrm{ prawd. a priori } }{ \\underbrace{\\sum_{i} P( x \\,|\\, y_i ) \\, P( y_i )}_\\textrm{wyrażenie normalizacyjne} } $$"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "notes"
}
},
"source": [
" * W tym przypadku „zdarzenie $x$” oznacza, że cechy wejściowe danej obserwacji przyjmują wartości opisane wektorem $x$.\n",
" * „Zdarzenie $y_k$” oznacza, że dana obserwacja należy do klasy $y_k$.\n",
" * **Model klasy** $y_k$ opisuje rozkład prawdopodobieństwa cech obserwacji należących do tej klasy.\n",
" * **Prawdopodobieństwo *a priori*** to prawdopodobienstwo, że losowa obserwacja należy do klasy $y_k$.\n",
" * **Prawdopodobieństwo *a posteriori*** to prawdopodobieństwo, którego szukamy: że obserwacja opisana wektorem cech $x$ należy do klasy $y_k$."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"### Rola wyrażenia normalizacyjnego w twierdzeniu Bayesa\n",
"\n",
" * Wartość wyrażenia normalizacyjnego nie wpływa na wynik klasyfikacji.\n",
"\n",
"_Przykład_: obserwacja nietypowa ma małe prawdopodobieństwo względem dowolnej klasy, wyrażenie normalizacyjne sprawia, że to prawdopodobieństwo staje się porównywalne z prawdopodobieństwami typowych obserwacji, ale nie wpływa na klasyfikację!"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"### Klasyfikatory dyskryminatywne a generatywne\n",
"\n",
"* Klasyfikatory generatywne tworzą model rozkładu prawdopodobieństwa dla każdej z klas.\n",
"* Klasyfikatory dyskryminatywne wyznaczają granicę klas (_decision boundary_) bezpośrednio.\n",
"* Naiwny klasyfikator baywsowski jest klasyfikatorem generatywnym (ponieważ wyznacza $P( x \\,|\\, y )$).\n",
"* Wszystkie klasyfikatory generatywne są probabilistyczne, ale nie na odwrót.\n",
"* Regresja logistyczna jest przykładem klasyfikatora dyskryminatywnego."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"### Założenie niezależności dla naiwnego klasyfikatora bayesowskiego\n",
"\n",
"* Naiwny klasyfikator bayesowski jest _naiwny_, ponieważ zakłada, że poszczególne cechy są niezależne od siebie:\n",
"$$ P( x_1, \\ldots, x_n \\,|\\, y ) \\,=\\, \\prod_{i=1}^n P( x_i \\,|\\, x_1, \\ldots, x_{i-1}, y ) \\,=\\, \\prod_{i=1}^n P( x_i \\,|\\, y ) $$\n",
"* To założenie jest bardzo przydatne ze względów obliczeniowych, ponieważ bardzo często mamy do czynienia z ogromną liczbą cech (bitmapy, słowniki itp.)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Naiwny klasyfikator bayesowski – przykład"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"slideshow": {
"slide_type": "notes"
}
},
"outputs": [],
"source": [
"# Przydtne importy\n",
"\n",
"import ipywidgets as widgets\n",
"import matplotlib.pyplot as plt\n",
"import numpy as np\n",
"import pandas\n",
"\n",
"%matplotlib inline"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"outputs": [],
"source": [
"# Wczytanie danych (gatunki kosaćców)\n",
"\n",
"data_iris = pandas.read_csv('iris.csv')\n",
"data_iris_setosa = pandas.DataFrame()\n",
"data_iris_setosa['dł. płatka'] = data_iris['pl'] # \"pl\" oznacza \"petal length\"\n",
"data_iris_setosa['szer. płatka'] = data_iris['pw'] # \"pw\" oznacza \"petal width\"\n",
"data_iris_setosa['Iris setosa?'] = data_iris['Gatunek'].apply(lambda x: 1 if x=='Iris-setosa' else 0)\n",
"\n",
"m, n_plus_1 = data_iris_setosa.values.shape\n",
"n = n_plus_1 - 1\n",
"Xn = data_iris_setosa.values[:, 0:n].reshape(m, n)\n",
"\n",
"X = np.matrix(np.concatenate((np.ones((m, 1)), Xn), axis=1)).reshape(m, n_plus_1)\n",
"Y = np.matrix(data_iris_setosa.values[:, 2]).reshape(m, 1)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"liczba przykładów: {0: 100, 1: 50}\n",
"prior probability: {0: 0.6666666666666666, 1: 0.3333333333333333}\n"
]
}
],
"source": [
"classes = [0, 1]\n",
"count = [sum(1 if y == c else 0 for y in Y.T.tolist()[0]) for c in classes]\n",
"prior_prob = [float(count[c]) / float(Y.shape[0]) for c in classes]\n",
"\n",
"print('liczba przykładów: ', {c: count[c] for c in classes})\n",
"print('prior probability:', {c: prior_prob[c] for c in classes})"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"slideshow": {
"slide_type": "notes"
}
},
"outputs": [],
"source": [
"# Wykres danych (wersja macierzowa)\n",
"def plot_data_for_classification(X, Y, xlabel, ylabel): \n",
" fig = plt.figure(figsize=(16*.6, 9*.6))\n",
" ax = fig.add_subplot(111)\n",
" fig.subplots_adjust(left=0.1, right=0.9, bottom=0.1, top=0.9)\n",
" X = X.tolist()\n",
" Y = Y.tolist()\n",
" X1n = [x[1] for x, y in zip(X, Y) if y[0] == 0]\n",
" X1p = [x[1] for x, y in zip(X, Y) if y[0] == 1]\n",
" X2n = [x[2] for x, y in zip(X, Y) if y[0] == 0]\n",
" X2p = [x[2] for x, y in zip(X, Y) if y[0] == 1]\n",
" ax.scatter(X1n, X2n, c='r', marker='x', s=50, label='Dane')\n",
" ax.scatter(X1p, X2p, c='g', marker='o', s=50, label='Dane')\n",
" \n",
" ax.set_xlabel(xlabel)\n",
" ax.set_ylabel(ylabel)\n",
" ax.margins(.05, .05)\n",
" return fig"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAlwAAAFkCAYAAAD13eXtAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nO3de5hddX3v8c83Fy5NhqIkNUiIEYj4CAeHTIppC0XwjjZMpkBQT4XWFm21DsE2EM55WvWcGk/a43SqeKFowR4vARkCtVQq4jniaVGTkAARERRSYkAuXphETyaz9/f8sfZ29szsvdea2eu31tp7v1/Ps56Zdfv9vusXH+fLWr+1vubuAgAAQDhz8g4AAACg05FwAQAABEbCBQAAEBgJFwAAQGAkXAAAAIGRcAEAAAQ2L+8AZmrRokW+fPnyvMMAAACYZPv27c+4++J6+9ou4Vq+fLm2bduWdxgAAACTmNmeRvt4pAgAABAYCRcAAEBgJFwAAACBkXABAAAERsIFAAAQGAkXAABAYCRcAAAAgZFwAQAABEbCBQAAEBgJFwAArXCXbrkl+plke6g+sogDsxYs4TKz483sa2b2oJntNrPBOse80sx+ZmY7K8tfhIoHAIAgtm6VBgak9esnkhr3aH1gINqfRR9ZxIFZC1lLcVzSe919h5n1SNpuZl9x9+9MOe5ud39TwDgAAAinv18aHJSGh6P1oaEoyRkejrb392fXR+g4MGvBEi53f0LSE5XfR83sQUnHSZqacAEA0L7MouRGipKbasIzOBhtN8uuj9BxYNbMM3ima2bLJX1d0qnu/lzN9ldKulnSXkn7JP2Zu++uc/5lki6TpGXLlvXt2dOwGDcAAPlwl+bUzNQpl9NPcpL0kUUcqMvMtrv7qnr7gk+aN7OFipKqy2uTrYodkl7k7i+X9BFJdR8wu/u17r7K3VctXrw4bMAAAMxUda5Urdq5VFn1kUUcmJWgCZeZzVeUbH3W3Uem7nf359x9f+X32yXNN7NFIWMCACBV1SSnOleqXJ6YS5VWspOkjyziwKwFm8NlZibpU5IedPcPNzhmiaQfubub2RmKEsBnQ8UEAEDqtm6dSHKqc6Vq51Kdfba0dm34Pqq/h4wDsxZsDpeZnSnpbkn3SypXNl8taZkkufsnzOzdkv5Y0RuNv5B0hbv/W7N2V61a5du2bQsSMwAAM+YeJUT9/ZPnSjXaHqoPKXwcaKrZHK5MJs2niYQLAAAUUa6T5gEAALodCRcAAEBgJFwAgOy1S92/clm68sroZ5LtQAMkXACA7LVL3b+NG6XNm6W+vonkqlyO1jdvjvYDCZBwAQCyV1sbsJp0FbHu36ZNUm+vtHPnRNLV1xet9/ZG+4EEQhavBgCgvizqD6Zhzhxp+/aJJGvu3Gh7b2+0fQ73LZAMn4UAAOSnXer+lcsTyZYklUokW5iGz0IAAIqnXer+VR8j1qqd0wUkQMIFAMheu9T9mzpnq1SaPqcLSICECwCQvUa1AatJV5HeUqwmW9U5W9u3TyRdvKWIhJjDBQDIXhb1B9NQLkdJ1aZN0+ea1duOrkYtRQAAgMCYNA8AAJAjEi4AQPbiSvuUy/Glf9JoI4trSdJPUdroFEUcC3dvq6Wvr88BAG1uZCRKmQYH3cvlaFu5HK1L7hs2NN8/MpJOG1lcS5J+itJGp8hpLCRt8wb5S+4J1EwXEi4A6AC1f/yqfxRr10ul5vvL5XTayOJakvRTlDY6RU5jQcIFACie2j+C1aXRHYl6+9NqI4traac2OkUOY9Es4eItRQBAfjymtE/c/rTaSEMa/RSljU6R8VjwliIAoHg8prRP3P602khDGv0UpY1OUbSxaHTrq6gLjxQBoAMwh6uYbXQK5nCRcAEAnLcUi9pGp+AtRRIuAIBHf/xGRqbfaahuL5Wa76/e4Wq1jSyuJendqSK00SlyGotmCReT5gEAAFLApHkAAIAckXABAAAERsIFAEAjnkJNvjTa6DYdOGYkXAAANLJ1qzQwUP/bXgMD0f4s2ug2HThm8/IOAACAwurvlwYHpeHhaH1oKPqjPzwcbe/vz6aNbtOBY8ZbigAANFO9s1L94y9Ff/SHhpKXiUmjjW7ThmPW7C1FEi4AAOI4NQ5z0WZjxmchAACYreqdllrUOAyvw8aMhAsAgEZqH2sNDkZ3WKpzi5L+8U+jjW7TgWPGpHkAABrZunXij3517tDQULRveFg6+2xp7drwbXSbDhwz5nABANCIe/THv79/8tyhRttDtdFt2nTMmDQPAAAQGJPmAQAAckTCBQAAEBgJFwCgMyWpxxd3TLncehvUW5ysm661BgkXAKAzJanHF3fMxo2tt0G9xcm66VpruXtbLX19fQ4AQKxy2X1wMLoHNThYfz3umFKp9TbK5XRi7RQdfK2StnmD/CX3BGqmCwkXACCx2j/m1WXqH/W4Y9JoI61YO0WHXmuzhIvPQgAAOpsnqMcXd0wabaQVa6fowGvlsxAAgO7kCerxxR2TRhtpxdopuulaqxrd+irqwiNFAEAizOEqpg6+VjGHCwDQdUZGpv8Rr/3jPjISf8yGDa23MTKSTqydooOvtVnCxRwuAEBn8gT1+KTmx5x/vnTrra21Qb3FyTr4WqmlCAAAEBiT5gEAAHJEwgUAmBnPoGROkpI6yF6Sf/t26idDwRIuMzvezL5mZg+a2W4zG6xzjJnZ35nZI2Z2n5mtDBUPACAlWZTMSVJSB9nLqixPJ5b/aTSbvtVF0rGSVlZ+75H0PUkvm3LMeZL+RZJJWi3pm3Ht8pYiAOQsi88tJPkcA7KX1Scd2vTTESrCZyEk3SrpNVO2fVLSm2vWH5J0bLN2SLgAoACyKJnToeVf2l5W/y5t+O/fLOHK5C1FM1su6euSTnX352q2f0nSh9z9G5X1r0q60t23TTn/MkmXSdKyZcv69uzZEzxmAEAMz6BkTpI+kL2s/l3a7N8/17cUzWyhpJslXV6bbFV31zllWgbo7te6+yp3X7V48eIQYQIAZqI6n6ZW2iVzkvSB7GX179Jp//6Nbn2lsUiaL+kOSVc02M8jRQBoN8zh6l7M4WpKeczhUnT36jOS/rbJMW/U5Enz34prl4QLAHKWRcmcJCV1kL2syvK0afmfZglXsDlcZnampLsl3S+pXNl8taRllTtrnzAzk/RRSa+X9HNJv+9T5m9NxZfmASBnnqA0i9RayZwkJXUKPJenYyX5t0/j3yWrflJGaR8AAIDAKO0DAACQIxIuAACAwEi4AADp85haeKWSdOWV0XeVapXL9bfPpo82mzLTMsaj0Ei4AADpi6uFd8EF0ubNUl/fRHJVLkfrmzdHtRRb7aMd6+21gvEotkavLxZ14bMQANAG4r6jND7u3tsbrff2Rt/dmrreah8F/VZTMIxH7pR3aZ808ZYiALSJ6t2V4eGJbYOD0tBQ9Ep/9Y7Wzp0T+3t7pe3bJ5dzaaWPbsN45IrPQgAA8uExtfDKZWnu3In1Uil5spW0j27DeOSGz0IAALJXvdtSq3Z+UfUOV63aOV1p9NFtGI/CIuECAKSv9tHW4GCURA0ORuvr10d3sqqPE3t7o/Xe3mg9adIV10e3JRmMR7E1mtxV1IVJ8wDQBuJq4fX3T58gXztxfsOG1vsoaL29YBiP3IlJ8wCATHlMLbw1a6Srr5Y2bZo+32jjxunbZ9NHQevtBcN45I5J8wAAAIExaR4AACBHJFwAAACBkXABACYrlaS1a6Of9bYfOtQ5dRAbxVzdXiq1Hmca15rVeBXl36UTNZpNX9SFtxQBILDqG4SLFkUleNyjn4sWRdtPOqlz3jDcsKH5tVTHopU407jWrMarKP8ubUpN3lLMPYGa6ULCBQCB1SZX1aSrdn1srHPqINaLvXZ9fLz1ONO41qzGqyj/Lm2KhAsAMDO1SVZ1qb3jVZuYVJekyVZV7R/z6pLHH/W4a0kjzqK0UaR+OlCzhIvPQgAA6iuVpHnzJtbHxyfXPeykOohx15JGnEVpo0j9dBg+CwEAmJlSSVqyZPK2JUsmJtJ3Uh3EuGtJI86itFGkfrpNo1tfRV14pAgAgTGHa2KdOVzM4ZoBMYcLAJAYbynylmLe/y5tioQLAJDc+HiUaFSTranbx8aiRGXqnaxSqf72esrl6I/31DsmjbaH0ijm6vbx8dbjTONasxqvovy7tKlmCReT5gEAAFLApHkAAIAckXABQLvwNiq70k6xAhkg4QKAdrF1qzQwMPkVfa+8wj8wEO0vinaKFcjAvPhDAACF0N8vDQ5Kw8PR+tBQlMAMD0fb+/vzja9WO8UKZIBJ8wDQTqp3iaqJjBQlMENDxfsSeDvFCqSg2aR5Ei4AaDfeRmVX2ilWoEW8pQgAnaJ616hWUcuutFOsQGAkXADQLmof0Q0ORneLqvOkipbItFOsQAaYNA8A7WLr1okEpjoPamgo2jc8LJ19trR2bb4xVrVTrEAGmMMFAO3CPUpk+vsnz4NqtD1P7RQrkBImzQMAAATGpHkAAIAckXABAAAERsIFAO0ijfqERalxWJQ4stBN14qGSLgAoF2kUZ+wKDUOixJHFrrpWtGYu7fV0tfX5wDQlcpl98FBdyn6WW89izbSUJQ4stBN19rlJG3zBvkLbykCQDtJoz5hUWocFiWOLHTTtXYxPgsBAJ0kjfqERalxWJQ4stBN19ql+CwEAHSKNOoTFqXGYVHiyEI3XSvqIuECgHaRRn3CotQ4LEocWeima0VjjSZ3FXVh0jyArjUyMn2ide0E7JGRbNpIQ1HiyEI3XWuXE5PmAaADeAr1CdNoIw1FiSML3XStXY5J8wAAAIExaR4AACBHJFwAAACBJU64zOzXzGxZdUlw/KfN7Ckze6DB/lea2c/MbGdl+YuZBA4AheIZ1Ms7dEhasSL62Wh7XBzlcutxlsvSlVdGPxttzyIOoJ00mk1fXSStkfSwpAOSHpVUlrQ7wXm/LWmlpAca7H+lpC/FtTN14S1FAIWUxZtoJ50UtTV3rvvYWLRtbCxal6L9cXFs2NB6nNU2envdS6VoW6kUrVf7yCIOoGDU5C3FJAnXLknHSLq3sn6OpGvjzqscu5yEC0BXyKJeXm1yVU26pq7HxVEqtR5nbXJVTbqmrmcRB1AwrSZc23wi8ZpT+f1bced5soTr2Uq7/yLplCRtknABKKzapKG6pJ081CZZ1aX2jleSONKIszbJqi61d7yyigMokGYJV+xnIczsTkn9kjZJWiTpKUm/7u6/Gfe40syWV+5inVpn31GSyu6+38zOkzTs7isatHOZpMskadmyZX179uyJ6xoA8uEZ1Ms7dEg67LCJ9bExaf78mcWRRpzlsjR37sR6qTS5zaziAAqi1c9CnC/p55LWS/qypO9LelOrQbn7c+6+v/L77ZLmm9miBsde6+6r3H3V4sWLW+0aAMLwDOrlHTokHXnk5G1HHjl5In1cHGnEWS5LfX2Tt/X1TZ5In0UcQLtodOurukh6Q51t74w7z+MfKS7RxIdXz5D0H9X1ZguPFAEUEnO4Jq8zhwtdSC3O4fo3SefWrG+Q9C8Jzvu8pCckHZK0V9LbJb2zmqxJerek3YrmcN0j6Tfj2nQSLgBFxVuKvKWIrtdqwrWokhCdJemvJN0saX7ceaEWEi4AhVQuR0nC1DszjbbPxthYlFTVTpCfuj0ujlKp9ThLpShhqp0gP3V7FnEABdMs4UpUS9HMfk3SnZK2S/oDT3JSINRSBAAARdRs0vy8JieNSnJJVvl5mKQTJF1gZu7uR4UIFgAAoNM0fEvR3Xvc/aian0e4+8LqepZBAsCsubdPCZkkJXPixF1vqdR6WZ4ijVlojAVSEvtZCDP7apJtAFBIW7dKAwP1P0cwMBDtL4qNG6XNmyd/XqH6+YXNm6P9ceKu94IL4vtopzELjbFAWhpN7pJ0hKKSPrskPU/S8yvLckkPNjov9MKkeQAzksXnGtKS5HMLceKud3y89U86FGnMQmMsMAOazVuKkgYVFas+KOkHld8frSRg7250XuiFhAvAjLVTCZkkJXPixF1vGmV5ugljgYSaJVxJSvv8qbt/JP17a7PDW4oAZsXbqIRMkpI5ceKuN42yPN2EsUACLZX2cfePmNmpZnaRmb2tuqQfJgAEUp1zU6uoJWSSlMyJE3e9aZTl6SaMBVKQZNL8X0r6SGU5R9JmSWsCxwUA6aj+sRwelgYHo6RicDBaL9ofzWoitHOn1Nsb3XXq7Y3WkyZdcddbKsX30U5jFhpjgbQ0etZYXSTdrygx21VZf4Gkf4o7L9TCHC4AM5JFyZ20JCmZEyfuevv74/topzELjbHADKjF0j7fqvzcLukoRR9C3R13XqiFhAvAjGRRcictSUrmxIm73vHx1svyFGnMQmMsMAPNEq4kk+Y/JulqSRdLeq+k/ZJ2uvvvp3+/LR6T5gEAQBHNqrRPlbv/iZnNd/dPmNmXJR3l7velHiUAAECHalZLcWXl1xMkXWxmf6XocaLMbKW778ggPgAAgLbX7C3F/1lZ3iVpqaQv12z7m/ChAeh4XpA6daWStHZt9LPe9kOH4usPxtVBHB9vvYZhuRw/XkUZUwCTNZrcNXWR9J6kx4ZcmDQPdJCivAFWfXNv0aJoUrl79HPRomj7SSfFv9kX94bhGWe0/nZgtY9m41WUMQW6kFp8S/EISVdIukXSzZIul3RE3HmhFhIuoIMUpU5dbXJVTbpq18fG4usPxtVBPHSo9RqGpVL8eBVlTIEu1GrCdaOkTyn66Ok5kq6VdFPceaEWEi6gwxSlTl1tklVdau94Jak/GHdMGjUMk4xXUcYU6DLNEq4kn4XY5e4vj9uWFT4LAXQgL0idulJJmlfzLtH4+OR6g0nqD8Ydk0YNwyTjVZQxBbpIS7UUJd1rZqtrGnuFpP+bVnAAupwXpE5dqSQtWTJ525IlExPpk9QfjDsmjRqGScarKGMKYEKjW1/VRdKDksqSHqssZUm7FZX8uS/u/LQXHikCHaQo842YwwUgBWpxDteLmi1x56e9kHABHaQob9TxliKAFLSUcBVtIeECOkhR6tSNj0dJVzXZmrp9bCy+/mBcHcRDh1qvYVgqxY9XUcYU6ELNEq7YSfNFw6R5AABQRK1OmgcAAEALSLgAdDZPUOomyTFp9JNFG0XoA8A0s0q4zOzatAMBgCC2bpUGBup/WmFgINqf5Jg0+smijSL0AWC6RpO7mi2S+mZzXhoLk+YBzEiSzySk8SmForRRhD6ALqXZvqUoaa6kv252TNYLCReAGcuqHE5R2ihCH0AXapZwJSntc5ekV3ncgRnhLUUAs+IZlcMpShtF6APoMi2X9pF0q5n9npkNVJd0QwSAgDyjcjhFaaMIfQCYJEnC9XxJz0o6V9LvVJY3hQwKAFJTTS6Gh6XBwehOzuBgtF5NMpIck0Y/WbRRhD4ATNfoWWNRF+ZwAZiRJKVu0iiHU5Q2itAH0KXU4hyul0j6uKQXuPupZnaapDXu/t8zyAenYQ4XgBlxjz510N8/eY5S7XYp/pi4+U1J+smijThZ9AF0qWZzuJIkXP9H0p9L+qS7n17Z9oC7n5p6pAmQcAEAgCJqddL8r7j7t6ZsG289LAAAgO6QJOF6xsxOlOSSZGYXSHoiaFQAAAAdJEnC9S5Jn5T0UjP7oaTLJf1x0KgANObUwpskbjzKZcYLQO5iEy53/4G7v1rSYkkvdfcz3f2x4JEBqI9aeJPFjcfGjYwXgNzNizvAzEqS/lrSxsorjzKzHe6+MnRwAOro75/4bpIkDQ1N/q5S9a27bhE3Hps2SQcPMl4AcpXkLcX7JH1Z0umS1rn7j83s3uobi1njLUVAkz9eWTU4GCUT3fhKf9x4MF4AMtDqZyF2uPtKM7tI0l9Kepukv8/rDhcJF1BBLbzJ4saD8QIQWKufhTBJcvcbJV0k6R8knZBeeABmjFp4k8WNB+MFIGdJEq4/rP7i7rslnSnpPcEiAtActfAmixuPcpnxApC72Enzkk4ws++5+6iZ/VdJKyXlUtYHgKK36qrJQ3UO0tBQtG94WDr7bGnt2nxjzFLceBx+OOMFIHeJJs27+2lmdqakTZL+RtLV7v6KLAKcijlc6HrUwpssbjzOP1+69VbGC0BwrU6av9fdTzezTZLud/fP8ZYiAADAZK1Omv+hmX1S0YT5283s8ITnAQAAQMkSp4sk3SHp9e7+U0nPl/TnQaMCAADoIElK+/zc3Ufc/eHK+hPu/q9x55nZp83sKTN7oMF+M7O/M7NHzOw+M+PL9UCRlMvSlVdGP5NsT/t8Kbu6kdRjBBBYyEeD10t6fZP9b5C0orJcJunjAWMBMFMbN0qbN0t9fRPJUbkcrW/eHO0Peb6UXd1I6jECCM3dgy2Slkt6oMG+T0p6c836Q5KOjWuzr6/PAWSgVHLv7XWXop/11kOe7+5eLrsPDkbnDA7WX09DXD+lUjZxAGhrkrZ5g/wlyXe4QjlO0uM163sr257IJxwAk8yZI23fHt2R2rlTmjs32t7bG22fE3ODvNXzpenfzKrWQky7DmKSfrKIA0DHiv0sREuNmy2X9CV3P7XOvn+WtMndv1FZ/6qkDe6+vc6xlyl67Khly5b17dmzJ1jMAKYolyeSJUkqlZIlS2mdL2VXB5F6jABa0OpnIULZK+n4mvWlkvbVO9Ddr3X3Ve6+avHixZkEB0ATc65q1c7JCn2+lF0dROoxAggoz4TrNklvq7ytuFrSz9ydx4lAUVSTpZ07o8eApVL0c+fOZElTq+dL2dWNpB4jgNAaTe5qdZH0eUXzsQ4pupv1dknvlPTOyn6TdI2k70u6X9KqJO0yaR7IyIYN0ye4105837Ah7Pnu7iMj0yem105YHxmZ/fXNpJ/qtYSOA0BbU5NJ80HncIVAaR8gI+Vy9DmETZumz1uqtz3t86Xs6kbG9UM9RgAJtFRLsWhIuAAAQBEVddI8AABAVyDhAgAACIyECwAAIDASLgAAgMBIuAAAAAIj4QIAAAiMhAsAACAwEi4AAIDASLgAAAACI+ECAAAIjIQLAAAgMBIuAACAwEi4AAAAAiPhAgAACIyECwAAIDASLgAAgMBIuAAAAAIj4QIAAAiMhAsAACAwEi4AAIDASLgAAAACI+ECAAAIjIQLAAAgMBIuAACAwEi4AAAAAiPhAgAACIyECwAAIDASLgAAgMBIuAAAAAIj4QIAAAiMhAsAACAwEi4AAIDASLgAAAACI+ECAAAIjIQLAAAgMBIuAACAwOblHQDCGj04qi27t+jhZx/WimNWaN0p69RzeE/eYQEA0FVIuDrYN/7jGzrvs+ep7GUdOHRAC+Yv0BV3XKHb33q7zlx2Zt7hAQDQNXik2KFGD47qvM+ep9GxUR04dECSdODQAY2ORdv3j+3POUIAALoHCVeH2rJ7i8perruv7GVteWBLxhEBANC9SLg61MPPPvzLO1tTHTh0QI/8+JGMIwIAoHuRcHWoFces0IL5C+ruWzB/gU56/kkZRwQAQPci4epQ605ZpzlW/593js3RulPXZRwRAADdi4SrQ/Uc3qPb33q7eg7r+eWdrgXzF6jnsGj7wsMW5hwhAADdg89CdLAzl52pfe/dpy0PbNEjP35EJz3/JK07dR3JFgAAGSPh6nALD1uot698e95hAADQ1XikCAAAEBgJFwAAQGBBEy4ze72ZPWRmj5jZVXX2X2pmT5vZzsryhyHjQX2jB0d13Y7rdOVXrtR1O67T6MHRvEMCAKCjBJvDZWZzJV0j6TWS9kr6tpnd5u7fmXLoFnd/d6g40Bz1FgEACC/kHa4zJD3i7j9w9zFJX5B0fsD+MEPUWwQAIBshE67jJD1es763sm2q3zWz+8zsi2Z2fMB4MAX1FgEAyEbIhMvqbPMp6/8kabm7nybpTkk31G3I7DIz22Zm255++umUw+xe1FsEACAbIROuvZJq71gtlbSv9gB3f9bdD1ZW/15SX72G3P1ad1/l7qsWL14cJNhuRL1FAACyETLh+rakFWb2YjM7TNLFkm6rPcDMjq1ZXSPpwYDxYArqLQIAkI1gCZe7j0t6t6Q7FCVSN7r7bjP7gJmtqRz2HjPbbWa7JL1H0qWh4sF01FsEACAb5j51WlWxrVq1yrdt25Z3GB1l/9h+6i0CANAiM9vu7qvq7aOWIqi3CABAYJT2AQAACIyECwAAIDAeKeZo9OCotuzeooeffVgrjlmhdaesU8/hPTNq43vPfE+Xbr1Uj/70Ub346Bfr+v7r9ZJFL5lRH2nEkUYbAAB0KibN56ReDcM5NmdGNQyvuOMKDd0zNG37+tXr9eHXfThRH2nEkUYbAAC0u2aT5km4cjB6cFTHffg4jY6NTtvXc1iP9r13X+xbgt975ns6+ZqTG+7fedlOnXX9WU37cPeW40jjWgAA6ATNEi7mcOUgjRqGl269tOn+gZsGYvtIIw7qMQIAEI85XDlIo4bhoz99tOn+H+3/UWwf1UeArcRBPUYAAOJxhysHadQwfPHRL266/wULXxDbRxpxUI8RAIB4JFw5SKOG4fX91zfdP3LhSGwfacRBPUYAAOKRcOUgjRqGL1n0Eq1fvb7uvvWr1+vlx748to804qAeIwAA8XhLMUdp1DD8/o+/r7fd8jY99tPHtPzo5frM2s/oxOefOKM+0oiDeowAgG7HZyEAAAAC47MQAAAAOeKzEDna99w+bfzqRn33me/qpYteqk2v2qQXHvXCScekUbonDmV5AAAIi0eKOfnYtz+md93+rmnbrznvGv3Jr/+JpHRK98ShLA8AAOlgDlfB7Htun44bOq7h/ife+4Se+3/PtVy6h7I8AABkhzlcBbPxqxub7r/qzqtSKd0Th7I8AABkgzlcOfjuM99tuv+hZx7SYz99rOkxSUr3xKEsDwAA2eAOVw5euuilTfefvOjkVEr3xKEsDwAA2SDhysGmV21quv9Dr/5QKqV74lCWBwCAbJBw5eCFR71Q15x3Td1915x3jZYsXJJK6Z44lOUBACAbvKWYoyf3P6mr7rxKDz3zkE5edLI+9OoPacnCJZOOSaN0TxzK8gAA0Do+CwEAABAYn4UAAADIEQkXAABAYBO+/18AAArUSURBVCRcDYweHNV1O67TlV+5UtftuE6jB6d/jT3Ovuf26ZJbLtEr/v4VuuSWS7TvuX2T9u/Yt0MnDp+oBX+1QCcOn6gd+3ZMa+Nzuz6n+R+YL3u/af4H5utzuz43af8dD9+hng/2aM7756jngz264+E7Ju2/+7G7tXjzYs3/wHwt3rxYdz92d5BrTaMNAAA6FXO46kijvmBcrcR1N63Tjd+5cdr+i152kbZcGH3h/fgPH6+9o3unHbO0Z6kev+JxrfzkSt375L3T9p++5HTteMcOnXvDufraY1+btv+c5eforkvuSu1aqccIAACT5mckjfqCcbUS73jrHXrdZ1/XcP+ud+zSAz96QG/d+taGx2xcvVGb7mn8Pa+h1w5p/b/W/6yEJP37H/y7Tvm1U1q+VuoxAgAQYdL8DKRRXzCuVuLv3vS7TfcP3DigS269pOkxzZItSU2TLUla84U1qVwr9RgBAIhHwjVFGvUF42olHhir337Vk/uf1LiPx/bTip/84iepXCv1GAEAiEfCNUUa9QXjaiUuOKx++1VLFi7RPAtbV/x5Rz4vlWulHiMAAPFIuKZIo75gXK3Emy+8uen+kYtGdMP5NzQ9ZuPq5o8th1471HT/bRfflsq1Uo8RAIB4JFxTpFFfMK5W4mtPeq0uetlFdfdf9LKLdNqS0/SWl79FS3uW1j1mac9SffB1H9TpS06vu//0Jafr8t+4XOcsP6fu/nOWn6PVx69O5VqpxwgAQDzeUmwgjfqCcbUS73vyPg3cOKAn9z+pJQuXaOSiEZ225LRJbXzxgS/qzSNv1riPa57N0+cHPq8LTr3gl/vv+sFdOn/L+TowdkALDlugW9fdqnNPOPeX++95/B6t+cIa/eQXP9Hzjnyebrv4Nq0+fnXq10o9RgBAt+OzEAAAAIHxWQgAAIAchX0VroONHhzVlt1b9PCzD2vFMSu07pR16jm8J/N+duzboQtvuvCXjyVvuvAmrXzhytTjAAAAs8cjxVnIqpRNXD9JygMBAIBsMIcrRVmVsonr5/a33K6zrj+r4fm73rFr2gR8AAAQDnO4UpRVKZu4ftZuWdv0/IEbB1KJAwAAtI45XDOUVSmbuH4Ojh9sev6T+59MJQ4AANA67nDNUFalbOL6OfqIo5ueX/u9LwAAkC8SrhnKqpRNXD+3rLul6fkjF42kEgcAAGgdCdcMZVXKJq6fM190Zmx5IAAAUAy8pThLWZWyiesnSXkgAAAQHp+FAAAACIzPQgAAAOSIhAsAACAwEi4AAIDAgiZcZvZ6M3vIzB4xs6vq7D/czLZU9n/TzJaHjAcAACAPwRIuM5sr6RpJb5D0MklvNrOXTTns7ZJ+4u4nSRqS9D9CxQMAAJCXkHe4zpD0iLv/wN3HJH1B0vlTjjlf0g2V378o6VVmZgFjAgAAyFzIhOs4SY/XrO+tbKt7jLuPS/qZpGOmNmRml5nZNjPb9vTTTwcKFwAAIIyQCVe9O1VTP/qV5Bi5+7XuvsrdVy1evDiV4AAAALISMuHaK+n4mvWlkvY1OsbM5kn6VUk/DhgTAABA5kImXN+WtMLMXmxmh0m6WNJtU465TdIlld8vkHSXt9un7wEAAGLMC9Wwu4+b2bsl3SFprqRPu/tuM/uApG3ufpukT0n6RzN7RNGdrYtDxQMAAJCXtqulaGZPS9qTYZeLJD2TYX+djvFMH2OaPsY0fYxpuhjP9KUxpi9y97qTzdsu4cqamW1rVIgSM8d4po8xTR9jmj7GNF2MZ/pCjymlfQAAAAIj4QIAAAiMhCvetXkH0GEYz/QxpuljTNPHmKaL8Uxf0DFlDhcAAEBg3OECAAAIjISrATP7tJk9ZWYP5B1LJzCz483sa2b2oJntNrPBvGNqd2Z2hJl9y8x2Vcb0/XnH1AnMbK6Z3WtmX8o7lk5gZo+Z2f1mttPMtuUdTycws6PN7Itm9t3K/6f+Rt4xtTMzO7nyv8/q8pyZXZ56PzxSrM/MflvSfkmfcfdT846n3ZnZsZKOdfcdZtYjabukfnf/Ts6htS0zM0kL3H2/mc2X9A1Jg+5+T86htTUzu0LSKklHufub8o6n3ZnZY5JWuTvfjEqJmd0g6W53v65SyeVX3P2necfVCcxsrqQfSnqFu6f6zU/ucDXg7l8XdR1T4+5PuPuOyu+jkh6UdFy+UbU3j+yvrM6vLPwXVAvMbKmkN0q6Lu9YgHrM7ChJv62oUovcfYxkK1WvkvT9tJMtiYQLOTCz5ZJOl/TNfCNpf5XHXzslPSXpK+7OmLbmbyVtkFTOO5AO4pL+1cy2m9lleQfTAU6Q9LSkf6g8+r7OzBbkHVQHuVjS50M0TMKFTJnZQkk3S7rc3Z/LO5525+4ld++VtFTSGWbG4+9ZMrM3SXrK3bfnHUuH+S13XynpDZLeVZmugdmbJ2mlpI+7++mSDki6Kt+QOkPl8ewaSTeFaJ+EC5mpzDO6WdJn3X0k73g6SeWRwv+W9PqcQ2lnvyVpTWXO0RcknWtm/yvfkNqfu++r/HxK0i2Szsg3ora3V9LemrvZX1SUgKF1b5C0w91/FKJxEi5kojLB+1OSHnT3D+cdTycws8VmdnTl9yMlvVrSd/ONqn25+0Z3X+ruyxU9VrjL3f9zzmG1NTNbUHlJRpXHXq+VxJvfLXD3JyU9bmYnVza9ShIvH6XjzQr0OFGKbk2iDjP7vKRXSlpkZnsl/aW7fyrfqNrab0n6PUn3V+YcSdLV7n57jjG1u2Ml3VB5q2aOpBvdnU8ZoEheIOmW6L+3NE/S59z9y/mG1BH+VNJnK4/AfiDp93OOp+2Z2a9Ieo2kdwTrg89CAAAAhMUjRQAAgMBIuAAAAAIj4QIAAAiMhAsAACAwEi4AAIDASLgAtBUze5+Z/Vnl9+vN7IJZtrPczJp+E6pyzFtq1i81s4/Opj8A3Y2ECwAaWy7pLXEHAUAcEi4AhWdm/8XMHjKzOyWdPGX30soHIBud+z4z+0czu8vMHjazP5qy/4TKnay7zWxHZfnNyu4PSTrLzHaa2fop573RzP7dzBaZ2e+Y2TcrxYTvNLMXpHHdADoHCReAQjOzPkWldk6XNCDp12t2H1nZ1hPTzGmS3ijpNyT9hZm9sHLuiZLOlPSUpNdUiiyvk/R3lfOuknS3u/e6+1BNTGsr+85z92ckfUPS6kox4S9I2jD7KwbQiSjtA6DozpJ0i7v/XJLM7LbKzwsVJUuD7v5sTBu3uvsvJP3CzL4mabWkP5L0fXf/jJn9qqSPmlmvpJKklzRp6xxJqyS91t2fq2xbKmmLmR0r6TBJj87mQgF0Lu5wAWgH02qQuftNkr4yy/NLkv64Zn29pB9JermiZKrhI0pFtet6NDkp+4ikj7r7f1JUi+2IhHEB6BIkXACK7uuS1prZkWbWI+l3ZtHG+WZ2hJkdo6go/ben7P9VSU+4e1lRkfW5le2jmv64co+ix5ifMbNTas7/YeX3S2YRH4AOR8IFoNDcfYekLZJ2SrpZ0t31jjOzD5jZmgbNfEvSP0u6R9J/c/d9U/Z/TNIlZnaPojtXByrb75M0bma7aifNu/tDkt4q6SYzO1HS+yq/3y3pmZlfJYBOZ+7T7tQDQMcws/dJ2u/uf5N3LAC6F3e4AAAAAuMOFwAAQGDc4QIAAAiMhAsAACAwEi4AAIDASLgAAAACI+ECAAAIjIQLAAAgsP8Ppsr4ScesF0EAAAAASUVORK5CYII=\n",
"text/plain": [
"