{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"___\n",
"\n",
"\n",
"___"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Text Classification Assessment \n",
"\n",
"### Goal: Given a set of text movie reviews that have been labeled negative or positive\n",
"\n",
"For more information on this dataset visit http://ai.stanford.edu/~amaas/data/sentiment/\n",
"\n",
"## Complete the tasks in bold below!"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Task: Perform imports and load the dataset into a pandas DataFrame**\n",
"For this exercise you can load the dataset from `'../DATA/moviereviews.csv'`."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"# CODE HERE"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import pandas as pd"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"df = pd.read_csv('../DATA/moviereviews.csv')"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
label
\n",
"
review
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
neg
\n",
"
how do films like mouse hunt get into theatres...
\n",
"
\n",
"
\n",
"
1
\n",
"
neg
\n",
"
some talented actresses are blessed with a dem...
\n",
"
\n",
"
\n",
"
2
\n",
"
pos
\n",
"
this has been an extraordinary year for austra...
\n",
"
\n",
"
\n",
"
3
\n",
"
pos
\n",
"
according to hollywood movies made in last few...
\n",
"
\n",
"
\n",
"
4
\n",
"
neg
\n",
"
my first press screening of 1998 and already i...
\n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" label review\n",
"0 neg how do films like mouse hunt get into theatres...\n",
"1 neg some talented actresses are blessed with a dem...\n",
"2 pos this has been an extraordinary year for austra...\n",
"3 pos according to hollywood movies made in last few...\n",
"4 neg my first press screening of 1998 and already i..."
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**TASK: Check to see if there are any missing values in the dataframe.**"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"#CODE HERE"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"label 0\n",
"review 35\n",
"dtype: int64"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**TASK: Remove any reviews that are NaN**"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**TASK: Check to see if any reviews are blank strings and not just NaN. Note: This means a review text could just be: \"\" or \" \" or some other larger blank string. How would you check for this? Note: There are many ways! Once you've discovered the reviews that are blank strings, go ahead and remove them as well. [Click me for a big hint](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.str.isspace.html)**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"27"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": []
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
label
\n",
"
review
\n",
"
\n",
" \n",
" \n",
"
\n",
"
57
\n",
"
neg
\n",
"
\n",
"
\n",
"
\n",
"
71
\n",
"
pos
\n",
"
\n",
"
\n",
"
\n",
"
147
\n",
"
pos
\n",
"
\n",
"
\n",
"
\n",
"
151
\n",
"
pos
\n",
"
\n",
"
\n",
"
\n",
"
283
\n",
"
pos
\n",
"
\n",
"
\n",
"
\n",
"
307
\n",
"
pos
\n",
"
\n",
"
\n",
"
\n",
"
313
\n",
"
neg
\n",
"
\n",
"
\n",
"
\n",
"
323
\n",
"
pos
\n",
"
\n",
"
\n",
"
\n",
"
343
\n",
"
pos
\n",
"
\n",
"
\n",
"
\n",
"
351
\n",
"
neg
\n",
"
\n",
"
\n",
"
\n",
"
427
\n",
"
pos
\n",
"
\n",
"
\n",
"
\n",
"
501
\n",
"
neg
\n",
"
\n",
"
\n",
"
\n",
"
633
\n",
"
pos
\n",
"
\n",
"
\n",
"
\n",
"
675
\n",
"
neg
\n",
"
\n",
"
\n",
"
\n",
"
815
\n",
"
neg
\n",
"
\n",
"
\n",
"
\n",
"
851
\n",
"
neg
\n",
"
\n",
"
\n",
"
\n",
"
977
\n",
"
neg
\n",
"
\n",
"
\n",
"
\n",
"
1079
\n",
"
neg
\n",
"
\n",
"
\n",
"
\n",
"
1299
\n",
"
pos
\n",
"
\n",
"
\n",
"
\n",
"
1455
\n",
"
neg
\n",
"
\n",
"
\n",
"
\n",
"
1493
\n",
"
pos
\n",
"
\n",
"
\n",
"
\n",
"
1525
\n",
"
neg
\n",
"
\n",
"
\n",
"
\n",
"
1531
\n",
"
neg
\n",
"
\n",
"
\n",
"
\n",
"
1763
\n",
"
neg
\n",
"
\n",
"
\n",
"
\n",
"
1851
\n",
"
neg
\n",
"
\n",
"
\n",
"
\n",
"
1905
\n",
"
pos
\n",
"
\n",
"
\n",
"
\n",
"
1993
\n",
"
pos
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" label review\n",
"57 neg \n",
"71 pos \n",
"147 pos \n",
"151 pos \n",
"283 pos \n",
"307 pos \n",
"313 neg \n",
"323 pos \n",
"343 pos \n",
"351 neg \n",
"427 pos \n",
"501 neg \n",
"633 pos \n",
"675 neg \n",
"815 neg \n",
"851 neg \n",
"977 neg \n",
"1079 neg \n",
"1299 pos \n",
"1455 neg \n",
"1493 pos \n",
"1525 neg \n",
"1531 neg \n",
"1763 neg \n",
"1851 neg \n",
"1905 pos \n",
"1993 pos "
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": []
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Int64Index: 1938 entries, 0 to 1999\n",
"Data columns (total 2 columns):\n",
" # Column Non-Null Count Dtype \n",
"--- ------ -------------- ----- \n",
" 0 label 1938 non-null object\n",
" 1 review 1938 non-null object\n",
"dtypes: object(2)\n",
"memory usage: 45.4+ KB\n"
]
}
],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**TASK: Confirm the value counts per label:**"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [],
"source": [
"#CODE HERE"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"pos 969\n",
"neg 969\n",
"Name: label, dtype: int64"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## EDA on Bag of Words\n",
"\n",
"**Bonus Task: Can you figure out how to use a CountVectorizer model to get the top 20 words (that are not english stop words) per label type? Note, this is a bonus task as we did not show this in the lectures. But a quick cursory Google search should put you on the right path. [Click me for a big hint](https://stackoverflow.com/questions/16288497/find-the-most-common-term-in-scikit-learn-classifier)**"
]
},
{
"cell_type": "code",
"execution_count": 45,
"metadata": {},
"outputs": [],
"source": [
"#CODE HERE"
]
},
{
"cell_type": "code",
"execution_count": 46,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 55,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Top 20 words used for Negative reviews.\n",
"[('film', 4063), ('movie', 3131), ('like', 1808), ('just', 1480), ('time', 1127), ('good', 1117), ('bad', 997), ('character', 926), ('story', 908), ('plot', 888), ('characters', 838), ('make', 813), ('really', 743), ('way', 734), ('little', 696), ('don', 683), ('does', 666), ('doesn', 648), ('action', 635), ('scene', 634)]\n"
]
}
],
"source": []
},
{
"cell_type": "code",
"execution_count": 56,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Top 20 words used for Positive reviews.\n",
"[('film', 5002), ('movie', 2389), ('like', 1721), ('just', 1273), ('story', 1199), ('good', 1193), ('time', 1175), ('character', 1037), ('life', 1032), ('characters', 957), ('way', 864), ('films', 851), ('does', 828), ('best', 788), ('people', 769), ('make', 764), ('little', 751), ('really', 731), ('man', 728), ('new', 702)]\n"
]
}
],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Training and Data\n",
"\n",
"**TASK: Split the data into features and a label (X and y) and then preform a train/test split. You may use whatever settings you like. To compare your results to the solution notebook, use `test_size=0.20, random_state=101`**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"#CODE HERE"
]
},
{
"cell_type": "code",
"execution_count": 57,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Training a Mode\n",
"\n",
"**TASK: Create a PipeLine that will both create a TF-IDF Vector out of the raw text data and fit a supervised learning model of your choice. Then fit that pipeline on the training data.**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"#CODE HERE"
]
},
{
"cell_type": "code",
"execution_count": 74,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 76,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Pipeline(steps=[('tfidf', TfidfVectorizer()), ('svc', LinearSVC())])"
]
},
"execution_count": 76,
"metadata": {},
"output_type": "execute_result"
}
],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**TASK: Create a classification report and plot a confusion matrix based on the results of your PipeLine.**"
]
},
{
"cell_type": "code",
"execution_count": 77,
"metadata": {},
"outputs": [],
"source": [
"#CODE HERE"
]
},
{
"cell_type": "code",
"execution_count": 78,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 79,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 80,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" precision recall f1-score support\n",
"\n",
" neg 0.81 0.86 0.83 191\n",
" pos 0.85 0.81 0.83 197\n",
"\n",
" accuracy 0.83 388\n",
" macro avg 0.83 0.83 0.83 388\n",
"weighted avg 0.83 0.83 0.83 388\n",
"\n"
]
}
],
"source": []
},
{
"cell_type": "code",
"execution_count": 81,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
""
]
},
"execution_count": 81,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAUUAAAEGCAYAAADyuIefAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8vihELAAAACXBIWXMAAAsTAAALEwEAmpwYAAAc8klEQVR4nO3de5xVdb3/8dd7hpuAgjCoKCioqOEFU8TbyYNSeeuEXTxi6fGoRZppeTlZnVOWaXlOdowyNRR+al5KzdSsMDXNyxEVEFFQlAIBRQEREEQuM5/fH2sNbIZhZs2w1+zZm/fTx3rM2t+99lqfcetnvrf1XYoIzMwsUVXqAMzM2hMnRTOzAk6KZmYFnBTNzAo4KZqZFehQ6gC2RE2v6hjQv2Opw7AWeG1a11KHYC30Pu8tjog+rf38sUd3i3eX1GY6dvK01Q9FxHGtvVYxlHVSHNC/I8891L/UYVgLHLvzgaUOwVrokbjnjS35/LtLannuoV0zHVvd9/WaLblWMZR1UjSz9i+AOupKHUZmTopmlqsgWBvZms/tgQdazCx3dRn/aY6k8ZIWSnq5Qfn5kl6VNF3S/xSUf1vSLEkzJR2bJVbXFM0sV0FQW7zbiW8GrgVurS+QdDQwEhgSEasl7ZCWDwZGAfsCOwOPSNoroulqq2uKZpa7OiLT1pyIeAJY0qD4XOCqiFidHrMwLR8J/CYiVkfEbGAWMKy5azgpmlmuAqglMm1AjaRJBdvoDJfYC/iYpGcl/U3SIWn5LsC8guPmp2VNcvPZzHKXpRaYWhwRQ1t4+g5AL+Aw4BDgLkm7t/AcG53MzCw3AazNd4nC+cC9kayD+JykOqAGeBMonMjcLy1rkpvPZparyNh0rs1em2zoPuBoAEl7AZ2AxcADwChJnSUNBAYBzzV3MtcUzSxfAbVFqihKuhMYTtL3OB+4DBgPjE+n6awBzkhrjdMl3QXMANYB5zU38gxOimaWs+SOliKdK+LUzbx12maOvxK4siXXcFI0s5yJWlTqIDJzUjSzXCUDLU6KZmZA/TxFJ0Uzs/XqXFM0M0u4pmhmViAQtWU0JdpJ0cxy5+azmVkqEGuiutRhZOakaGa5SiZvu/lsZraeB1rMzFIRojZcUzQzW6/ONUUzs0Qy0FI+qaZ8IjWzsuSBFjOzBmo9T9HMLOE7WszMGqjz6LOZWSJZEMJJ0cwMSJrPa32bn5lZIgJP3jYz20CevG1mVi8or5pi+URqZmWrlqpMW3MkjZe0MH3Gc8P3LpYUkmrS15L0c0mzJE2TdFCWWJ0UzSxXgaiLbFsGNwPHNSyU1B/4JDC3oPh4YFC6jQauz3IBJ0Uzy1XyiNMOmbZmzxXxBLCkkbeuAb6ZXq7eSODWSEwEekrq29w13KdoZjlTS9ZTrJE0qeD12IgY2+TZpZHAmxHxorTRdXYB5hW8np+WLWjqfE6KZparoEV3tCyOiKFZD5bUFfgOSdO5KJwUzSx3Oa68vQcwEKivJfYDpkgaBrwJ9C84tl9a1iQnRTPLVYRyu/c5Il4Cdqh/LWkOMDQiFkt6APiapN8AhwLLIqLJpjM4KZpZzpKBluLc5ifpTmA4Sd/jfOCyiBi3mcP/BJwAzAI+AM7Mcg0nRTPLWfGe0RIRpzbz/oCC/QDOa+k1nBTNLFfJQItv8zMzW89Lh5mZpervaCkXTopmljs/uMrMLBUBa+ucFM3MgPrms5Oimdl6Od7RUnROiiXw0wv78+wj29GzZh1jH5u5vvz+cTU8cHMNVdXBoSOW86Xvbph8v3B+R748fB9Ou/htTj53USnCtlSfndfwH2Pm0rPPOgj40229uW9cH75zwxz67bEagG7b1bJyeTVf/cTeJY629Dwlx5r1yVOW8OkzF/OTr++6vmzq0935v4d6cP0jM+nUOVi6eOOv5lc/2IVDjnm/rUO1RtSuE2Mv35lZL3Vlm261XDvhNaY8sS0/OmfA+mNGf+8tVr5fPk3GfJVX87l8Iq0g+x+2km23r92o7MFbe3PK196hU+dkObieNevWv/d/f+7BTv3XsNteH7ZpnNa4JQs7MuulrgCsWlnNvFldqOm7tuCI4KhPL+Wx+7YvTYDtUF36nJbmtvYgt6QoaYCkVyTdKGm6pL9I2kbSHpImSJos6UlJ+6TH7yFpoqSXJF0haUVesbVHb/69Cy8/250LThzEJZ/dk5lTtwFg1coq7rpuB067+O0SR2iN2bHfGvbYbxWvTum6vmy/Q1fy3qIOvDW7cwkjaz+S0efqTFt7kHdNcRDwy4jYF1gKfA4YC5wfEQcDlwDXpceOAcZExP4ki0E2StJoSZMkTVr0bu3mDis7tbXw/tJqxjz4Ol/67ltc+ZUBRMCvr96Jz3x5Edt0qyt1iNZAl661fPemOdzwvZ35YMWG/6GPPmkpj9/Xs3SBtTNFfhxB7vLuU5wdEVPT/cnAAOAI4O6CFXLr/5weDpyU7t8BXN3YCdNVeMcCDB3SJRo7phzV9F3LkScsQ4J9PvoBVVWwbEk1r77Qlaf+2JNxV+zMiuXVqCro1DkYedbiUoe8VavuEHz3pjn89d7tefrPPdeXV1UHR56wjK8dN6h0wbVD7aVpnEXeSXF1wX4tsCOwNCIOzPm6ZeeI45bx4tPdOfDIFcz/e2fWrhE9etXyv/fNWn/Mr6/eiS7dap0QSy646KfzmPd6F+4d22ejdw762PvMm9WZxQs6lSi29qfcRp/beqBlOTBb0smw/hGEQ9L3JpI0rwFGtXFcberH5+7Ghf8yiPl/78IXDx7MhDt6ceyoJbw9txOjj96bH5+7G/8xZi4qn/+Otir7DlvJx09+jyFHruC6h2dy3cMzOeSY5QD880g3nRtTF1WZtvagFFNyvghcL+m/gI7Ab4AXgW8At0n6T2ACsKwEsbWJb1//RqPll147t9Hyeqdf4sGW9mD6c905duchjb730wt3bbR8axYh1rWThJdFbkkxIuYA+xW8Luwj3OS5rSTPTjgsIkLSKMCzXs0qRDk1n9vT5O2DgWuVjMAsBc4qbThmVgzl1qfYbpJiRDwJNN4mMbOy5qRoZpbyIrNmZg14nqKZWSoC1nmRWTOzDcqp+Vw+6dvMylIx732WNF7SQkkvF5T9RNKrkqZJ+r2kngXvfVvSLEkzJR2bJV4nRTPLXYQybRnczKbznB8G9ouIA4DXgG8DSBpMcnfcvulnrpPU7FI8TopmlrtiracYEU8ASxqU/SUi6hcgnQj0S/dHAr+JiNURMRuYBQxr7hruUzSzXEW0qE+xRtKkgtdj05WxsjoL+G26vwtJkqw3Py1rkpOimeVM1GYffV4cEUNbdZVk3YR1wO2t+Xw9J0Uzy13G/sJWk/TvwKeAERFRv87qm0D/gsP6pWVNcp+imeWq/t7nvFbelnQc8E3g0xHxQcFbDwCjJHWWNJDkSQDPNXc+1xTNLF+R9CsWg6Q7geEkfY/zgctIRps7Aw+nK/pPjIhzImK6pLuAGSTN6vMiotlnmDgpmlnuinWbX0Sc2kjxuCaOvxK4siXXcFI0s1xFywZaSs5J0cxyV6zmc1twUjSz3OU9+lxMTopmlqsIJ0Uzs42U0yo5Topmljv3KZqZpQJR59FnM7MNyqii6KRoZjnzQIuZWQNlVFV0UjSz3FVETVHSL2giv0fEBblEZGYVJYC6ugpIisCkJt4zM8smgEqoKUbELYWvJXVtsFaZmVkm5TRPsdnJQ5IOlzQDeDV9PUTSdblHZmaVIzJu7UCWGZU/A44F3gWIiBeBo3KMycwqSrbHm7aXwZhMo88RMS9d0bZes6vXmpmt105qgVlkSYrzJB0BhKSOwNeBV/INy8wqRkCU0ehzlubzOcB5JM9LfQs4MH1tZpaRMm6l12xNMSIWA19sg1jMrFKVUfM5y+jz7pL+IGmRpIWS7pe0e1sEZ2YVosJGn+8A7gL6AjsDdwN35hmUmVWQ+snbWbZ2IEtS7BoRv46Idel2G9Al78DMrHJEZNvag80mRUm9JPUC/izpW5IGSNpN0jeBP7VdiGZW9uqUbWuGpPFpN97LBWW9JD0s6fX05/ZpuST9XNIsSdMkHZQl1KZqipNJ7n/+V+ArwGPA48C5wClZTm5mBqDItmVwM3Bcg7JvAY9GxCDg0fQ1wPHAoHQbDVyf5QJN3fs8MFOIZmZNKeIgSkQ8IWlAg+KRwPB0/xaSytulafmtERHAREk9JfWNiAVNXSPTHS2S9gMGU9CXGBG3ZvmsmW3tWjSIUiOpcIWusRExtpnP7FiQ6N4Gdkz3dwHmFRw3Py3bsqQo6TKSLDyYpC/xeOApwEnRzLLJXlNcHBFDW32ZiJAyNsQ3I8vo8+eBEcDbEXEmMATosSUXNbOtTF3GrXXekdQXIP25MC1/E+hfcFy/tKxJWZLiqoioA9ZJ2i69YP9mPmNmlsh/nuIDwBnp/hnA/QXl/5aOQh8GLGuuPxGy9SlOktQTuJFkRHoF8ExLozazrdeWNWgLziPdSdKdVyNpPnAZcBVwl6SzgTdIZsxA0t13AjAL+AA4M8s1stz7/NV09wZJE4DtImJaC34PM9vaFW/0+dTNvDWikWODVixe09SDqzY70VHSQRExpaUXMzNr75qqKf60ifcCOKbIsbTY66/04MRhJ5Y6DGuBX8+7q9QhWAv17bfl5yhW87ktNDV5++i2DMTMKlSQ6Ra+9iLT5G0zsy1SCTVFM7NiqYjms5lZ0ZRRUsyy8rYknSbpe+nrXSUNyz80M6sYFbby9nXA4UD9/KD3gV/mFpGZVZSsy4a1lyZ2lubzoRFxkKQXACLiPUmdco7LzCpJhY0+r5VUTVq5ldSHLbl128y2Ou2lFphFlubzz4HfAztIupJk2bAf5RqVmVWWMupTzHLv8+2SJpPcWyjgpIh4JffIzKwytKP+wiyyLDK7K8kKE38oLIuIuXkGZmYVpJKSIvBHkl9JJI8jGAjMBPbNMS4zqyAqo1GILM3n/Qtfp6vnfHUzh5uZlbUW39ESEVMkHZpHMGZWoSqp+SzpooKXVcBBwFu5RWRmlaXSBlqAbQv215H0Mf4un3DMrCJVSlJMJ21vGxGXtFE8ZlaJKiEpSuoQEeskHdmWAZlZZRGVM/r8HEn/4VRJDwB3Ayvr34yIe3OOzcwqQQX2KXYB3iV5Jkv9fMUAnBTNLJsKSYo7pCPPL7MhGdYro1/RzEqujDJGUwtCVAPd023bgv36zcwsk2KupyjpQknTJb0s6U5JXSQNlPSspFmSfrslyxs2VVNcEBGXt/bEZmbrFammKGkX4AJgcESsknQXMAo4AbgmIn4j6QbgbOD61lyjqZpi+awKaWbtVySjz1m2jDoA20jqAHQFFpCMedyTvn8LcFJrw20qKY5o7UnNzDaSfT3FGkmTCrbRG50m4k3gamAuSTJcBkwGlkbEuvSw+cAurQ11s83niFjS2pOamRVqwZScxRExdLPnkbYHRpKs1rWUZKrgcVsY3kb8iFMzy1/xRp8/DsyOiEUAku4FjgR61t9wAvQD3mztBbI8jsDMrPWyNp2zJc65wGGSukoSSTffDOAx4PPpMWcA97c2XCdFM8uVKN6UnIh4lmRAZQrwEkkOGwtcClwkaRbQGxjX2njdfDaz3BXzNr+IuAy4rEHxP4BhxTi/k6KZ5a+M7mhxUjSz/DkpmpmlKnCVHDOzLeOkaGa2QaUsMmtmVhRuPpuZ1cs+MbtdcFI0s/w5KZqZJervaCkXTopmljvVlU9WdFI0s3y5T9HMbGNuPpuZFXJSNDPbwDVFM7NCTopmZqnwbX5mZut5nqKZWUNRPlnRSdHMcueaomXWsVMt//2riXTsVEd1dfD0oztx+417MeSQxZx1/qtUVQWrPujANZcfwIL53Uod7lbrxov35IVHt2e73mu56tGpANz7v/15/I4d2bb3WgBOvnQuBx7zHuvWiPHf2oPZ07qjKjj9B//gI4cvL2H0JebJ29YSa9dU8Z2vHsqHqzpQXV3HT258hknP9OG8S1/mh5cMZd6c7pz4uTcYddYsrrl8SKnD3Wp97OSFfOLfF3DDNwZtVH7sl97ixHPe2qjssTt2BODHj0xl2eKOXP1vg/nBgy9StRU/O7OcBlq24q+pvRAfrkr+NnXoEFR3CAgRIbp2WwdA1+5reXdRl1IGudXb57DldOu5LtOxb77elcFHLgOgR81aum63jtkvds8zvHZPddm29iDXpChpgKRXJd0u6RVJ96QPsR4h6QVJL0kaL6lzevxVkmZImibp6jxja0+qqoJf3PYktz/0CFOfq2Hm9J78/Mr9+f7PnueWP/yVY45/i7tv3b3UYVojHrmlL9/5xIHcePGerFxaDcCug1cy5eFe1K6DhXM7M+el7ixZ0LnEkZZQkAy0ZNkykNQzzSWvpnnlcEm9JD0s6fX05/atDbctaop7A9dFxEeA5cBFwM3AKRGxP0kT/lxJvYHPAPtGxAHAFY2dTNJoSZMkTVpTt6oNws9fXZ04/7SPccanjmGvwUvZbff3OenU2Xz/G4dwxr8cw8MP9uPL33il1GFaAyNOf5ufPjWZKx6aSs8d1nDHDwcC8M+nvEOvndbwvROHcPv3B7LnwctRVRl1quWgsQffN7ZlNAaYEBH7AEOAV4BvAY9GxCDg0fR1q7RFUpwXEU+n+7cBI4DZEfFaWnYLcBSwDPgQGCfps8AHjZ0sIsZGxNCIGNqpapucQ29bK1d0ZNrk3hx8xCIGDnqfmdN7AvDkw335yP5LSxqbbapHn7VUVUNVFQz/wjv8fWrSRK7uAKd9fzZXPvQiF45/lQ+Wd6Dv7pXxB7zVIuPWDEk9SPLFOICIWBMRS4GRJLmE9OdJrQ21LZJiw191aaMHRawDhgH3AJ8CJuQbVvuwXc/VdOuejF526lzLgYcuZt6cbnTtvpadd10BwEfTMmtflr7Tcf3+pAm96bd38nd89aoqPvwg+V/rpSd6UF0d7LLX1psU6ydvZ6wp1tS3BNNtdIPTDQQWAf8v7YK7SVI3YMeIWJAe8zawY2vjbYvR510lHR4RzwBfACYBX5G0Z0TMAk4H/iapO9A1Iv4k6WngH20QW8n1qlnNRZdNo6oqUFXw1CN9ef6pHfnFj/bnP6+aQl2IFcs7MuaHB5Q61K3aL8/bi1cm9mDFkg5ccMhQPnvxXF59pgdvTO+GBDX9VnPWVbMAWL64I/9z2r5UVQXb77SGc8a8XuLoSyyiJYvMLo6IoU283wE4CDg/Ip6VNIYGTeWICKn1MyPbIinOBM6TNB6YAVwATATultQBeB64AegF3C+pC8kfl4vaILaSmzNrOy44/Z82KX/m8Z145vGdShCRNea8X762SdnwUQsbPbZP/9X85G9T8g6pvBSvS3U+MD8ink1f30OSFN+R1DciFkjqCzT+5WTQFklxXUSc1qDsUeCjDcoWkDSfzazCFOuOloh4W9I8SXtHxEySMYoZ6XYGcFX68/7WXsOTt80sXwEU9xkt5wO3S+pE0s12Jsn4yF2SzgbeAP61tSfPNSlGxBxgvzyvYWZloIg5MSKmAo31O44oxvldUzSz3HlBCDOzAn7EqZlZPa+SY2a2QTJ5u3yyopOimeWvnayAk4WTopnlzjVFM7N67lM0MyvUonufS85J0czy5+azmVkq2s+jBrJwUjSz/LmmaGZWoHxyopOimeVPdeXTfnZSNLN8BZ68bWZWT4Qnb5uZbcRJ0cysgJOimVnKfYpmZhvz6LOZ2Xrh5rOZ2XqBk6KZ2UbKp/XspGhm+SuneYpVpQ7AzLYCEdm2jCRVS3pB0oPp64GSnpU0S9JvJXVqbahOimaWrwiorcu2Zfd14JWC1/8NXBMRewLvAWe3NlwnRTPLXxFripL6AScCN6WvBRwD3JMecgtwUmtDdZ+imeUve9O4RtKkgtdjI2Jsg2N+BnwT2DZ93RtYGhHr0tfzgV1aGamTopnlLIDsz2hZHBFDN/empE8BCyNisqThWx7cppwUzSxnAVG0OTlHAp+WdALQBdgOGAP0lNQhrS32A95s7QXcp2hm+QqKNtASEd+OiH4RMQAYBfw1Ir4IPAZ8Pj3sDOD+1obrpGhm+SvylJxGXApcJGkWSR/juNaeyM1nM8tfDpO3I+Jx4PF0/x/AsGKc10nRzHLmBSHMzDYIwEuHmZkVcE3RzKxetPQWvpJyUjSzfAVE8eYp5s5J0czyl/2OlpJzUjSz/LlP0cwsFeHRZzOzjbimaGZWL4ja2lIHkZmTopnlq2VLh5Wck6KZ5c9TcszMEgGEa4pmZqko6iKzuXNSNLPcldNAi6KMhsobkrQIeKPUceSgBlhc6iCsRSr5O9stIvq09sOSJpD8+8licUQc19prFUNZJ8VKJWlSUw/vsfbH31nl8OMIzMwKOCmamRVwUmyfGj7829o/f2cVwn2KZmYFXFM0MyvgpGhmVsBJ0cysgJOimVkBJ8USkDRA0iuSbpQ0XdJfJG0jaQ9JEyRNlvSkpH3S4/eQNFHSS5KukLSi1L/D1ib9zl6VdHv63d0jqaukEZJeSL+b8ZI6p8dfJWmGpGmSri51/Jadk2LpDAJ+GRH7AkuBz5FM6zg/Ig4GLgGuS48dA4yJiP2B+SWI1RJ7A9dFxEeA5cBFwM3AKel30wE4V1Jv4DPAvhFxAHBFieK1VnBSLJ3ZETE13Z8MDACOAO6WNBX4FdA3ff9w4O50/462C9EamBcRT6f7twEjSL7H19KyW4CjgGXAh8A4SZ8FPmjzSK3VvEpO6awu2K8FdgSWRsSBpQnHMmg4qXcp0HuTgyLWSRpGkjQ/D3wNOCb36KwoXFNsP5YDsyWdDKDEkPS9iSTNa4BRpQjOANhV0uHp/heAScAASXumZacDf5PUHegREX8CLgSGbHoqa6+cFNuXLwJnS3oRmA6MTMu/AVwkaRqwJ0nzzNreTOA8Sa8A2wPXAGeSdHm8BNQBNwDbAg+m39dTJH2PViZ8m18ZkNQVWBURIWkUcGpEjGzuc1Y8kgYAD0bEfqWOxfLlPsXycDBwrSSR9GOdVdpwzCqXa4pmZgXcp2hmVsBJ0cysgJOimVkBJ8UKJ6lW0lRJL0u6Ox3Jbu25bpb0+XT/JkmDmzh2uKQjWnGNOZI2efLb5sobHNOie8IlfV/SJS2N0Sqbk2LlWxURB6ZTSdYA5xS+KalVMxAi4ksRMaOJQ4aT3LZoVlacFLcuTwJ7prW4JyU9AMyQVC3pJ5KeT1d1+Qqsv6vmWkkzJT0C7FB/IkmPSxqa7h8naYqkFyU9ms7pOwe4MK2lfkxSH0m/S6/xvKQj08/2TlcJmi7pJkDN/RKS7ktXEpouaXSD965Jyx+V1Ccta3T1IbPGeJ7iViKtER4PTEiLDgL2i4jZaWJZFhGHpEtfPS3pL8BHSVaGGUxyb/YMYHyD8/YBbgSOSs/VKyKWSLoBWBERV6fH3QFcExFPSdoVeAj4CHAZ8FREXC7pRODsDL/OWek1tgGel/S7iHgX6AZMiogLJX0vPffXSFYfOiciXpd0KMnqQ74X2RrlpFj5tklX3YGkpjiOpFn7XETMTss/CRxQ318I9CBZ2uwo4M6IqAXekvTXRs5/GPBE/bkiYslm4vg4MDiZfw7Aduk9wkcBn00/+0dJ72X4nS6Q9Jl0v38a67skt9n9Ni2/Dbg3vUb96kP1n++c4Rq2lXJSrHyrGq68kyaHlYVFJOs4PtTguBOKGEcVcFhEfNhILJlJGk6SYA+PiA8kPQ502czhkV7Xqw9ZZu5TNEiasudK6gggaS9J3YAngFPSPse+wNGNfHYicJSkgelne6Xl75MsjFDvL8D59S8kHZjuPkGy4gySjidZaKEpPYD30oS4D0lNtV4VyVJdpOd8KiKaWn3IbBNOigZwE0l/4RRJL5MscNsB+D3wevrercAzDT8YEYuA0SRN1RfZ0Hz9A/CZ+oEW4AJgaDqQM4MNo+A/IEmq00ma0XObiXUC0CFdqeYqkqRcbyUwLP0djgEuT8s3t/qQ2SZ877OZWQHXFM3MCjgpmpkVcFI0MyvgpGhmVsBJ0cysgJOimVkBJ0UzswL/H3WzFDNuVjY2AAAAAElFTkSuQmCC\n",
"text/plain": [
"