{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"import numpy as np \n",
"import matplotlib.pyplot as plt \n",
"import seaborn as sns\n",
"from sklearn.model_selection import train_test_split\n",
"from sklearn.preprocessing import OneHotEncoder\n",
"from sklearn.preprocessing import LabelEncoder\n",
"from sklearn.metrics import accuracy_score, f1_score, precision_score, recall_score, roc_auc_score\n",
"\n",
"from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier, AdaBoostClassifier\n",
"from sklearn.tree import DecisionTreeClassifier\n",
"from sklearn.neighbors import KNeighborsClassifier\n",
"from xgboost import XGBClassifier\n",
"from catboost import CatBoostClassifier\n",
"\n",
"from sklearn.compose import ColumnTransformer\n",
"from sklearn.pipeline import Pipeline\n",
"from sklearn.preprocessing import StandardScaler\n",
"\n",
"import warnings\n",
"\n",
"# Ignore warnings\n",
"warnings.filterwarnings(\"ignore\")"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"os.chdir(\"/config/workspace\")"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" Temparature | \n",
" Humidity | \n",
" Moisture | \n",
" Soil Type | \n",
" Crop Type | \n",
" Nitrogen | \n",
" Potassium | \n",
" Phosphorous | \n",
" Fertilizer Name | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" 26 | \n",
" 52 | \n",
" 38 | \n",
" Sandy | \n",
" Maize | \n",
" 37 | \n",
" 0 | \n",
" 0 | \n",
" Urea | \n",
"
\n",
" \n",
" 1 | \n",
" 29 | \n",
" 52 | \n",
" 45 | \n",
" Loamy | \n",
" Sugarcane | \n",
" 12 | \n",
" 0 | \n",
" 36 | \n",
" DAP | \n",
"
\n",
" \n",
" 2 | \n",
" 34 | \n",
" 65 | \n",
" 62 | \n",
" Black | \n",
" Cotton | \n",
" 7 | \n",
" 9 | \n",
" 30 | \n",
" 14-35-14 | \n",
"
\n",
" \n",
" 3 | \n",
" 32 | \n",
" 62 | \n",
" 34 | \n",
" Red | \n",
" Tobacco | \n",
" 22 | \n",
" 0 | \n",
" 20 | \n",
" 28-28 | \n",
"
\n",
" \n",
" 4 | \n",
" 28 | \n",
" 54 | \n",
" 46 | \n",
" Clayey | \n",
" Paddy | \n",
" 35 | \n",
" 0 | \n",
" 0 | \n",
" Urea | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" Temparature Humidity Moisture Soil Type Crop Type Nitrogen Potassium \\\n",
"0 26 52 38 Sandy Maize 37 0 \n",
"1 29 52 45 Loamy Sugarcane 12 0 \n",
"2 34 65 62 Black Cotton 7 9 \n",
"3 32 62 34 Red Tobacco 22 0 \n",
"4 28 54 46 Clayey Paddy 35 0 \n",
"\n",
" Phosphorous Fertilizer Name \n",
"0 0 Urea \n",
"1 36 DAP \n",
"2 30 14-35-14 \n",
"3 20 28-28 \n",
"4 0 Urea "
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"FILE_PATH =r\"fertilizer-prediction/Fertilizer Prediction.csv\"\n",
"\n",
"# Loading the dataset into pandas\n",
"df = pd.read_csv(FILE_PATH)\n",
"\n",
"df.head()"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Shape of the dataset: (99, 9)\n"
]
}
],
"source": [
"print(f\"Shape of the dataset: {df.shape}\")"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"RangeIndex: 99 entries, 0 to 98\n",
"Data columns (total 9 columns):\n",
" # Column Non-Null Count Dtype \n",
"--- ------ -------------- ----- \n",
" 0 Temparature 99 non-null int64 \n",
" 1 Humidity 99 non-null int64 \n",
" 2 Moisture 99 non-null int64 \n",
" 3 Soil Type 99 non-null object\n",
" 4 Crop Type 99 non-null object\n",
" 5 Nitrogen 99 non-null int64 \n",
" 6 Potassium 99 non-null int64 \n",
" 7 Phosphorous 99 non-null int64 \n",
" 8 Fertilizer Name 99 non-null object\n",
"dtypes: int64(6), object(3)\n",
"memory usage: 7.1+ KB\n"
]
}
],
"source": [
"# datatypes \n",
"df.info()"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Temparature 0\n",
"Humidity 0\n",
"Moisture 0\n",
"Soil Type 0\n",
"Crop Type 0\n",
"Nitrogen 0\n",
"Potassium 0\n",
"Phosphorous 0\n",
"Fertilizer Name 0\n",
"dtype: int64"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# checking for null values \n",
"df.isnull().sum()"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAA0kAAAJwCAYAAABceyqRAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pXeV/AAAACXBIWXMAAA9hAAAPYQGoP6dpAABC4ElEQVR4nO3dd5RV1d0//s+lzQxtDAoMHaxY0aBBbCAWwKhYosZHI6IhxhYVK4lSLA8xRsF8o5hoAE2MBQ1GMRqVpkGxIBpBg4gY9JESiYCAFJn9+8PF/Z0RhjICQ3m91rprcfbZZ5/Pvefey7znnLMnl1JKAQAAQEREVKnsAgAAALYkQhIAAECGkAQAAJAhJAEAAGQISQAAABlCEgAAQIaQBAAAkCEkAQAAZAhJAAAAGUISANuNjz76KHK5XAwbNmyT72vYsGGRy+Xio48+yre1bNkyjj/++E2+74iIsWPHRi6Xi7Fjx26W/QFsS4QkgC3cqh+2Vz0KCwujcePG0blz5/jNb34TX3zxRYXHfvnll6Nfv34xf/78jVfwt3D33XdvUIDJvi7VqlWLevXqRdu2beOyyy6Ld999t9Lq2py25NoAtla5lFKq7CIAKN+wYcOiR48eceONN0arVq1ixYoVMXv27Bg7dmw8//zz0bx583jyySdjv/322+Cxf/3rX8fVV18dM2bMiJYtW2784jfQPvvsEzvttNN6n/3I5XJxzDHHxDnnnBMppViwYEG8/fbbMXz48Fi8eHHceuut0atXr3z/lFIsW7YsqlevHlWrVt1kdUVErFy5MlasWBEFBQWRy+Ui4uszSfvss0+MHDlyvcepaG2lpaWxfPnyqFGjRlSp4neiABuiWmUXAMD66dq1axx44IH55d69e8fo0aPj+OOPjxNPPDHee++9KCoqqsQKK8fuu+8eZ599dpm2X/7yl3HCCSfElVdeGa1bt47jjjsuIiJ/Jm5TWrx4cdSqVSuqVq26QUFsY6tSpcomf64A2yq/WgLYinXq1CluuOGG+Pe//x1/+tOf8u3//Oc/49xzz42dd945CgsLo6SkJM4777yYN29evk+/fv3i6quvjoiIVq1a5S9bW3UPzdChQ6NTp07RoEGDKCgoiL322isGDx68Wg1vvPFGdO7cOXbaaacoKiqKVq1axXnnnVemT2lpaQwaNCj23nvvKCwsjIYNG8YFF1wQn3/+eb5Py5YtY8qUKTFu3Lh8LR07dqzQ67LjjjvGww8/HNWqVYtbbrkl376me5Jmz54dPXr0iKZNm0ZBQUE0atQounXrln8d1lbXqkshx40bFxdddFE0aNAgmjZtWmZd9p6kVZ577rnYf//9o7CwMPbaa6/4y1/+UmZ9v3798mefsr455tpqK++epOHDh0fbtm2jqKgodtpppzj77LPj//7v/8r0Offcc6N27drxf//3f3HSSSdF7dq1o379+nHVVVfFypUr1/HqA2z9nEkC2Mr96Ec/ip///Ofx3HPPRc+ePSMi4vnnn48PP/wwevToESUlJTFlypT4/e9/H1OmTIkJEyZELpeLU045Jd5///146KGHYuDAgbHTTjtFRET9+vUjImLw4MGx9957x4knnhjVqlWLp556Ki666KIoLS2Niy++OCIi5s6dG8cee2zUr18/rrvuuthhhx3io48+Wu2H/gsuuCB/2eDPfvazmDFjRvz2t7+NSZMmxfjx46N69eoxaNCguPTSS6N27drxi1/8IiIiGjZsWOHXpXnz5tGhQ4cYM2ZMLFy4MOrWrbvGfqeeempMmTIlLr300mjZsmXMnTs3nn/++Zg5c2a0bNlyveq66KKLon79+tGnT59YvHjxWuuaNm1anHHGGfHTn/40unfvHkOHDo3TTjstnn322TjmmGM26Dlu6Gu26hgcdNBBMWDAgJgzZ07ceeedMX78+Jg0aVLssMMO+b4rV66Mzp07R7t27eLXv/51vPDCC3H77bfHLrvsEhdeeOEG1Qmw1UkAbNGGDh2aIiK9/vrr5fYpLi5OBxxwQH55yZIlq/V56KGHUkSkF198Md922223pYhIM2bMWK3/msbo3Llz2nnnnfPLI0aMWGdtL730UoqI9OCDD5Zpf/bZZ1dr33vvvVOHDh3KHeubIiJdfPHF5a6/7LLLUkSkt99+O6WU0owZM1JEpKFDh6aUUvr8889TRKTbbrttrfspr65Vx+awww5LX3311RrXZV/bFi1apIhIjz/+eL5twYIFqVGjRmWOX9++fdOa/ote05jl1TZmzJgUEWnMmDEppZSWL1+eGjRokPbZZ5/05Zdf5vuNHDkyRUTq06dPvq179+4pItKNN95YZswDDjggtW3bdrV9AWxrXG4HsA2oXbt2mVnusvcmLV26ND777LM4+OCDIyLizTffXK8xs2MsWLAgPvvss+jQoUN8+OGHsWDBgoiI/JmHkSNHxooVK9Y4zvDhw6O4uDiOOeaY+Oyzz/KPtm3bRu3atWPMmDEb9Fw3RO3atSMiyp0BsKioKGrUqBFjx44tc+nfhurZs+d633/UuHHjOPnkk/PLdevWjXPOOScmTZoUs2fPrnAN6/LGG2/E3Llz46KLLipzr9L3v//9aN26dTz99NOrbfPTn/60zPLhhx8eH3744SarEWBLISQBbAMWLVoUderUyS//97//jcsuuywaNmwYRUVFUb9+/WjVqlVERD7grMv48ePj6KOPjlq1asUOO+wQ9evXj5///OdlxujQoUOceuqp0b9//9hpp52iW7duMXTo0Fi2bFl+nGnTpsWCBQuiQYMGUb9+/TKPRYsWxdy5czfWy7CaRYsWRUSUeW2yCgoK4tZbb41nnnkmGjZsGEcccUT86le/2uCwsuq1XR+77rrravcb7b777hERa7x/aWP597//HRERe+yxx2rrWrdunV+/SmFhYf7Sy1W+853vfKswCbC1cE8SwFbuk08+iQULFsSuu+6abzv99NPj5Zdfjquvvjr233//qF27dpSWlkaXLl2itLR0nWNOnz49jjrqqGjdunXccccd0axZs6hRo0b87W9/i4EDB+bHyOVy8dhjj8WECRPiqaeeir///e9x3nnnxe233x4TJkzI77dBgwbx4IMPrnFf3/xBfGOaPHlyVK1ada0h5vLLL48TTjghnnjiifj73/8eN9xwQwwYMCBGjx4dBxxwwHrtZ2PPKrimSRsiYrNOmlCZM/MBVDYhCWAr98c//jEiIjp37hwREZ9//nmMGjUq+vfvH3369Mn3mzZt2mrblvfD+FNPPRXLli2LJ598Mpo3b55vL+/SuIMPPjgOPvjguOWWW+LPf/5znHXWWfHwww/Hj3/849hll13ihRdeiEMPPXSdYaK8eipi5syZMW7cuGjfvn25Z5JW2WWXXeLKK6+MK6+8MqZNmxb7779/3H777fkZAzdmXR988EGklMqM+f7770dE5P9W1Xe+852IiJg/f36ZyRS+ebZnQ2pr0aJFRERMnTo1OnXqVGbd1KlT8+sBcLkdwFZt9OjRcdNNN0WrVq3irLPOioj//wxA+sbfCh80aNBq29eqVSsivv5hPGtNYyxYsCCGDh1apt/nn3++2n7233//iIj8JXenn356rFy5Mm666abV9v/VV1+V2XetWrVWq6Ui/vvf/8aZZ54ZK1euzM/6tiZLliyJpUuXlmnbZZddok6dOmUuGdxYdUVEfPrppzFixIj88sKFC+OBBx6I/fffP0pKSvI1RES8+OKL+X6LFy+O+++/f7Xx1re2Aw88MBo0aBD33HNPmef2zDPPxHvvvRff//73K/qUALY5ziQBbCWeeeaZ+Ne//hVfffVVzJkzJ0aPHh3PP/98tGjRIp588sn8zfh169bN31uzYsWKaNKkSTz33HMxY8aM1cZs27ZtRET84he/iB/+8IdRvXr1OOGEE+LYY4+NGjVqxAknnBAXXHBBLFq0KO69995o0KBBzJo1K7/9/fffH3fffXecfPLJscsuu8QXX3wR9957b9StWzf/B1w7dOgQF1xwQQwYMCDeeuutOPbYY6N69eoxbdq0GD58eNx5553xgx/8IF/P4MGD4+abb45dd901GjRosNpZj296//33409/+lOklGLhwoXx9ttvx/Dhw2PRokVxxx13RJcuXda67VFHHRWnn3567LXXXlGtWrUYMWJEzJkzJ374wx+WeZ02tK7y7L777nH++efH66+/Hg0bNowhQ4bEnDlzygTQY489Npo3bx7nn39+XH311VG1atUYMmRI1K9fP2bOnFlmvPWtrXr16nHrrbdGjx49okOHDnHmmWfmpwBv2bJlXHHFFRV6PgDbpEqdWw+AdVo17fOqR40aNVJJSUk65phj0p133pkWLly42jaffPJJOvnkk9MOO+yQiouL02mnnZY+/fTTFBGpb9++ZfredNNNqUmTJqlKlSplppd+8skn03777ZcKCwtTy5Yt06233pqGDBlSps+bb76ZzjzzzNS8efNUUFCQGjRokI4//vj0xhtvrFbT73//+9S2bdtUVFSU6tSpk/bdd990zTXXpE8//TTfZ/bs2en73/9+qlOnToqIdU4Hnn1dqlSpknbYYYd0wAEHpMsuuyxNmTJltf7fnAL8s88+SxdffHFq3bp1qlWrViouLk7t2rVLjz76aJntyqtrbdOzlzcF+Pe///3097//Pe23336poKAgtW7dOg0fPny17SdOnJjatWuXatSokZo3b57uuOOONY5ZXm3fnAJ8lUceeSQdcMABqaCgINWrVy+dddZZ6ZNPPinTp3v37qlWrVqr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JAEAAGQISQAAABlCEgAAQIaQBAAAkCEkAQAAZAhJAAAAGZUakl588cU44YQTonHjxpHL5eKJJ54os/7cc8+NXC5X5tGlS5fKKRYAANguVGpIWrx4cbRp0ybuuuuucvt06dIlZs2alX889NBDm7FCAABge1OtMnfetWvX6Nq161r7FBQURElJyWaqCAAA2N5t8fckjR07Nho0aBB77LFHXHjhhTFv3ry19l+2bFksXLiwzAMAAGB9bdEhqUuXLvHAAw/EqFGj4tZbb41x48ZF165dY+XKleVuM2DAgCguLs4/mjVrthkrBgAAtnaVernduvzwhz/M/3vfffeN/fbbL3bZZZcYO3ZsHHXUUWvcpnfv3tGrV6/88sKFCwUlAABgvW3RZ5K+aeedd46ddtopPvjgg3L7FBQURN26dcs8AAAA1tdWFZI++eSTmDdvXjRq1KiySwEAALZRlXq53aJFi8qcFZoxY0a89dZbUa9evahXr170798/Tj311CgpKYnp06fHNddcE7vuumt07ty5EqsGAAC2ZZUakt5444048sgj88ur7iXq3r17DB48OP75z3/G/fffH/Pnz4/GjRvHscceGzfddFMUFBRUVskAAMA2rlJDUseOHSOlVO76v//975uxGgAAgK3sniQAAIBNTUgCAADIEJIAAAAyhCQAAIAMIQkAACBDSAIAAMgQkgAAADKEJAAAgAwhCQAAIENIAgAAyBCSAAAAMoQkAACADCEJAAAgQ0gCAADIEJIAAAAyhCQAAICMapVdALB9O/T/HVrZJWzzxl86vrJLADaSW87+QWWXsE37xZ8eq+wS2EI4kwQAAJAhJAEAAGQISQAAABlCEgAAQIaQBAAAkCEkAQAAZAhJAAAAGUISAABAhpAEAACQISQBAABkCEkAAAAZQhIAAECGkAQAAJAhJAEAAGQISQAAABlCEgAAQIaQBAAAkCEkAQAAZAhJAAAAGUISAABAhpAEAACQISQBAABkCEkAAAAZQhIAAECGkAQAAJAhJAEAAGQISQAAABlCEgAAQIaQBAAAkCEkAQAAZAhJAAAAGUISAABAhpAEAACQISQBAABkCEkAAAAZQhIAAECGkAQAAJAhJAEAAGQISQAAABkVCkmdOnWK+fPnr9a+cOHC6NSp07etCQAAoNJUKCSNHTs2li9fvlr70qVL46WXXvrWRQEAAFSWahvS+Z///Gf+3++++27Mnj07v7xy5cp49tlno0mTJhuvOgAAgM1sg0LS/vvvH7lcLnK53BovqysqKor/9//+30YrDgAAYHPboJA0Y8aMSCnFzjvvHK+99lrUr18/v65GjRrRoEGDqFq16kYvEgAAYHPZoJDUokWLiIgoLS3dJMUAAABUtg0KSVnTpk2LMWPGxNy5c1cLTX369PnWhQEAAFSGCoWke++9Ny688MLYaaedoqSkJHK5XH5dLpcTkgAAgK1WhULSzTffHLfccktce+21G7seAACASlWhv5P0+eefx2mnnbaxawEAAKh0FQpJp512Wjz33HMbuxYAAIBKV6HL7Xbddde44YYbYsKECbHvvvtG9erVy6z/2c9+tlGKAwAA2NwqFJJ+//vfR+3atWPcuHExbty4MutyuZyQBAAAbLUqFJJmzJixsesAAADYIlToniQAAIBtVYXOJJ133nlrXT9kyJAKFQMAAFDZKhSSPv/88zLLK1asiMmTJ8f8+fOjU6dOG6UwAACAylChkDRixIjV2kpLS+PCCy+MXXbZ5VsXBQAAUFk22j1JVapUiV69esXAgQM31pAAAACb3UaduGH69Onx1VdfbcwhAQAANqsKXW7Xq1evMssppZg1a1Y8/fTT0b17941SGAAAQGWoUEiaNGlSmeUqVapE/fr14/bbb1/nzHcAAABbsgqFpDFjxmzsOgAAALYIFQpJq/znP/+JqVOnRkTEHnvsEfXr198oRQEAAFSWCk3csHjx4jjvvPOiUaNGccQRR8QRRxwRjRs3jvPPPz+WLFmysWsEAADYbCoUknr16hXjxo2Lp556KubPnx/z58+Pv/71rzFu3Li48sorN3aNAAAAm02FLrd7/PHH47HHHouOHTvm24477rgoKiqK008/PQYPHryx6gMAANisKnQmacmSJdGwYcPV2hs0aOByOwAAYKtWoZDUvn376Nu3byxdujTf9uWXX0b//v2jffv2G604AACAza1Cl9sNGjQounTpEk2bNo02bdpERMTbb78dBQUF8dxzz23UAgEAADanCoWkfffdN6ZNmxYPPvhg/Otf/4qIiDPPPDPOOuusKCoq2qgFAgAAbE4VCkkDBgyIhg0bRs+ePcu0DxkyJP7zn//Etddeu1GKAwAA2NwqdE/S7373u2jduvVq7XvvvXfcc88937ooAACAylKhkDR79uxo1KjRau3169ePWbNmfeuiAAAAKkuFQlKzZs1i/Pjxq7WPHz8+Gjdu/K2LAgAAqCwVuiepZ8+ecfnll8eKFSuiU6dOERExatSouOaaa+LKK6/cqAUCAABsThUKSVdffXXMmzcvLrrooli+fHlERBQWFsa1114bvXv33qgFAgAAbE4VCkm5XC5uvfXWuOGGG+K9996LoqKi2G233aKgoGBj1wcAALBZVSgkrVK7du046KCDNlYtAAAAla5CEzcAAABsq4QkAACADCEJAAAgQ0gCAADIEJIAAAAyhCQAAIAMIQkAACBDSAIAAMgQkgAAADKEJAAAgAwhCQAAIKNSQ9KLL74YJ5xwQjRu3DhyuVw88cQTZdanlKJPnz7RqFGjKCoqiqOPPjqmTZtWOcUCAADbhUoNSYsXL442bdrEXXfdtcb1v/rVr+I3v/lN3HPPPfHqq69GrVq1onPnzrF06dLNXCkAALC9qFaZO+/atWt07dp1jetSSjFo0KC4/vrro1u3bhER8cADD0TDhg3jiSeeiB/+8Idr3G7ZsmWxbNmy/PLChQs3fuEAAMA2a4u9J2nGjBkxe/bsOProo/NtxcXF0a5du3jllVfK3W7AgAFRXFycfzRr1mxzlAsAAGwjttiQNHv27IiIaNiwYZn2hg0b5tetSe/evWPBggX5x8cff7xJ6wQAALYtlXq53aZQUFAQBQUFlV0GAACwldpizySVlJRERMScOXPKtM+ZMye/DgAAYGPbYkNSq1atoqSkJEaNGpVvW7hwYbz66qvRvn37SqwMAADYllXq5XaLFi2KDz74IL88Y8aMeOutt6JevXrRvHnzuPzyy+Pmm2+O3XbbLVq1ahU33HBDNG7cOE466aTKKxoAANimVWpIeuONN+LII4/ML/fq1SsiIrp37x7Dhg2La665JhYvXhw/+clPYv78+XHYYYfFs88+G4WFhZVVMgAAsI2r1JDUsWPHSCmVuz6Xy8WNN94YN95442asCgAA2J5tsfckAQAAVAYhCQAAIENIAgAAyBCSAAAAMoQkAACADCEJAAAgQ0gCAADIEJIAAAAyhCQAAIAMIQkAACBDSAIAAMgQkgAAADKEJAAAgAwhCQAAIENIAgAAyBCSAAAAMoQkAACADCEJAAAgQ0gCAADIEJIAAAAyhCQAAIAMIQkAACBDSAIAAMgQkgAAADKEJAAAgAwhCQAAIENIAgAAyBCSAAAAMoQkAACADCEJAAAgQ0gCAADIEJIAAAAyhCQAAIAMIQkAACBDSAIAAMgQkgAAADKEJAAAgAwhCQAAIENIAgAAyBCSAAAAMoQkAACADCEJAAAgQ0gCAADIEJIAAAAyhCQAAIAMIQkAACBDSAIAAMgQkgAAADKEJAAAgAwhCQAAIENIAgAAyBCSAAAAMoQkAACADCEJAAAgQ0gCAADIEJIAAAAyhCQAAIAMIQkAACBDSAIAAMgQkgAAADKEJAAAgAwhCQAAIKNaZRcAAGxev73yqcouYZt2ye0nVHYJbGHeu2V0ZZewzdvzF5026njOJAEAAGQISQAAABlCEgAAQIaQBAAAkCEkAQAAZAhJAAAAGUISAABAhpAEAACQISQBAABkCEkAAAAZQhIAAECGkAQAAJAhJAEAAGQISQAAABlCEgAAQIaQBAAAkCEkAQAAZAhJAAAAGUISAABAhpAEAACQISQBAABkCEkAAAAZQhIAAECGkAQAAJAhJAEAAGQISQAAABlCEgAAQIaQBAAAkCEkAQAAZAhJAAAAGUISAABAhpAEAACQISQBAABkCEkAAAAZQhIAAECGkAQAAJAhJAEAAGQISQAAABlCEgAAQIaQBAAAkCEkAQAAZAhJAAAAGVt0SOrXr1/kcrkyj9atW1d2WQAAwDasWmUXsC577713vPDCC/nlatW2+JIBAICt2BafOKpVqxYlJSWVXQYAALCd2KIvt4uImDZtWjRu3Dh23nnnOOuss2LmzJlr7b9s2bJYuHBhmQcAAMD62qJDUrt27WLYsGHx7LPPxuDBg2PGjBlx+OGHxxdffFHuNgMGDIji4uL8o1mzZpuxYgAAYGu3RYekrl27xmmnnRb77bdfdO7cOf72t7/F/Pnz49FHHy13m969e8eCBQvyj48//ngzVgwAAGzttvh7krJ22GGH2H333eODDz4ot09BQUEUFBRsxqoAAIBtyRZ9JumbFi1aFNOnT49GjRpVdikAAMA2aosOSVdddVWMGzcuPvroo3j55Zfj5JNPjqpVq8aZZ55Z2aUBAADbqC36crtPPvkkzjzzzJg3b17Ur18/DjvssJgwYULUr1+/sksDAAC2UVt0SHr44YcruwQAAGA7s0VfbgcAALC5CUkAAAAZQhIAAECGkAQAAJAhJAEAAGQISQAAABlCEgAAQIaQBAAAkCEkAQAAZAhJAAAAGUISAABAhpAEAACQISQBAABkCEkAAAAZQhIAAECGkAQAAJAhJAEAAGQISQAAABlCEgAAQIaQBAAAkCEkAQAAZAhJAAAAGUISAABAhpAEAACQISQBAABkCEkAAAAZQhIAAECGkAQAAJAhJAEAAGQISQAAABlCEgAAQIaQBAAAkCEkAQAAZAhJAAAAGUISAABAhpAEAACQISQBAABkCEkAAAAZQhIAAECGkAQAAJAhJAEAAGQISQAAABlCEgAAQIaQBAAAkCEkAQAAZAhJAAAAGUISAABAhpAEAACQISQBAABkCEkAAAAZQhIAAECGkAQAAJAhJAEAAGQISQAAABlCEgAAQIaQBAAAkCEkAQAAZAhJAAAAGUISAABAhpAEAACQISQBAABkCEkAAAAZQhIAAECGkAQAAJAhJAEAAGQISQAAABlCEgAAQIaQBAAAkCEkAQAAZAhJAAAAGUISAABAhpAEAACQISQBAABkCEkAAAAZQhIAAECGkAQAAJAhJAEAAGQISQAAABlCEgAAQIaQBAAAkCEkAQAAZAhJAAAAGUISAABAhpAEAACQISQBAABkCEkAAAAZQhIAAECGkAQAAJAhJAEAAGQISQAAABlCEgAAQIaQBAAAkCEkAQAAZAhJAAAAGUISAABAhpAEAACQISQBAABkCEkAAAAZQhIAAECGkAQAAJAhJAEAAGQISQAAABlCEgAAQIaQBAAAkCEkAQAAZAhJAAAAGVtFSLrrrruiZcuWUVhYGO3atYvXXnutsksCAAC2UVt8SHrkkUeiV69e0bdv33jzzTejTZs20blz55g7d25llwYAAGyDtviQdMcdd0TPnj2jR48esddee8U999wTNWvWjCFDhlR2aQAAwDaoWmUXsDbLly+PiRMnRu/evfNtVapUiaOPPjpeeeWVNW6zbNmyWLZsWX55wYIFERGxcOHC9drnymVffouKWR/reyw21BdLV26ScfnapjpuX3351SYZl//fpjp2i79y7Da1TXXsvly2ZJOMy9c21XGLiFi6YsUmG5tNd+wWLV28Scbl/7e+x25Vv5TSWvvl0rp6VKJPP/00mjRpEi+//HK0b98+337NNdfEuHHj4tVXX11tm379+kX//v03Z5kAAMBW5OOPP46mTZuWu36LPpNUEb17945evXrll0tLS+O///1v7LjjjpHL5Sqxso1v4cKF0axZs/j444+jbt26lV0OG8Cx23o5dlsnx23r5dhtvRy7rde2fOxSSvHFF19E48aN19pviw5JO+20U1StWjXmzJlTpn3OnDlRUlKyxm0KCgqioKCgTNsOO+ywqUrcItStW3ebewNvLxy7rZdjt3Vy3LZejt3Wy7Hbem2rx664uHidfbboiRtq1KgRbdu2jVGjRuXbSktLY9SoUWUuvwMAANhYtugzSRERvXr1iu7du8eBBx4Y3/ve92LQoEGxePHi6NGjR2WXBgAAbIO2+JB0xhlnxH/+85/o06dPzJ49O/bff/949tlno2HDhpVdWqUrKCiIvn37rnZ5IVs+x27r5dhtnRy3rZdjt/Vy7LZejt0WPrsdAADA5rZF35MEAACwuQlJAAAAGUISAABAhpAEAACQISRtATp27BiXX375au3Dhg3b5v8Q7rbi3HPPjVwuF7lcLqpXrx4NGzaMY445JoYMGRKlpaWr9e/cuXNUrVo1Xn/99bWOVaNGjdh1113jxhtvjK+++mpzPJWtyosvvhgnnHBCNG7cOHK5XDzxxBPl9v3pT38auVwuBg0atNYx582bF126dInGjRtHQUFBNGvWLC655JJYuHBhvs/YsWPzxyj7mD179lrH/stf/hLHHnts7LjjjpHL5eKtt94qt29KKbp27brO57WtGzBgQBx00EFRp06daNCgQZx00kkxderUMn1mz54dP/rRj6KkpCRq1aoV3/3ud+Pxxx9f67hvv/12nHnmmdGsWbMoKiqKPffcM+68887V+j344IPRpk2bqFmzZjRq1CjOO++8mDdv3kZ9jluTdX3m1vS5yOVycdttt6113J/97GfRtm3bKCgoiP3333+19f369VvjuLVq1fpW9X6bmrdl6/O5W7p0aVx88cWx4447Ru3atePUU0+NOXPmrHXcsWPHRrdu3aJRo0ZRq1at2H///ePBBx9crd/w4cOjdevWUVhYGPvuu2/87W9/26jPb2uzrvdxSin69OkTjRo1iqKiojj66KNj2rRpax1zfb8Dly1bFr/4xS+iRYsWUVBQEC1btowhQ4asdez1ef9ERLzyyivRqVOnqFWrVtStWzeOOOKI+PLLL9f9gmwmQtJWavny5ZVdAt/QpUuXmDVrVnz00UfxzDPPxJFHHhmXXXZZHH/88WUCzsyZM+Pll1+OSy65pNwvmlVjTZs2La688sro16/fdv0fdnkWL14cbdq0ibvuumut/UaMGBETJkyIxo0br3PMKlWqRLdu3eLJJ5+M999/P4YNGxYvvPBC/PSnP12t79SpU2PWrFn5R4MGDdZZ72GHHRa33nrrOusYNGhQ5HK5dfbb1o0bNy4uvvjimDBhQjz//POxYsWKOPbYY2Px4sX5Puecc05MnTo1nnzyyXjnnXfilFNOidNPPz0mTZpU7rgTJ06MBg0axJ/+9KeYMmVK/OIXv4jevXvHb3/723yf8ePHxznnnBPnn39+TJkyJYYPHx6vvfZa9OzZc5M+5y3Zuj5z2c/DrFmzYsiQIZHL5eLUU09d59jnnXdenHHGGWtcd9VVV6029l577RWnnXbat6r329a8rVqfz90VV1wRTz31VAwfPjzGjRsXn376aZxyyilrHffll1+O/fbbLx5//PH45z//GT169IhzzjknRo4cWabPmWeeGeeff35MmjQpTjrppDjppJNi8uTJm+z5bunW9T7+1a9+Fb/5zW/innvuiVdffTVq1aoVnTt3jqVLl5Y75vp8B0ZEnH766TFq1Kj4wx/+EFOnTo2HHnoo9thjj7XWuz7vn1deeSW6dOkSxx57bLz22mvx+uuvxyWXXBJVqmxB0SRR6Tp06JAuu+yy1dqHDh2aiouLU0opde/ePXXr1i3dfPPNqVGjRqlly5YppZRmzpyZTjvttFRcXJy+853vpBNPPDHNmDEjP8Zrr72Wjj766LTjjjumunXrpiOOOCJNnDhxMzyr7cuq4/NNo0aNShGR7r333nxbv3790g9/+MP03nvvpeLi4rRkyZJ1jnXMMcekgw8+eFOUvs2IiDRixIjV2j/55JPUpEmTNHny5NSiRYs0cODADR77zjvvTE2bNs0vjxkzJkVE+vzzzytU64wZM1JEpEmTJq1x/aRJk1KTJk3SrFmzyn1e26u5c+emiEjjxo3Lt9WqVSs98MADZfrVq1evzOdufVx00UXpyCOPzC/fdtttaeeddy7T5ze/+U1q0qRJBSrf9qzPe7Nbt26pU6dO6z1m3759U5s2bdbZ76233koRkV588cX1Hnt9P0sbWvP24Jufu/nz56fq1aun4cOH5/u89957KSLSK6+8skFjH3fccalHjx755dNPPz19//vfL9OnXbt26YILLvgWz2Db8c33cWlpaSopKUm33XZbvm3+/PmpoKAgPfTQQxs09je/A5955plUXFyc5s2b961qXtP3drt27dL111//rcbd1LaguMa6jBo1KqZOnRrPP/98jBw5MlasWBGdO3eOOnXqxEsvvRTjx4+P2rVrR5cuXfJnmr744ovo3r17/OMf/4gJEybEbrvtFscdd1x88cUXlfxstg+dOnWKNm3axF/+8peI+PqU+NChQ+Pss8+O1q1bx6677hqPPfbYOscpKipy9rACSktL40c/+lFcffXVsffee1dojE8//TT+8pe/RIcOHVZbt//++0ejRo3imGOOifHjx3/bciMiYsmSJfE///M/cdddd0VJSclGGXNbsmDBgoiIqFevXr7tkEMOiUceeST++9//RmlpaTz88MOxdOnS6Nix4waPnR23ffv28fHHH8ff/va3SCnFnDlz4rHHHovjjjtuozyXbd2cOXPi6aefjvPPP3+jj33ffffF7rvvHocffvhGHXdT1rw1++bnbuLEibFixYo4+uij831at24dzZs3j1deeWWDx85+7l555ZUy40Z8fYn6ho67vZgxY0bMnj27zGtWXFwc7dq1+9bH4sknn4wDDzwwfvWrX0WTJk1i9913j6uuumqDL4n75vtn7ty58eqrr0aDBg3ikEMOiYYNG0aHDh3iH//4xwaNu6kJSVuRWrVqxX333Rd777137L333vHII49EaWlp3HfffbHvvvvGnnvuGUOHDo2ZM2fG2LFjI+LrH9JX/UC+5557xu9///tYsmRJjBs3rnKfzHakdevW8dFHH0VExAsvvBBLliyJzp07R0TE2WefHX/4wx/K3TalFC+88EL8/e9/j06dOm2Ocrcpt956a1SrVi1+9rOfbfC2Z555ZtSsWTOaNGkSdevWjfvuuy+/rlGjRnHPPffE448/Ho8//ng0a9YsOnbsGG+++ea3rvmKK66IQw45JLp16/atx9rWlJaWxuWXXx6HHnpo7LPPPvn2Rx99NFasWBE77rhjFBQUxAUXXBAjRoyIXXfddb3Hfvnll+ORRx6Jn/zkJ/m2Qw89NB588ME444wzokaNGlFSUhLFxcXrvLyTr91///1Rp06ddV6CtaGWLl0aDz744CYJMpuq5q3Zmj53s2fPjho1aqx233TDhg3XeW9m1qOPPhqvv/569OjRI982e/bsaNiw4bcad3uy6nX5tq/Zmr4DP/zww/jHP/4RkydPjhEjRsSgQYPisccei4suumi9x13T++fDDz+MiK/vNezZs2c8++yz8d3vfjeOOuqodd5LtTkJSVuRfffdN2rUqJFffvvtt+ODDz6IOnXqRO3ataN27dpRr169WLp0aUyfPj0ivv6tWM+ePWO33XaL4uLiqFu3bixatChmzpxZWU9ju5NSyt9bMmTIkDjjjDOiWrVqEfH1D+Ljx4/PH69VRo4cGbVr147CwsLo2rVrnHHGGdGvX7/NXfpWbeLEiXHnnXfGsGHDyr23p2vXrvnPzjfPNA0cODDefPPN+Otf/xrTp0+PXr165dftscceccEFF0Tbtm3jkEMOiSFDhsQhhxwSAwcOjIivb/ZfNW7t2rXjpZdeWq+an3zyyRg9evQ6J5fYXl188cUxefLkePjhh8u033DDDTF//vx44YUX4o033ohevXrF6aefHu+8805ErP04R0RMnjw5unXrFn379o1jjz023/7uu+/GZZddFn369ImJEyfGs88+Gx999NEa709jdUOGDImzzjorCgsL823rOhbrY8SIEfmrJFZ56aWXynzm1jQZQEVr3t6V97lbl7333jt/PLp27bra+jFjxkSPHj3i3nvvrfB7gfVT0e/A0tLSyOVy8eCDD8b3vve9OO644+KOO+6I+++/P7788sv1+tyt6f2zakKrCy64IHr06BEHHHBADBw4MPbYY491TgqxOVWr7AKIqFu3bv5UZNb8+fOjuLg4v/zNWXwWLVoUbdu2XeObsn79+hER0b1795g3b17ceeed+ZlJ2rdv79Ktzei9996LVq1axX//+98YMWJErFixIgYPHpxfv3LlyhgyZEjccsst+bYjjzwyBg8eHDVq1IjGjRvnQxXr76WXXoq5c+dG8+bN820rV66MK6+8MgYNGhQfffRR3HffffnLBqpXr15m+5KSkigpKYnWrVtHvXr14vDDD48bbrghGjVqtMb9fe9738tfKnDiiSdGu3bt8uuaNGmyXjWPHj06pk+fvtpvZ0899dQ4/PDD82eIt0eXXHJJjBw5Ml588cVo2rRpvn369Onx29/+NiZPnpz/z79Nmzbx0ksvxV133RX33HPPWo/zu+++G0cddVT85Cc/ieuvv77MugEDBsShhx4aV199dURE7LffflGrVq04/PDD4+abby73vcDXn7+pU6fGI488UqZ9bcdifd13331x/PHHl/nN+YEHHlhmtshv/lb929S8PSvvc1dSUhLLly+P+fPnl/m+mjNnTv4y4b/97W+xYsWKiPj6kvGscePGxQknnBADBw6Mc845p8y6kpKS1WbJy45LWatelzlz5pT5TpozZ05+psiKfgc2atQomjRpUuZn0T333DNSSvHJJ5+s83NX3vtnVZ177bVXmf577rnnFvVLfD95bQH22GOPeO6551Zrf/PNN2P33Xcvd7vvfve78cgjj0SDBg2ibt26a+wzfvz4uPvuu/PX0H/88cfx2WefbZzCWafRo0fHO++8E1dccUU8+OCD0bRp09Wm7nzuuefi9ttvjxtvvDGqVq0aEV8H4g25VIjV/ehHP1rjde0/+tGP8pd2rG94WfVbr2XLlpXb56233sp/8depUyfq1KmzwTVfd9118eMf/7hM27777hsDBw6ME044YYPH2xaklOLSSy+NESNGxNixY6NVq1Zl1i9ZsiQiYrUZkapWrZo/buUd5ylTpkSnTp2ie/fuZX5JkR37m7+gWPUZTSlV7AltJ/7whz9E27Zto02bNmXa1/czV54ZM2bEmDFj4sknnyzTXlRU9K2/M8ureXu0rs9d27Zto3r16jFq1Kj8LIBTp06NmTNnRvv27SMiokWLFmsce+zYsXH88cfHrbfeWubSrlXat28fo0aNKvOnUZ5//vn8uJTVqlWrKCkpiVGjRuVD0cKFC+PVV1+NCy+8MCIq/h146KGHxvDhw2PRokVRu3btiIh4//33o0qVKtG0adNyP3frev+0bNkyGjduvNq04O+///4azzpWmkqbMoK86dOnp8LCwnTppZemt99+O/3rX/9Kt99+e6pWrVp65plnUkprnvFs8eLFabfddksdO3ZML774Yvrwww/TmDFj0qWXXpo+/vjjlFJKBxxwQDrmmGPSu+++myZMmJAOP/zwVFRUVKEZvihf9+7dU5cuXdKsWbPSJ598kiZOnJhuueWWVLt27XT88cenr776KrVp0yZde+21q207f/78VKNGjTRy5Mj8WGuaKY/VffHFF2nSpElp0qRJKSLSHXfckSZNmpT+/e9/r7H/+sxu9/TTT6chQ4akd955J82YMSONHDky7bnnnunQQw/N9xk4cGB64okn0rRp09I777yTLrvsslSlSpX0wgsvrHXsefPmpUmTJqWnn346RUR6+OGH06RJk9KsWbPK3Sa289ntLrzwwlRcXJzGjh2bZs2alX+smhVy+fLladddd02HH354evXVV9MHH3yQfv3rX6dcLpeefvrpcsd95513Uv369dPZZ59dZty5c+fm+wwdOjRVq1Yt3X333Wn69OnpH//4RzrwwAPT9773vU3+vLdU6/OZW7BgQapZs2YaPHjweo87bdq0NGnSpHTBBRek3XffPb+PZcuWlel3/fXXp8aNG6evvvpqo9Vb0Zq3Zev63KWU0k9/+tPUvHnzNHr06PTGG2+k9u3bp/bt26913NGjR6eaNWum3r17lxk3O3va+PHjU7Vq1dKvf/3r9N5776W+ffum6tWrp3feeWeTPd8t3brex7/85S/TDjvskP7617+mf/7zn6lbt26pVatW6csvvyx3zPX5Dvziiy9S06ZN0w9+8IM0ZcqUNG7cuLTbbrulH//4x2utd33ePwMHDkx169ZNw4cPT9OmTUvXX399KiwsTB988MG3fLU2HiFpC/Haa6+lY445JtWvXz8VFxendu3alfnBqLwfnGfNmpXOOeectNNOO6WCgoK08847p549e6YFCxaklFJ6880304EHHpgKCwvTbrvtloYPH17haZApX/fu3VNEpIhI1apVS/Xr109HH310GjJkSFq5cmV64403UkSk1157bY3bd+3aNZ188sn5sYSk9bNqKu5vPrp3777G/uvz3h89enRq3759Ki4uzn9urr322jLTfd96661pl112SYWFhalevXqpY8eOafTo0eusd+jQoWust2/fvuVus72HpDW9XhGRhg4dmu/z/vvvp1NOOSU1aNAg1axZM+23336rTQn+TX379l3juC1atCjT7ze/+U3aa6+9UlFRUWrUqFE666yz0ieffLIJnunWYX0+c7/73e9SUVFRmj9//nqP26FDhzWOm/2TFitXrkxNmzZNP//5zzdqvRWteVu2Pp+7L7/8Ml100UXpO9/5TqpZs2Y6+eST1/oLn5TK/l+ZfXTo0KFMv0cffTTtvvvuqUaNGmnvvfde6y88tgfreh+XlpamG264ITVs2DAVFBSko446Kk2dOnWtY67vd+B7772Xjj766FRUVJSaNm2aevXqtdqfLvmm9Xn/pJTSgAEDUtOmTVPNmjVT+/bt00svvbShL80mlUvJNQMAAACrmN0OAAAgQ0gCAADIEJIAAAAyhCQAAIAMIQkAACBDSAIAAMgQkgAAADKEJAAAgAwhCYAtQseOHePyyy/PL7ds2TIGDRqUX87lcvHEE09s9roA2P4ISQCU69xzz41cLrfa44MPPqjwmGPHjo1cLhfz588v0/6Xv/wlbrrppnK3mzVrVnTt2rXC+62oXC4XhYWF8e9//7tM+0knnRTnnnvuZq8HgE1PSAJgrbp06RKzZs0q82jVqlWFxlqxYkW56+rVqxd16tQpd31JSUkUFBRUaL/rklKKr776qtz1uVwu+vTps0n2DcCWR0gCYK0KCgqipKSkzKNq1aoREfHXv/41vvvd70ZhYWHsvPPO0b9//zJhI5fLxeDBg+PEE0+MWrVqRc+ePePII4+MiIjvfOc7kcvl8mdjvnm53TdlL7fr16/fGs9wDRs2LCIiSktLY8CAAdGqVasoKiqKNm3axGOPPZYfa9XZrGeeeSbatm0bBQUF8Y9//KPcfV9yySXxpz/9KSZPnlxun2effTYOO+yw2GGHHWLHHXeM448/PqZPn55f/9FHH0Uul4tHH300Dj/88CgqKoqDDjoo3n///Xj99dfjwAMPjNq1a0fXrl3jP//5T5mx77vvvthzzz2jsLAwWrduHXfffXe5dQDw7QlJAFTISy+9FOecc05cdtll8e6778bvfve7GDZsWNxyyy1l+vXr1y9OPvnkeOedd6J///7x+OOPR0TE1KlTY9asWXHnnXdu8L6vuuqqMme2fv3rX0fNmjXjwAMPjIiIAQMGxAMPPBD33HNPTJkyJa644oo4++yzY9y4cWXGue666+KXv/xlvPfee7HffvuVu79DDz00jj/++LjuuuvK7bN48eLo1atXvPHGGzFq1KioUqVKnHzyyVFaWlqmX9++feP666+PN998M6pVqxb/8z//E9dcc03ceeed8dJLL8UHH3xQ5qzVgw8+GH369Ilbbrkl3nvvvfjf//3fuOGGG+L+++/f4NcNgPWUAKAc3bt3T1WrVk21atXKP37wgx+klFI66qij0v/+7/+W6f/HP/4xNWrUKL8cEenyyy8v02fMmDEpItLnn39epr1Dhw7psssuyy+3aNEiDRw4sMxYI0aMWK3GV155JRUWFqZHHnkkpZTS0qVLU82aNdPLL79cpt/555+fzjzzzDI1PPHEE+t8DVbtd8qUKalq1arpxRdfTCml1K1bt9S9e/dyt/vPf/6TIiK98847KaWUZsyYkSIi3Xffffk+Dz30UIqINGrUqHzbgAED0h577JFf3mWXXdKf//znMmPfdNNNqX379uusHYCKqVZ58QyArcGRRx4ZgwcPzi/XqlUrIiLefvvtGD9+fJkzRytXroylS5fGkiVLombNmhER+bM7m8LMmTPjpJNOiquuuipOP/30iIj44IMPYsmSJXHMMceU6bt8+fI44IADyrRtSG177bVXnHPOOXHdddfF+PHjV1s/bdq06NOnT7z66qvx2Wef5c8gzZw5M/bZZ598v+wZq4YNG0ZExL777lumbe7cuRHx9dmp6dOnx/nnnx89e/bM9/nqq6+iuLh4vWsHYMMISQCsVa1atWLXXXddrX3RokXRv3//OOWUU1ZbV1hYWGb7TWHx4sVx4oknRvv27ePGG28sU1dExNNPPx1NmjQps803J37Y0Nr69+8fu++++xqnIj/hhBOiRYsWce+990bjxo2jtLQ09tlnn1i+fHmZftWrV8//O5fLrbFtVcBa9VzuvffeaNeuXZlxVt0XBsDGJyQBUCHf/e53Y+rUqWsMUGtTo0aNiPj6rFNFpZTi7LPPjtLS0vjjH/+YDxsRX5/xKSgoiJkzZ0aHDh0qvI81adasWVxyySXx85//PHbZZZd8+7x582Lq1Klx7733xuGHHx4RsdaJINZXw4YNo3HjxvHhhx/GWWed9a3HA2D9CEkAVEifPn3i+OOPj+bNm8cPfvCDqFKlSrz99tsxefLkuPnmm8vdrkWLFpHL5WLkyJFx3HHHRVFRUdSuXXuD9t2vX7944YUX4rnnnotFixblz7gUFxdHnTp14qqrroorrrgiSktL47DDDosFCxbE+PHjo27dutG9e/dv9bx79+4d9957b8yYMSPOOOOMiPh6pr4dd9wxfv/730ejRo1i5syZa53kYUP0798/fvazn0VxcXF06dIlli1bFm+88UZ8/vnn0atXr42yDwDKMrsdABXSuXPnGDlyZDz33HNx0EEHxcEHHxwDBw6MFi1arHW7Jk2aRP/+/eO6666Lhg0bxiWXXLLB+x43blwsWrQoDjnkkGjUqFH+8cgjj0RExE033RQ33HBDDBgwIPbcc8/o0qVLPP300xX++05Z9erVi2uvvTaWLl2ab6tSpUo8/PDDMXHixNhnn33iiiuuiNtuu+1b7ysi4sc//nHcd999MXTo0Nh3332jQ4cOMWzYsI3yXABYs1xKKVV2EQAAAFsKZ5IAAAAyhCQAAIAMIQkAACBDSAIAAMgQkgAAADKEJAAAgAwhCQAAIENIAgAAyBCSAAAAMoQkAACADCEJAAAg4/8DkDqrpYigst4AAAAASUVORK5CYII=",
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# checking the data distribution \n",
"plt.figure(figsize=(10, 7))\n",
"\n",
"sns.countplot(data=df, x='Fertilizer Name')\n",
"plt.title(\"Dataset Distribution\")\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array(['Sandy', 'Loamy', 'Black', 'Red', 'Clayey'], dtype=object)"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# soil type\n",
"df['Soil Type'].unique()"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array(['Maize', 'Sugarcane', 'Cotton', 'Tobacco', 'Paddy', 'Barley',\n",
" 'Wheat', 'Millets', 'Oil seeds', 'Pulses', 'Ground Nuts'],\n",
" dtype=object)"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df['Crop Type'].unique()"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Shape of the training dataset: (79, 8)\n",
"Shape of the testing dataset: (20, 8)\n"
]
}
],
"source": [
"# splitting the dataset \n",
"X = df.drop(columns=[\"Fertilizer Name\"])\n",
"y = df[\"Fertilizer Name\"]\n",
"\n",
"X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)\n",
"\n",
"print(f\"Shape of the training dataset: {X_train.shape}\")\n",
"print(f\"Shape of the testing dataset: {X_test.shape}\")"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['Temparature', 'Humidity ', 'Moisture', 'Nitrogen', 'Potassium', 'Phosphorous']\n"
]
}
],
"source": [
"# numerical columns in the dataset\n",
"print(df._get_numeric_data().columns.tolist())"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"['Soil Type', 'Crop Type']"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# segrating categorical columns\n",
"categorical_columns = [i for i in df.columns if (i not in df._get_numeric_data().columns) & (i !='Fertilizer Name')]\n",
"categorical_columns"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Encoding"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"ohe = OneHotEncoder(drop='first')\n",
"standard_scaler = StandardScaler()\n",
"\n",
"preprocessor = ColumnTransformer(\n",
" transformers =[\n",
" ('StandaradScaling', standard_scaler, df._get_numeric_data().columns),\n",
" ('One_hot_encoding', ohe, categorical_columns)\n",
" ],\n",
" remainder='passthrough'\n",
")\n",
"\n",
"pipeline = Pipeline([\n",
" ('preprocess', preprocessor)\n",
"])"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [],
"source": [
"X_train_transformed = pipeline.fit_transform(X_train)\n",
"X_test_transformed = pipeline.transform(X_test)"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
"le = LabelEncoder()\n",
"\n",
"y_train_transformed = le.fit_transform(y_train)\n",
"y_test_transformed = le.transform(y_test)"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [],
"source": [
"def evaluate_clf(true, predicted):\n",
" '''\n",
" This function takes in true values and predicted values\n",
" Returns: Accuracy, F1-Score, Precision, Recall, Roc-auc Score\n",
" '''\n",
" acc = accuracy_score(true, predicted)\n",
" f1 = f1_score(true, predicted, average='weighted')\n",
" precision = precision_score(true, predicted, average='weighted')\n",
" recall = recall_score(true, predicted, average='weighted')\n",
" \n",
" return acc, f1, precision, recall"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [],
"source": [
"# create a function which can evaluate models and returns a report \n",
"def evaluate_model(X_train, X_test, y_train, y_test, models):\n",
" '''\n",
" This function takes X_train, X_test, y_train, y_test and models dictionary as input\n",
" Iterate through the given model directory and evaluate metrics\n",
"\n",
" Returns:\n",
" DataFrame which contains report of all models metrics \n",
" '''\n",
"\n",
" model_list = []\n",
" metric_list = []\n",
"\n",
" for i in range(len(list(models))):\n",
" model = list(models.values())[i]\n",
" model.fit(X_train, y_train)\n",
"\n",
" # Make predictions\n",
" y_train_pred = model.predict(X_train)\n",
" y_test_pred = model.predict(X_test)\n",
"\n",
" # Training set performances\n",
" model_train_accuracy, model_train_f1, model_train_precision, \\\n",
" model_train_recall = evaluate_clf(y_train, y_train_pred)\n",
"\n",
" # Test set peformances \n",
" model_test_accuracy, model_test_f1, model_test_precision, \\\n",
" model_test_recall = evaluate_clf(y_test, y_test_pred)\n",
"\n",
" print(list(models.keys())[i])\n",
" model_list.append(list(models.keys())[i])\n",
"\n",
" result_dict ={'model_name':list(models.keys())[i], \n",
" \"train_accuracy\": model_train_accuracy, \"test_accuracy\": model_test_accuracy,\n",
" \"train_precision\": model_train_precision, \"test_precision\": model_test_precision,\n",
" 'train_recall': model_train_recall, \"test_recall\":model_test_recall,\n",
" \"train_f1_score\": model_train_f1, \"test_f1_score\": model_test_f1}\n",
"\n",
" metric_list.append(result_dict)\n",
"\n",
" \n",
" return metric_list\n"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [],
"source": [
"# Model Dictionary\n",
"models = {\n",
" \"Random Forest\": RandomForestClassifier(),\n",
" \"Decision Tree\": DecisionTreeClassifier(),\n",
" \"Gradient Boosting\": GradientBoostingClassifier(),\n",
" \"K-Neighbors Classifier\": KNeighborsClassifier(),\n",
" \"XGBClassifier\": XGBClassifier(), \n",
" \"CatBoosting Classifier\": CatBoostClassifier(verbose=False),\n",
" \"AdaBoost Classifier\": AdaBoostClassifier()\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Random Forest\n",
"Decision Tree\n",
"Gradient Boosting\n",
"K-Neighbors Classifier\n",
"XGBClassifier\n",
"CatBoosting Classifier\n",
"AdaBoost Classifier\n"
]
}
],
"source": [
"resultant_metrics = evaluate_model(X_train_transformed, X_test_transformed, y_train_transformed, y_test_transformed, models)\n",
"\n",
"resultant_metrics_df = pd.DataFrame(data=resultant_metrics)"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" model_name | \n",
" train_accuracy | \n",
" test_accuracy | \n",
" train_precision | \n",
" test_precision | \n",
" train_recall | \n",
" test_recall | \n",
" train_f1_score | \n",
" test_f1_score | \n",
"
\n",
" \n",
" \n",
" \n",
" 1 | \n",
" Decision Tree | \n",
" 1.000000 | \n",
" 1.00 | \n",
" 1.000000 | \n",
" 1.000000 | \n",
" 1.000000 | \n",
" 1.00 | \n",
" 1.000000 | \n",
" 1.000000 | \n",
"
\n",
" \n",
" 4 | \n",
" XGBClassifier | \n",
" 1.000000 | \n",
" 1.00 | \n",
" 1.000000 | \n",
" 1.000000 | \n",
" 1.000000 | \n",
" 1.00 | \n",
" 1.000000 | \n",
" 1.000000 | \n",
"
\n",
" \n",
" 5 | \n",
" CatBoosting Classifier | \n",
" 1.000000 | \n",
" 1.00 | \n",
" 1.000000 | \n",
" 1.000000 | \n",
" 1.000000 | \n",
" 1.00 | \n",
" 1.000000 | \n",
" 1.000000 | \n",
"
\n",
" \n",
" 0 | \n",
" Random Forest | \n",
" 1.000000 | \n",
" 0.95 | \n",
" 1.000000 | \n",
" 1.000000 | \n",
" 1.000000 | \n",
" 0.95 | \n",
" 1.000000 | \n",
" 0.966667 | \n",
"
\n",
" \n",
" 2 | \n",
" Gradient Boosting | \n",
" 1.000000 | \n",
" 0.95 | \n",
" 1.000000 | \n",
" 0.975000 | \n",
" 1.000000 | \n",
" 0.95 | \n",
" 1.000000 | \n",
" 0.955556 | \n",
"
\n",
" \n",
" 6 | \n",
" AdaBoost Classifier | \n",
" 0.594937 | \n",
" 0.70 | \n",
" 0.477918 | \n",
" 0.657143 | \n",
" 0.594937 | \n",
" 0.70 | \n",
" 0.504147 | \n",
" 0.662500 | \n",
"
\n",
" \n",
" 3 | \n",
" K-Neighbors Classifier | \n",
" 0.898734 | \n",
" 0.65 | \n",
" 0.904539 | \n",
" 0.666667 | \n",
" 0.898734 | \n",
" 0.65 | \n",
" 0.897599 | \n",
" 0.647727 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" model_name train_accuracy test_accuracy train_precision \\\n",
"1 Decision Tree 1.000000 1.00 1.000000 \n",
"4 XGBClassifier 1.000000 1.00 1.000000 \n",
"5 CatBoosting Classifier 1.000000 1.00 1.000000 \n",
"0 Random Forest 1.000000 0.95 1.000000 \n",
"2 Gradient Boosting 1.000000 0.95 1.000000 \n",
"6 AdaBoost Classifier 0.594937 0.70 0.477918 \n",
"3 K-Neighbors Classifier 0.898734 0.65 0.904539 \n",
"\n",
" test_precision train_recall test_recall train_f1_score test_f1_score \n",
"1 1.000000 1.000000 1.00 1.000000 1.000000 \n",
"4 1.000000 1.000000 1.00 1.000000 1.000000 \n",
"5 1.000000 1.000000 1.00 1.000000 1.000000 \n",
"0 1.000000 1.000000 0.95 1.000000 0.966667 \n",
"2 0.975000 1.000000 0.95 1.000000 0.955556 \n",
"6 0.657143 0.594937 0.70 0.504147 0.662500 \n",
"3 0.666667 0.898734 0.65 0.897599 0.647727 "
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"resultant_metrics_df = resultant_metrics_df.sort_values(by='test_f1_score', ascending=False)\n",
"resultant_metrics_df"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3.8.10 64-bit",
"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.8.10"
},
"orig_nbformat": 4,
"vscode": {
"interpreter": {
"hash": "e7370f93d1d0cde622a1f8e1c04877d8463912d04d973331ad4851f04de6915a"
}
}
},
"nbformat": 4,
"nbformat_minor": 2
}