great-ai/docs/examples/simple/train.ipynb

894 lines
84 KiB
Text

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Optimise and train a model\n",
"\n",
"![position of this step in the lifecycle](/media/scope-train.svg)\n",
"> The blue boxes show the steps implemented in this notebook.\n",
"\n",
"In the first part, we have cleaned and transformed our training data. We can now access this data using `great_ai.LargeFile`. Locally, it will gives us the cached version, otherwise, the latest version is downloaded from S3 or GridFS. \n",
"\n",
"In this part, we hyperparameter-optimise and train a simple, Naive Bayes classifier which we then export for deployment using `great_ai.save_model`.\n",
"\n",
"## Load data that has been extracted in [part 1](/examples/simple/data)"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"\u001b[38;5;226mEnvironment variable ENVIRONMENT is not set, defaulting to development mode ‼️\u001b[0m\n",
"\u001b[38;5;226mCannot find credentials files, defaulting to using ParallelTinyDbDriver\u001b[0m\n",
"\u001b[38;5;226mThe selected tracing database (ParallelTinyDbDriver) is not recommended for production\u001b[0m\n",
"\u001b[38;5;226mCannot find credentials files, defaulting to using LargeFileLocal\u001b[0m\n",
"\u001b[38;5;39mGreatAI (v0.1.4): configured ✅\u001b[0m\n",
"\u001b[38;5;39m 🔩 tracing_database: ParallelTinyDbDriver\u001b[0m\n",
"\u001b[38;5;39m 🔩 large_file_implementation: LargeFileLocal\u001b[0m\n",
"\u001b[38;5;39m 🔩 is_production: False\u001b[0m\n",
"\u001b[38;5;39m 🔩 should_log_exception_stack: True\u001b[0m\n",
"\u001b[38;5;39m 🔩 prediction_cache_size: 512\u001b[0m\n",
"\u001b[38;5;39m 🔩 dashboard_table_size: 50\u001b[0m\n",
"\u001b[38;5;226mYou still need to check whether you follow all best practices before trusting your deployment.\u001b[0m\n",
"\u001b[38;5;226m> Find out more at https://se-ml.github.io/practices\u001b[0m\n"
]
}
],
"source": [
"from great_ai import query_ground_truth\n",
"\n",
"data = query_ground_truth(\"train\")\n",
"X = [d.input for d in data for domain in d.feedback]\n",
"y = [domain for d in data for domain in d.feedback]"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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+zlu27atPD09zY6VK37++We1bdtWzz//vL744gv16dNH69ev19q1ay3zpebq1asKDw/XgQMH9Oijj2rcuHGWuEN8L9WrV9cvv/yiEiVKmB0l193cK6Cg2Lx5s63ZpiRFREQoKSnJck1Vg4KCtG/fPtuyXemPnR8feeQRxcTEmJgMOXXixAmNHz/+tkt3rbbL47Bhw/TQQw/plVdesR376KOPdOjQIX344Yd66623tGHDBu3evdvElM6RmZmpvXv32q6hHn/8ccu2VXjttdd07NgxzZo1S/Xr11dUVJRGjBihqlWr6q233jI7Xq7JKqTBejIzM3Xu3DmVKVPGlN9bikv3UBAavd3Oli1bdODAATVs2FCNGjUyO45TtWvXTqVLl9ZLL72kVatW6fvvv9eHH36ojh07au3atZo4caL2799vdkw4weXLl3XixAk99NBDlt6BKatfQExMjAIDA9WrVy9L3WHs37+/IiIi1Lp1a23cuFHNmjXThx9+aHasXHFzQ80tW7Zow4YN+vvf/55txmGVKlXyOlquGjVqlB5++GH16dPH7ChwMh8fHyUkJNhtFpKRkaFSpUpla4CdH23atEleXl623bWio6PVp08fHThwQI0aNdLChQvtdpCzkkaNGik4OFg9e/bM9hnbtGlTk1LljnvtjJeWlqbSpUtb4mc6y+HDh3Xw4EE9+uijCgoKMjtOrrh+/brGjBmj+fPn69q1a/Lw8NCgQYM0bdo0S9/EorhkPUlJSfrrX/+qlStX6saNGypcuLC6deum2bNny9vbO89yUFy6h6FDhyo2NlZjx45VmzZtdPnyZcXGxqpVq1aKiooyO55TdO/eXS1atNDAgQMlSdOnT9fEiRNVt25dHTx4UHPnzrXU1HVfX1/Fx8fL3d1d165dU8mSJZWWlma7Y367HV+sYMuWLVq5cqXOnz+v9evXW+4u+fTp01W1alV16tRJ0h8X/F26dFFKSop8fHy0ceNGNWjQwOSUcERAQIB+/fVXBQQE6PTp02rSpIllm1K6urrecflfFiv2IXrqqae0d+9eVa5cOVshzYp9IO7W/8Jqr/fJJ5/U3/72N3Xp0sV27KuvvtKMGTP0888/m5jMOR577DHNnj3bdiOuadOmKl68uIYNG6YFCxaoaNGi+vzzz01OmTu8vLx0+fJly85quVmNGjX07rvvqn379rZj69at0+jRo3X48GFduXJFwcHBSkhIMDGl40aNGqVHH31UvXr1kvTHctb+/fvLx8dHKSkp+vrrr20Nr60i6wu49Mf77vnz5+Xr6ys3Nzc98cQTKlTIuq2JKS5ZT9++fZWcnKx33nnHtqR1/Pjx8vDwuOtul85Gcekebt7W/OZfxJIlS+ry5cvmhnOSihUrKiIiQqVLl1ZmZqbKlCmjuXPn6sUXX9S3336rsWPHWqoHRFaz8iy3vsHeOm4FH374oT744AMNHDhQ77zzjq5cuaKoqCgNGjRIu3btMjueU9SoUUPr1q1T9erVJf2xpKhz584aN26c3n//ff3www+W7Mtz6dIlzZgx47bLEqzyJfVev7PI/wrKNt9Zbn29Z8+e1WeffaZevXrddSfT/OjHH3/Uc889p5YtWyo4OFjHjh3TDz/8oI0bN+rJJ580O16OlSpVSufPn1ehQoV0/vx5lStXTjExMSpfvrwSEhJUt25dxcXFmR0zV7Rt21ZTpkxR/fr1zY6S6zZv3qzOnTurdu3atg1+Dhw4oC+//FKtWrXS5s2btXv37nzbaqBKlSravn27KlasKEmqUKGCxo0bp6FDh2rx4sX6+OOPLVEMzvLxxx9r165dWrp0qSSpePHi8vX1lWEYunbtmqZPn64BAwaYnNJ5br3+7dChg9auXWt3I8sqN5sLqrJly+r48eN2s0hTUlIUHBysc+fO5VkOikv3UBAavd38xe2XX37R008/rcuXL8vNzU2GYcjHx8cyhTRJ8vDw0IYNG2xvqLe+wbZr105Xr141M6LTBQcH64cfflClSpXk4+OjxMREZWRkqHTp0rp48aLZ8Zzi5hlnx44dU0hIiC5evChPT0+lpaXZLvStpnXr1kpLS1OXLl2yLUuwypfye/3OSta8KIqNjZWHh4ddr5rExET9/vvvKleunInJkBuOHTumfv366d///rfZUZwuJiZGK1assPVw6dmzp2Ua1fv6+urcuXMqVKiQ1q5dq9dee01Hjx6V9EfjXG9vb8vdsMoyfPhwrVq1Sh07dszWo3Pq1Kkmpco9CQkJ+vbbb20b/Dz//PPy9fU1O5ZT3Pxd4MCBA3rsscd0+fJlFSlSRBkZGfL397fUTZ1GjRpp7ty5qlevniTZro0lad++fXr55Zct0T8rS+XKle867uLiYrcsH/lPpUqVtGPHDrslrCdPnlSTJk3ytAeedef7OUnnzp0VFhamWbNmSZLi4+M1YsQISzV89vPz08mTJ1WpUiVt27ZNjRo1svVGuHr1ql2fBCsoXbq03bblvr6+do9Lly5tRqxclZycbLuQz1qKcePGDbm7u5sZy6k8PDyUlJQkLy8v/fjjj6pbt66tiberq6vS09NNTpg7du3apQsXLli6N8C9fmetelHUoUMHLViwwK64dObMGQ0cOFB79uwxMZnzGYahTz/9VCtWrFBCQoL279+vnTt36uzZs3bLqaysfPnylu33FxQUpNdff93UJqO5JTQ0VLNnz9bAgQP16aef2i0dOn78uPz8/ExMl7uuXr2qtm3b6saNGzp9+rTtuFUb8/v5+alp06aKjY1V+fLlLVNYkv64QZf1+/nvf/9boaGhtuuKGzdu3HWpdn504sQJW2FJkt1uwvXq1bPcNYVVWwng/wwcOFAtW7bUqFGjbMviZs2apcGDB+dpDopL9/D2229rzJgxqlOnjq5du6Zq1app0KBBlpq2PnDgQD3//PN69tlntWTJErtGuTt37lTNmjVNTOd8WVvGFiRNmjTRtGnTNH78eNux2bNn223znt8999xzGjx4sHr06KEZM2bY+gZIsvR27nXr1tWZM2csuV17loL4OytJR44cUZ06deyO1alTR4cOHTIpUe6ZNGmStmzZohEjRugvf/mLpD+WZYwcOdKSxaUFCxbYPb527Zq+/vprNWzY0KREuScpKck2wyU9PV2FChUypclobpk1a5batWun0aNHq2rVqvrkk09sY0uXLlWTJk1MTJe7Fi5caHaEPBMfH69u3brp559/VqlSpXTx4kU1bNhQK1eutMRM0i5duqhbt27q2LGj3nvvPY0dO9Y2tmfPHstdY6SkpOjq1asqXry4JOmnn36yjV29etVyKxhgfePHj1e5cuW0fPlyxcXFqVy5cnr99dftbsbmBZbF3cGt08cyMzOVkJAgPz8/2x23rHXJVrB48WJFRESoYcOG6tmzp91xLy8vdezY0cR0yKn4+Hi1a9dOCQkJio2NVZUqVVSiRAl988032aay51dXrlzRyJEj9Z///EcNGzbURx99ZLvrFh4eLhcXF7vimlVMmjRJK1asUL9+/bL9W+b1Bwqcq2rVqtq0aZOqVq1qO3bs2DG1atXKcndVAwMD9dtvv8nPz8+2PMEwDJUq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",
"text/plain": [
"<Figure size 1440x360 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"from collections import Counter\n",
"import matplotlib.pyplot as plt\n",
"\n",
"domains, counts = zip(*Counter(y).most_common())\n",
"\n",
"# Configure matplotlib to have nice, high-resolution charts\n",
"%matplotlib inline\n",
"plt.rcParams[\"figure.figsize\"] = (20, 5)\n",
"plt.rcParams[\"figure.facecolor\"] = \"white\"\n",
"plt.rcParams[\"font.size\"] = 12\n",
"\n",
"plt.xticks(rotation=90)\n",
"plt.bar(domains, counts)\n",
"None"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Optimise and train Multinomial Naive Bayes classifier"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"from sklearn.naive_bayes import MultinomialNB\n",
"from sklearn.pipeline import Pipeline\n",
"from sklearn.feature_extraction.text import TfidfVectorizer\n",
"\n",
"\n",
"def create_pipeline() -> Pipeline:\n",
" return Pipeline(\n",
" steps=[\n",
" (\"vectorizer\", TfidfVectorizer(sublinear_tf=True)),\n",
" (\"classifier\", MultinomialNB()),\n",
" ]\n",
" )"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Fitting 3 folds for each of 24 candidates, totalling 72 fits\n"
]
},
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>mean_fit_time</th>\n",
" <th>std_fit_time</th>\n",
" <th>mean_score_time</th>\n",
" <th>std_score_time</th>\n",
" <th>param_classifier__alpha</th>\n",
" <th>param_classifier__fit_prior</th>\n",
" <th>param_vectorizer__max_df</th>\n",
" <th>param_vectorizer__min_df</th>\n",
" <th>params</th>\n",
" <th>split0_test_score</th>\n",
" <th>split1_test_score</th>\n",
" <th>split2_test_score</th>\n",
" <th>mean_test_score</th>\n",
" <th>std_test_score</th>\n",
" <th>rank_test_score</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>9.447799</td>\n",
" <td>0.785535</td>\n",
" <td>4.260490</td>\n",
" <td>0.180851</td>\n",
" <td>0.5</td>\n",
" <td>False</td>\n",
" <td>0.05</td>\n",
" <td>20</td>\n",
" <td>{'classifier__alpha': 0.5, 'classifier__fit_pr...</td>\n",
" <td>0.517618</td>\n",
" <td>0.518688</td>\n",
" <td>0.513803</td>\n",
" <td>0.516703</td>\n",
" <td>0.002096</td>\n",
" <td>1</td>\n",
" </tr>\n",
" <tr>\n",
" <th>10</th>\n",
" <td>9.750011</td>\n",
" <td>0.671769</td>\n",
" <td>4.791153</td>\n",
" <td>0.544862</td>\n",
" <td>0.5</td>\n",
" <td>False</td>\n",
" <td>0.1</td>\n",
" <td>20</td>\n",
" <td>{'classifier__alpha': 0.5, 'classifier__fit_pr...</td>\n",
" <td>0.513254</td>\n",
" <td>0.517940</td>\n",
" <td>0.509116</td>\n",
" <td>0.513437</td>\n",
" <td>0.003605</td>\n",
" <td>2</td>\n",
" </tr>\n",
" <tr>\n",
" <th>11</th>\n",
" <td>9.398448</td>\n",
" <td>0.656403</td>\n",
" <td>5.194527</td>\n",
" <td>0.303382</td>\n",
" <td>0.5</td>\n",
" <td>False</td>\n",
" <td>0.1</td>\n",
" <td>100</td>\n",
" <td>{'classifier__alpha': 0.5, 'classifier__fit_pr...</td>\n",
" <td>0.508306</td>\n",
" <td>0.502244</td>\n",
" <td>0.501839</td>\n",
" <td>0.504129</td>\n",
" <td>0.002958</td>\n",
" <td>3</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>9.285461</td>\n",
" <td>0.869226</td>\n",
" <td>5.030563</td>\n",
" <td>0.305472</td>\n",
" <td>0.5</td>\n",
" <td>False</td>\n",
" <td>0.05</td>\n",
" <td>100</td>\n",
" <td>{'classifier__alpha': 0.5, 'classifier__fit_pr...</td>\n",
" <td>0.504070</td>\n",
" <td>0.502116</td>\n",
" <td>0.500603</td>\n",
" <td>0.502263</td>\n",
" <td>0.001419</td>\n",
" <td>4</td>\n",
" </tr>\n",
" <tr>\n",
" <th>19</th>\n",
" <td>9.662259</td>\n",
" <td>0.234167</td>\n",
" <td>4.854762</td>\n",
" <td>0.126622</td>\n",
" <td>1</td>\n",
" <td>False</td>\n",
" <td>0.05</td>\n",
" <td>20</td>\n",
" <td>{'classifier__alpha': 1, 'classifier__fit_prio...</td>\n",
" <td>0.492205</td>\n",
" <td>0.504466</td>\n",
" <td>0.495489</td>\n",
" <td>0.497387</td>\n",
" <td>0.005182</td>\n",
" <td>5</td>\n",
" </tr>\n",
" <tr>\n",
" <th>23</th>\n",
" <td>9.024540</td>\n",
" <td>0.469833</td>\n",
" <td>3.235823</td>\n",
" <td>0.173482</td>\n",
" <td>1</td>\n",
" <td>False</td>\n",
" <td>0.1</td>\n",
" <td>100</td>\n",
" <td>{'classifier__alpha': 1, 'classifier__fit_prio...</td>\n",
" <td>0.501203</td>\n",
" <td>0.493465</td>\n",
" <td>0.492361</td>\n",
" <td>0.495676</td>\n",
" <td>0.003934</td>\n",
" <td>6</td>\n",
" </tr>\n",
" <tr>\n",
" <th>20</th>\n",
" <td>9.304917</td>\n",
" <td>0.192977</td>\n",
" <td>4.370798</td>\n",
" <td>0.255480</td>\n",
" <td>1</td>\n",
" <td>False</td>\n",
" <td>0.05</td>\n",
" <td>100</td>\n",
" <td>{'classifier__alpha': 1, 'classifier__fit_prio...</td>\n",
" <td>0.498869</td>\n",
" <td>0.494357</td>\n",
" <td>0.492431</td>\n",
" <td>0.495219</td>\n",
" <td>0.002698</td>\n",
" <td>7</td>\n",
" </tr>\n",
" <tr>\n",
" <th>22</th>\n",
" <td>9.642570</td>\n",
" <td>0.438559</td>\n",
" <td>3.332855</td>\n",
" <td>0.435930</td>\n",
" <td>1</td>\n",
" <td>False</td>\n",
" <td>0.1</td>\n",
" <td>20</td>\n",
" <td>{'classifier__alpha': 1, 'classifier__fit_prio...</td>\n",
" <td>0.479585</td>\n",
" <td>0.496964</td>\n",
" <td>0.485209</td>\n",
" <td>0.487253</td>\n",
" <td>0.007241</td>\n",
" <td>8</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>10.047471</td>\n",
" <td>0.473215</td>\n",
" <td>4.358744</td>\n",
" <td>0.051892</td>\n",
" <td>0.5</td>\n",
" <td>False</td>\n",
" <td>0.05</td>\n",
" <td>5</td>\n",
" <td>{'classifier__alpha': 0.5, 'classifier__fit_pr...</td>\n",
" <td>0.472578</td>\n",
" <td>0.486362</td>\n",
" <td>0.481865</td>\n",
" <td>0.480268</td>\n",
" <td>0.005739</td>\n",
" <td>9</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>10.287111</td>\n",
" <td>0.349778</td>\n",
" <td>4.908435</td>\n",
" <td>0.099558</td>\n",
" <td>0.5</td>\n",
" <td>True</td>\n",
" <td>0.1</td>\n",
" <td>100</td>\n",
" <td>{'classifier__alpha': 0.5, 'classifier__fit_pr...</td>\n",
" <td>0.474821</td>\n",
" <td>0.474690</td>\n",
" <td>0.478096</td>\n",
" <td>0.475869</td>\n",
" <td>0.001576</td>\n",
" <td>10</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>10.997282</td>\n",
" <td>0.851917</td>\n",
" <td>6.131619</td>\n",
" <td>0.274400</td>\n",
" <td>0.5</td>\n",
" <td>True</td>\n",
" <td>0.05</td>\n",
" <td>100</td>\n",
" <td>{'classifier__alpha': 0.5, 'classifier__fit_pr...</td>\n",
" <td>0.476218</td>\n",
" <td>0.471377</td>\n",
" <td>0.478548</td>\n",
" <td>0.475381</td>\n",
" <td>0.002987</td>\n",
" <td>11</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>9.147621</td>\n",
" <td>0.290876</td>\n",
" <td>5.392678</td>\n",
" <td>0.390403</td>\n",
" <td>0.5</td>\n",
" <td>False</td>\n",
" <td>0.1</td>\n",
" <td>5</td>\n",
" <td>{'classifier__alpha': 0.5, 'classifier__fit_pr...</td>\n",
" <td>0.458994</td>\n",
" <td>0.475008</td>\n",
" <td>0.469998</td>\n",
" <td>0.468000</td>\n",
" <td>0.006689</td>\n",
" <td>12</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>10.299674</td>\n",
" <td>0.486001</td>\n",
" <td>5.776907</td>\n",
" <td>0.462777</td>\n",
" <td>0.5</td>\n",
" <td>True</td>\n",
" <td>0.05</td>\n",
" <td>20</td>\n",
" <td>{'classifier__alpha': 0.5, 'classifier__fit_pr...</td>\n",
" <td>0.461036</td>\n",
" <td>0.466296</td>\n",
" <td>0.467280</td>\n",
" <td>0.464871</td>\n",
" <td>0.002741</td>\n",
" <td>13</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>10.771393</td>\n",
" <td>0.330218</td>\n",
" <td>4.961415</td>\n",
" <td>0.454726</td>\n",
" <td>0.5</td>\n",
" <td>True</td>\n",
" <td>0.1</td>\n",
" <td>20</td>\n",
" <td>{'classifier__alpha': 0.5, 'classifier__fit_pr...</td>\n",
" <td>0.454689</td>\n",
" <td>0.463340</td>\n",
" <td>0.457743</td>\n",
" <td>0.458591</td>\n",
" <td>0.003582</td>\n",
" <td>14</td>\n",
" </tr>\n",
" <tr>\n",
" <th>14</th>\n",
" <td>9.969123</td>\n",
" <td>0.715883</td>\n",
" <td>4.382175</td>\n",
" <td>0.216170</td>\n",
" <td>1</td>\n",
" <td>True</td>\n",
" <td>0.05</td>\n",
" <td>100</td>\n",
" <td>{'classifier__alpha': 1, 'classifier__fit_prio...</td>\n",
" <td>0.444039</td>\n",
" <td>0.449822</td>\n",
" <td>0.450524</td>\n",
" <td>0.448128</td>\n",
" <td>0.002906</td>\n",
" <td>15</td>\n",
" </tr>\n",
" <tr>\n",
" <th>17</th>\n",
" <td>9.439775</td>\n",
" <td>1.333323</td>\n",
" <td>4.914944</td>\n",
" <td>0.292653</td>\n",
" <td>1</td>\n",
" <td>True</td>\n",
" <td>0.1</td>\n",
" <td>100</td>\n",
" <td>{'classifier__alpha': 1, 'classifier__fit_prio...</td>\n",
" <td>0.440663</td>\n",
" <td>0.448419</td>\n",
" <td>0.443441</td>\n",
" <td>0.444174</td>\n",
" <td>0.003209</td>\n",
" <td>16</td>\n",
" </tr>\n",
" <tr>\n",
" <th>18</th>\n",
" <td>10.025776</td>\n",
" <td>0.198347</td>\n",
" <td>5.375965</td>\n",
" <td>0.220059</td>\n",
" <td>1</td>\n",
" <td>False</td>\n",
" <td>0.05</td>\n",
" <td>5</td>\n",
" <td>{'classifier__alpha': 1, 'classifier__fit_prio...</td>\n",
" <td>0.418284</td>\n",
" <td>0.428063</td>\n",
" <td>0.428696</td>\n",
" <td>0.425014</td>\n",
" <td>0.004766</td>\n",
" <td>17</td>\n",
" </tr>\n",
" <tr>\n",
" <th>13</th>\n",
" <td>9.251913</td>\n",
" <td>0.441015</td>\n",
" <td>5.085037</td>\n",
" <td>0.224299</td>\n",
" <td>1</td>\n",
" <td>True</td>\n",
" <td>0.05</td>\n",
" <td>20</td>\n",
" <td>{'classifier__alpha': 1, 'classifier__fit_prio...</td>\n",
" <td>0.400471</td>\n",
" <td>0.406275</td>\n",
" <td>0.406521</td>\n",
" <td>0.404422</td>\n",
" <td>0.002796</td>\n",
" <td>18</td>\n",
" </tr>\n",
" <tr>\n",
" <th>21</th>\n",
" <td>9.173751</td>\n",
" <td>0.112242</td>\n",
" <td>4.271786</td>\n",
" <td>0.293579</td>\n",
" <td>1</td>\n",
" <td>False</td>\n",
" <td>0.1</td>\n",
" <td>5</td>\n",
" <td>{'classifier__alpha': 1, 'classifier__fit_prio...</td>\n",
" <td>0.393559</td>\n",
" <td>0.402869</td>\n",
" <td>0.406431</td>\n",
" <td>0.400953</td>\n",
" <td>0.005427</td>\n",
" <td>19</td>\n",
" </tr>\n",
" <tr>\n",
" <th>16</th>\n",
" <td>9.683013</td>\n",
" <td>0.600089</td>\n",
" <td>4.924559</td>\n",
" <td>0.321389</td>\n",
" <td>1</td>\n",
" <td>True</td>\n",
" <td>0.1</td>\n",
" <td>20</td>\n",
" <td>{'classifier__alpha': 1, 'classifier__fit_prio...</td>\n",
" <td>0.387535</td>\n",
" <td>0.392661</td>\n",
" <td>0.393992</td>\n",
" <td>0.391396</td>\n",
" <td>0.002784</td>\n",
" <td>20</td>\n",
" </tr>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>9.835260</td>\n",
" <td>0.220524</td>\n",
" <td>6.034349</td>\n",
" <td>0.586497</td>\n",
" <td>0.5</td>\n",
" <td>True</td>\n",
" <td>0.05</td>\n",
" <td>5</td>\n",
" <td>{'classifier__alpha': 0.5, 'classifier__fit_pr...</td>\n",
" <td>0.379471</td>\n",
" <td>0.381348</td>\n",
" <td>0.386078</td>\n",
" <td>0.382299</td>\n",
" <td>0.002780</td>\n",
" <td>21</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>11.905621</td>\n",
" <td>0.329256</td>\n",
" <td>5.571229</td>\n",
" <td>0.541937</td>\n",
" <td>0.5</td>\n",
" <td>True</td>\n",
" <td>0.1</td>\n",
" <td>5</td>\n",
" <td>{'classifier__alpha': 0.5, 'classifier__fit_pr...</td>\n",
" <td>0.368234</td>\n",
" <td>0.367599</td>\n",
" <td>0.372849</td>\n",
" <td>0.369561</td>\n",
" <td>0.002339</td>\n",
" <td>22</td>\n",
" </tr>\n",
" <tr>\n",
" <th>12</th>\n",
" <td>10.378068</td>\n",
" <td>0.227200</td>\n",
" <td>5.247946</td>\n",
" <td>0.126687</td>\n",
" <td>1</td>\n",
" <td>True</td>\n",
" <td>0.05</td>\n",
" <td>5</td>\n",
" <td>{'classifier__alpha': 1, 'classifier__fit_prio...</td>\n",
" <td>0.278087</td>\n",
" <td>0.278157</td>\n",
" <td>0.278143</td>\n",
" <td>0.278129</td>\n",
" <td>0.000030</td>\n",
" <td>23</td>\n",
" </tr>\n",
" <tr>\n",
" <th>15</th>\n",
" <td>10.375661</td>\n",
" <td>0.139826</td>\n",
" <td>5.239350</td>\n",
" <td>0.298795</td>\n",
" <td>1</td>\n",
" <td>True</td>\n",
" <td>0.1</td>\n",
" <td>5</td>\n",
" <td>{'classifier__alpha': 1, 'classifier__fit_prio...</td>\n",
" <td>0.259347</td>\n",
" <td>0.262720</td>\n",
" <td>0.258716</td>\n",
" <td>0.260261</td>\n",
" <td>0.001758</td>\n",
" <td>24</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" mean_fit_time std_fit_time mean_score_time std_score_time \\\n",
"7 9.447799 0.785535 4.260490 0.180851 \n",
"10 9.750011 0.671769 4.791153 0.544862 \n",
"11 9.398448 0.656403 5.194527 0.303382 \n",
"8 9.285461 0.869226 5.030563 0.305472 \n",
"19 9.662259 0.234167 4.854762 0.126622 \n",
"23 9.024540 0.469833 3.235823 0.173482 \n",
"20 9.304917 0.192977 4.370798 0.255480 \n",
"22 9.642570 0.438559 3.332855 0.435930 \n",
"6 10.047471 0.473215 4.358744 0.051892 \n",
"5 10.287111 0.349778 4.908435 0.099558 \n",
"2 10.997282 0.851917 6.131619 0.274400 \n",
"9 9.147621 0.290876 5.392678 0.390403 \n",
"1 10.299674 0.486001 5.776907 0.462777 \n",
"4 10.771393 0.330218 4.961415 0.454726 \n",
"14 9.969123 0.715883 4.382175 0.216170 \n",
"17 9.439775 1.333323 4.914944 0.292653 \n",
"18 10.025776 0.198347 5.375965 0.220059 \n",
"13 9.251913 0.441015 5.085037 0.224299 \n",
"21 9.173751 0.112242 4.271786 0.293579 \n",
"16 9.683013 0.600089 4.924559 0.321389 \n",
"0 9.835260 0.220524 6.034349 0.586497 \n",
"3 11.905621 0.329256 5.571229 0.541937 \n",
"12 10.378068 0.227200 5.247946 0.126687 \n",
"15 10.375661 0.139826 5.239350 0.298795 \n",
"\n",
" param_classifier__alpha param_classifier__fit_prior \\\n",
"7 0.5 False \n",
"10 0.5 False \n",
"11 0.5 False \n",
"8 0.5 False \n",
"19 1 False \n",
"23 1 False \n",
"20 1 False \n",
"22 1 False \n",
"6 0.5 False \n",
"5 0.5 True \n",
"2 0.5 True \n",
"9 0.5 False \n",
"1 0.5 True \n",
"4 0.5 True \n",
"14 1 True \n",
"17 1 True \n",
"18 1 False \n",
"13 1 True \n",
"21 1 False \n",
"16 1 True \n",
"0 0.5 True \n",
"3 0.5 True \n",
"12 1 True \n",
"15 1 True \n",
"\n",
" param_vectorizer__max_df param_vectorizer__min_df \\\n",
"7 0.05 20 \n",
"10 0.1 20 \n",
"11 0.1 100 \n",
"8 0.05 100 \n",
"19 0.05 20 \n",
"23 0.1 100 \n",
"20 0.05 100 \n",
"22 0.1 20 \n",
"6 0.05 5 \n",
"5 0.1 100 \n",
"2 0.05 100 \n",
"9 0.1 5 \n",
"1 0.05 20 \n",
"4 0.1 20 \n",
"14 0.05 100 \n",
"17 0.1 100 \n",
"18 0.05 5 \n",
"13 0.05 20 \n",
"21 0.1 5 \n",
"16 0.1 20 \n",
"0 0.05 5 \n",
"3 0.1 5 \n",
"12 0.05 5 \n",
"15 0.1 5 \n",
"\n",
" params split0_test_score \\\n",
"7 {'classifier__alpha': 0.5, 'classifier__fit_pr... 0.517618 \n",
"10 {'classifier__alpha': 0.5, 'classifier__fit_pr... 0.513254 \n",
"11 {'classifier__alpha': 0.5, 'classifier__fit_pr... 0.508306 \n",
"8 {'classifier__alpha': 0.5, 'classifier__fit_pr... 0.504070 \n",
"19 {'classifier__alpha': 1, 'classifier__fit_prio... 0.492205 \n",
"23 {'classifier__alpha': 1, 'classifier__fit_prio... 0.501203 \n",
"20 {'classifier__alpha': 1, 'classifier__fit_prio... 0.498869 \n",
"22 {'classifier__alpha': 1, 'classifier__fit_prio... 0.479585 \n",
"6 {'classifier__alpha': 0.5, 'classifier__fit_pr... 0.472578 \n",
"5 {'classifier__alpha': 0.5, 'classifier__fit_pr... 0.474821 \n",
"2 {'classifier__alpha': 0.5, 'classifier__fit_pr... 0.476218 \n",
"9 {'classifier__alpha': 0.5, 'classifier__fit_pr... 0.458994 \n",
"1 {'classifier__alpha': 0.5, 'classifier__fit_pr... 0.461036 \n",
"4 {'classifier__alpha': 0.5, 'classifier__fit_pr... 0.454689 \n",
"14 {'classifier__alpha': 1, 'classifier__fit_prio... 0.444039 \n",
"17 {'classifier__alpha': 1, 'classifier__fit_prio... 0.440663 \n",
"18 {'classifier__alpha': 1, 'classifier__fit_prio... 0.418284 \n",
"13 {'classifier__alpha': 1, 'classifier__fit_prio... 0.400471 \n",
"21 {'classifier__alpha': 1, 'classifier__fit_prio... 0.393559 \n",
"16 {'classifier__alpha': 1, 'classifier__fit_prio... 0.387535 \n",
"0 {'classifier__alpha': 0.5, 'classifier__fit_pr... 0.379471 \n",
"3 {'classifier__alpha': 0.5, 'classifier__fit_pr... 0.368234 \n",
"12 {'classifier__alpha': 1, 'classifier__fit_prio... 0.278087 \n",
"15 {'classifier__alpha': 1, 'classifier__fit_prio... 0.259347 \n",
"\n",
" split1_test_score split2_test_score mean_test_score std_test_score \\\n",
"7 0.518688 0.513803 0.516703 0.002096 \n",
"10 0.517940 0.509116 0.513437 0.003605 \n",
"11 0.502244 0.501839 0.504129 0.002958 \n",
"8 0.502116 0.500603 0.502263 0.001419 \n",
"19 0.504466 0.495489 0.497387 0.005182 \n",
"23 0.493465 0.492361 0.495676 0.003934 \n",
"20 0.494357 0.492431 0.495219 0.002698 \n",
"22 0.496964 0.485209 0.487253 0.007241 \n",
"6 0.486362 0.481865 0.480268 0.005739 \n",
"5 0.474690 0.478096 0.475869 0.001576 \n",
"2 0.471377 0.478548 0.475381 0.002987 \n",
"9 0.475008 0.469998 0.468000 0.006689 \n",
"1 0.466296 0.467280 0.464871 0.002741 \n",
"4 0.463340 0.457743 0.458591 0.003582 \n",
"14 0.449822 0.450524 0.448128 0.002906 \n",
"17 0.448419 0.443441 0.444174 0.003209 \n",
"18 0.428063 0.428696 0.425014 0.004766 \n",
"13 0.406275 0.406521 0.404422 0.002796 \n",
"21 0.402869 0.406431 0.400953 0.005427 \n",
"16 0.392661 0.393992 0.391396 0.002784 \n",
"0 0.381348 0.386078 0.382299 0.002780 \n",
"3 0.367599 0.372849 0.369561 0.002339 \n",
"12 0.278157 0.278143 0.278129 0.000030 \n",
"15 0.262720 0.258716 0.260261 0.001758 \n",
"\n",
" rank_test_score \n",
"7 1 \n",
"10 2 \n",
"11 3 \n",
"8 4 \n",
"19 5 \n",
"23 6 \n",
"20 7 \n",
"22 8 \n",
"6 9 \n",
"5 10 \n",
"2 11 \n",
"9 12 \n",
"1 13 \n",
"4 14 \n",
"14 15 \n",
"17 16 \n",
"18 17 \n",
"13 18 \n",
"21 19 \n",
"16 20 \n",
"0 21 \n",
"3 22 \n",
"12 23 \n",
"15 24 "
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from sklearn.model_selection import GridSearchCV\n",
"\n",
"optimisation_pipeline = GridSearchCV(\n",
" create_pipeline(),\n",
" {\n",
" \"vectorizer__min_df\": [5, 20, 100],\n",
" \"vectorizer__max_df\": [0.05, 0.1],\n",
" \"classifier__alpha\": [0.5, 1],\n",
" \"classifier__fit_prior\": [True, False],\n",
" },\n",
" scoring=\"f1_macro\",\n",
" cv=3,\n",
" n_jobs=-1,\n",
" verbose=1,\n",
")\n",
"optimisation_pipeline.fit(X, y)\n",
"\n",
"results = pd.DataFrame(optimisation_pipeline.cv_results_)\n",
"results.sort_values(\"rank_test_score\")"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<style>#sk-container-id-1 {color: black;background-color: white;}#sk-container-id-1 pre{padding: 0;}#sk-container-id-1 div.sk-toggleable {background-color: white;}#sk-container-id-1 label.sk-toggleable__label {cursor: pointer;display: block;width: 100%;margin-bottom: 0;padding: 0.3em;box-sizing: border-box;text-align: center;}#sk-container-id-1 label.sk-toggleable__label-arrow:before {content: \"▸\";float: left;margin-right: 0.25em;color: #696969;}#sk-container-id-1 label.sk-toggleable__label-arrow:hover:before {color: black;}#sk-container-id-1 div.sk-estimator:hover label.sk-toggleable__label-arrow:before {color: black;}#sk-container-id-1 div.sk-toggleable__content {max-height: 0;max-width: 0;overflow: hidden;text-align: left;background-color: #f0f8ff;}#sk-container-id-1 div.sk-toggleable__content pre {margin: 0.2em;color: black;border-radius: 0.25em;background-color: #f0f8ff;}#sk-container-id-1 input.sk-toggleable__control:checked~div.sk-toggleable__content {max-height: 200px;max-width: 100%;overflow: auto;}#sk-container-id-1 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {content: \"▾\";}#sk-container-id-1 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-1 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-1 input.sk-hidden--visually {border: 0;clip: rect(1px 1px 1px 1px);clip: rect(1px, 1px, 1px, 1px);height: 1px;margin: -1px;overflow: hidden;padding: 0;position: absolute;width: 1px;}#sk-container-id-1 div.sk-estimator {font-family: monospace;background-color: #f0f8ff;border: 1px dotted black;border-radius: 0.25em;box-sizing: border-box;margin-bottom: 0.5em;}#sk-container-id-1 div.sk-estimator:hover {background-color: #d4ebff;}#sk-container-id-1 div.sk-parallel-item::after {content: \"\";width: 100%;border-bottom: 1px solid gray;flex-grow: 1;}#sk-container-id-1 div.sk-label:hover label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-1 div.sk-serial::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 0;bottom: 0;left: 50%;z-index: 0;}#sk-container-id-1 div.sk-serial {display: flex;flex-direction: column;align-items: center;background-color: white;padding-right: 0.2em;padding-left: 0.2em;position: relative;}#sk-container-id-1 div.sk-item {position: relative;z-index: 1;}#sk-container-id-1 div.sk-parallel {display: flex;align-items: stretch;justify-content: center;background-color: white;position: relative;}#sk-container-id-1 div.sk-item::before, #sk-container-id-1 div.sk-parallel-item::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 0;bottom: 0;left: 50%;z-index: -1;}#sk-container-id-1 div.sk-parallel-item {display: flex;flex-direction: column;z-index: 1;position: relative;background-color: white;}#sk-container-id-1 div.sk-parallel-item:first-child::after {align-self: flex-end;width: 50%;}#sk-container-id-1 div.sk-parallel-item:last-child::after {align-self: flex-start;width: 50%;}#sk-container-id-1 div.sk-parallel-item:only-child::after {width: 0;}#sk-container-id-1 div.sk-dashed-wrapped {border: 1px dashed gray;margin: 0 0.4em 0.5em 0.4em;box-sizing: border-box;padding-bottom: 0.4em;background-color: white;}#sk-container-id-1 div.sk-label label {font-family: monospace;font-weight: bold;display: inline-block;line-height: 1.2em;}#sk-container-id-1 div.sk-label-container {text-align: center;}#sk-container-id-1 div.sk-container {/* jupyter's `normalize.less` sets `[hidden] { display: none; }` but bootstrap.min.css set `[hidden] { display: none !important; }` so we also need the `!important` here to be able to override the default hidden behavior on the sphinx rendered scikit-learn.org. See: https://github.com/scikit-learn/scikit-learn/issues/21755 */display: inline-block !important;position: relative;}#sk-container-id-1 div.sk-text-repr-fallback {display: none;}</style><div id=\"sk-container-id-1\" class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>Pipeline(steps=[(&#x27;vectorizer&#x27;,\n",
" TfidfVectorizer(max_df=0.05, min_df=20, sublinear_tf=True)),\n",
" (&#x27;classifier&#x27;, MultinomialNB(alpha=0.5, fit_prior=False))])</pre><b>In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. <br />On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.</b></div><div class=\"sk-container\" hidden><div class=\"sk-item sk-dashed-wrapped\"><div class=\"sk-label-container\"><div class=\"sk-label sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-1\" type=\"checkbox\" ><label for=\"sk-estimator-id-1\" class=\"sk-toggleable__label sk-toggleable__label-arrow\">Pipeline</label><div class=\"sk-toggleable__content\"><pre>Pipeline(steps=[(&#x27;vectorizer&#x27;,\n",
" TfidfVectorizer(max_df=0.05, min_df=20, sublinear_tf=True)),\n",
" (&#x27;classifier&#x27;, MultinomialNB(alpha=0.5, fit_prior=False))])</pre></div></div></div><div class=\"sk-serial\"><div class=\"sk-item\"><div class=\"sk-estimator sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-2\" type=\"checkbox\" ><label for=\"sk-estimator-id-2\" class=\"sk-toggleable__label sk-toggleable__label-arrow\">TfidfVectorizer</label><div class=\"sk-toggleable__content\"><pre>TfidfVectorizer(max_df=0.05, min_df=20, sublinear_tf=True)</pre></div></div></div><div class=\"sk-item\"><div class=\"sk-estimator sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-3\" type=\"checkbox\" ><label for=\"sk-estimator-id-3\" class=\"sk-toggleable__label sk-toggleable__label-arrow\">MultinomialNB</label><div class=\"sk-toggleable__content\"><pre>MultinomialNB(alpha=0.5, fit_prior=False)</pre></div></div></div></div></div></div></div>"
],
"text/plain": [
"Pipeline(steps=[('vectorizer',\n",
" TfidfVectorizer(max_df=0.05, min_df=20, sublinear_tf=True)),\n",
" ('classifier', MultinomialNB(alpha=0.5, fit_prior=False))])"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from sklearn import set_config\n",
"\n",
"set_config(display=\"diagram\")\n",
"\n",
"classifier = create_pipeline()\n",
"classifier.set_params(**optimisation_pipeline.best_params_)\n",
"classifier.fit(X, y)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Export the model using GreatAI"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"\u001b[38;5;39mFetching cached versions of small-domain-prediction\u001b[0m\n",
"\u001b[38;5;39mCopying file for small-domain-prediction-1\u001b[0m\n",
"\u001b[38;5;39mCompressing small-domain-prediction-1\u001b[0m\n",
"\u001b[38;5;39mModel small-domain-prediction uploaded with version 1\u001b[0m\n"
]
},
{
"data": {
"text/plain": [
"'small-domain-prediction:1'"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from great_ai import save_model\n",
"\n",
"\n",
"save_model(classifier, key=\"small-domain-prediction\", keep_last_n=5)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Next: [Part 3](/examples/simple/deploy)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3.10.4 ('.env': venv)",
"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.10.4"
},
"orig_nbformat": 4,
"vscode": {
"interpreter": {
"hash": "02dd6d3afbfa9fbbe1037d64ad9014965528a1ccad21929d6e72f466389a68ad"
}
}
},
"nbformat": 4,
"nbformat_minor": 2
}