{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "cell-0",
   "metadata": {},
   "source": [
    "# Optimise and train a model\n",
    "\n",
    "![position of this step in the lifecycle](https://great-ai.schmelczer.dev/media/scope-train.svg)\n",
    "> The blue boxes show the steps implemented in this notebook.\n",
    "\n",
    "Run `data.ipynb` first. We read its ground truth from the shared local TinyDB database. The default uses a compact parameter search suitable for the bundled sample; `GREAT_AI_NOTEBOOK_FULL=1` enables the original larger search on the full MAG training data. \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](https://great-ai.schmelczer.dev/examples/simple/data)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d3495327",
   "metadata": {},
   "source": [
    "## Local setup\n",
    "\n",
    "Use Python 3.12 or 3.13 and install this checkout with `uv pip install --editable '.[notebooks]'`.\n",
    "See **Run notebooks locally** in the repository README for the kernel, execution order,\n",
    "and full-data options. Run related notebooks from the same working directory\n",
    "to share the default `.cache/` model store and `tracing_database.json` database.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "d8ae0655",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-28T22:47:33.469672Z",
     "iopub.status.busy": "2026-10-28T22:47:33.469359Z",
     "iopub.status.idle": "2026-10-28T22:47:33.475106Z",
     "shell.execute_reply": "2026-10-28T22:47:33.473998Z"
    }
   },
   "outputs": [],
   "source": [
    "from docs.notebook_support import FULL_RUN"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "cell-3",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-28T22:47:33.476993Z",
     "iopub.status.busy": "2026-10-28T22:47:33.476853Z",
     "iopub.status.idle": "2026-10-28T22:47:34.629711Z",
     "shell.execute_reply": "2026-10-28T22:47:34.629235Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;226mEnvironment variable ENVIRONMENT is not set, defaulting to development mode ‼️\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;226mCannot find credentials files, defaulting to using ParallelTinyDbDriver\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;226mThe selected tracing database (ParallelTinyDbDriver) is not recommended for production\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;226mCannot find credentials files, defaulting to using LargeFileLocal\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;39mGreatAI (v0.1.11): configured ✅\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;39m  🔩 tracing_database: ParallelTinyDbDriver\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;39m  🔩 large_file_implementation: LargeFileLocal\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;39m  🔩 is_production: False\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;39m  🔩 should_log_exception_stack: True\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;39m  🔩 prediction_cache_size: 512\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;39m  🔩 dashboard_table_size: 50\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;226mYou still need to check whether you follow all best practices before trusting your deployment.\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\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\", \"local-domain-example\"])\n",
    "if not data:\n",
    "    raise ValueError(\"Run data.ipynb first in the same local/full mode.\")\n",
    "\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": 3,
   "id": "cell-4",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-28T22:47:34.630652Z",
     "iopub.status.busy": "2026-10-28T22:47:34.630494Z",
     "iopub.status.idle": "2026-10-28T22:47:34.675524Z",
     "shell.execute_reply": "2026-10-28T22:47:34.675167Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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IAAAAAAAQCEJQQAAAAAAgEISggAAAAAAAIUkBAEAAAAAAApJCAIAAAAAABSSEAQAAAAAACgkIQgAAAAAAFBIQhAAAAAAAKCQhCAAAAAAAEAhCUEAAAAAAIBCEoIAAAAAAACFJAQBAAAAAAAKSQgCAAAAAAAUkhAEAAAAAAAoJCEIAAAAAABQSEIQAAAAAACgkIQgAAAAAABAIf2uEGTq1Knpgw8+SF988cVM7T9u3Lj0xhtvpO++++73/DoAAAAAAICaDUFGjRqVevbsmeadd9604YYbphVXXDG1bt06DRw4ME2bNq3C/p988knaZJNN0mKLLZa23XbbvG/v3r3TxIkTq3+kAAAAAAAA1dC4OjufffbZacyYMemJJ55IK6+8cv7ssssuSwcccEBe7XHKKaeU7jtlypS02WabpQYNGqQPP/wwtWrVKq8GWXfddfO2wYMHV+dXAwAAAAAA1NxKkB133DE98sgjpQFI2H///dM666yTLrroojL73njjjemVV15JZ555Zg5AwnLLLZf69u2bhgwZkt58883qHSkAAAAAAEBNhSA777xzatKkSYXPW7Rokb799tv0888/l3521113pTnmmCNtsMEGZfaN8lhh5MiR1fnVAAAAAAAANVcOqzJRHuv+++9Pq6yySg49SsRKj0UXXTTNOeecZfZfcsklS7dXZfLkyflVYsKECX/0MAEAAAAAgHqmWitByvvll1/SXnvtlSZNmlSmH0gYP358atasWYWfiabq0SckVo5U5fTTT8+rS0pe7dq1+yOHCQAAAAAA1EN/KASJhuixCuTYY49Nm2++eZltjRo1yiFJeVOnTk3Tpk0rs2qkvP79++cQpeQ1evToP3KYAAAAAABAPfS7y2H16dMnXXnllenwww+vsAoktG7dutKSV19++WXp9qpECa3yZbQAAAAAAABqfCVIv3790vnnn58OO+ywdO6551a6z2qrrZbGjh2bvvjiizKfv/zyy/nPLl26/J5fDQAAAAAAUDMhyIknnpjOPPPMdMghh6SBAwdWuV/Pnj3zn0OGDCnz+bXXXpv7fPTo0aO6vxoAAAAAAKBmymHF6o8BAwakjTbaKPXu3Tu9+OKLZbZ36tSptNdHrPQ49NBD0/HHH5/mmmuu/H748OFp6NCh6ZprrslBCAAAAAAAQJ0IQV555ZXUuXPnXOZqr732qrD9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lB5++OE0duzY1LFjx/SXv/wlNWwoewEAAAAAAP7EIchTTz2Vtt9++7TAAgukzp075zCkZcuWaeTIkalNmzY1+asBAAAAAIB6rsaWZEyYMCFtvfXWaZVVVkkvvvhi+s9//pNee+219OOPP6add965pn4tAAAAAABAzYYggwcPziWwjj/++NSoUaP8WfPmzdNRRx2VHnvssfTkk0/W1K8GAAAAAACouRDkgQceSHPNNVdabbXVyny+3nrr5T/vu+8+ww8AAAAAAPz5eoK89957adFFF63QBL19+/al26syefLk/Coxfvz40hJblDV18o+GhDrnz3CuOneoi/4M505w/lDXOHeg2OeP7x3qIucOOHfA907d+T6eNm3aDPdrMO239vidllhiiTTPPPOkl19+ucK2CEa22267dPPNN1f6syeeeGIaMGBATRwWAAAAAABQEKNHj05t27ad/StBmjZtmn7++ecKn0+ZMiUnM1Eqqyr9+/dPRxxxROn7qVOnpq+//jotuOCCqUGDBjV1yNTz1LBdu3b5hIneNYBzB3z3QN3kug2cO+B7B+o+12zMDpEzfPfdd6lNmzYz3K/GQpBIXkaNGlXh888++6x0e1XmnHPO/JrefPPNVwNHCWVFACIEgepz7sDv5/wB5w7MTr53wLkDvncokhYtWtReY/S//OUvuZfHO++8U+bzkmBk7bXXrqlfDQAAAAAAUHMhyJ577pmaNGmSLrzwwjLLUy666KLUoUOHtPHGGxt+AAAAAACgxtRYOawIOiLw+Pvf/55rwHXp0iWNGDEiPf/88+muu+7KAQnUFVF+7YQTTqhQhg1w7oDvHqhbXLeBcwd870Dd55qNuqTBtFieUYNee+21dNNNN6WxY8emjh07pl69ev1moxIAAAAAAIA6H4IAAAAAAAAUqicIAAAAAABAbRKCAAAAAAAAhSQEgXJUiIOqjRkzJt13333OE5iFfO+Acwdq0rhx49JVV12Vjj322PToo4/mzz799NP0+eefG3ioxOuvv55GjRplbKCavv322zR8+PA0ZcoUY0edIwSh3rrjjjvSU089Vfr+hhtuSC1btkwtWrRIl156aa0eG9TlEGSjjTZKiy++eDrppJPSxx9/XNuHBH8aX331VTrnnHPKPJRab7310hxzzJG6d++exo8fX6vHB3U5KDz11FPTDz/8kN9PnTo17bXXXqlp06Zp2WWXzQ+rgMrdeuutqWPHjmnfffdNp512Wnruuefy5++++27q2bOnYYNKvPzyy6lr165phRVWSOeee2768ssvjRPMZAiy1VZbpfbt26f+/fund955x7hRZwhBqLf/MB955JH5xjl89913ab/99sv/UPfo0SMdeuih6ZNPPqntw4Q6Z9VVV01DhgxJiyyySDrhhBPyTfWmm26abrrppvTTTz/V9uFBnXbKKafkwKNEPNR95pln8sPcuEE488wza/X4oK668cYb02uvvZbmmWee/D6+c6699tq0zTbbpGbNmqWDDz64tg8R6qTRo0fnoCMCkJi4Evc4Jf7617+msWPHprfeeqtWjxHqongmcPHFF6eGDRvm5waLLrpo2mGHHdLdd9+dg3igcvFM7ZZbbknLL798vrdZeuml86SvwYMHpx9//NGwUauEINRLjz/+eOrUqVOab7758vv7778/TZo0Kd17773puuuuS9tuu2268847a/swoc5p0qRJ2m233dITTzyRXnzxxXxT/dhjj6WddtoptWnTJh1++OHp1Vdfre3DhDppxIgR+aa6xG233ZaOOeaYdOWVV6brr78+3zAAM3fubLHFFnkV7wMPPJDDxK+//trQQTk333xz2mSTTdJ5552X2rVrlx/oTi9muU+/Mh74nwjd//73v+cVIY888kgOQKLEz+abb54WW2yx9M9//jN98MEHhgvKie+Z7bbbLpfQfvPNN1OfPn3SK6+8kvbcc888kfKAAw7I121QG4Qg1NtZUfHAtkRc2MRy1wUXXDC/X2WVVXLZH6BqnTt3TpdddlmuKT1o0KDUunXrNHDgwLTiiiumNddcM/373/9OP//8syGESr57YkbuRx99lB/k+t6B6l+3lZw7sRJkiSWWsIIXKhHXaGussUbp+wYNGlR40GtmLszYuuuum4YOHZq/i6KkXKNGjfLq3vju6datWw4b9XeDimIVSITwUWUl+lIttdRS+flBfC+ttNJK6cILL/QdxGwlBKFeWmihhUrrR8cFy8iRI9M666xTpk77AgssUItHCH8eEydOzL0MoqxciNlRcX7ts88++eImHvQCZb97YjZh8+bNc2gYfO/AzJ070c/gs88+c90GMyH6HcZM3KrEqt62bdsaS5gJ0Zcq7nlK+lMtueSSucLEjjvumNZee+1cchuoKKquxLkzYcKE/D4mtkQwcsghh+QS9bFSBGYHIQj10vrrr5+effbZXId91113TW+//XauK10itsVMdqBqMRN3l112yeUVjj/++Bx4RKAYS8OjxnTUcP/ll19yA3Ug5RIKvXr1yiWwoqfOlltumRo3bux7B2bi3DnuuONyg80opxCzb0sCxAhEYnZ71GsHytpss81yucUoKVd+Jcill16a+1FFbxCgctH/I86fWH0YoUc0Se/evXt69NFH8zOEL774Iq9+f//99/PKeCCVea7Wu3fvfI12xBFH5NA9+rrFJMm4fotzK6qx9OvXz7AxW/zvzhvqmVjlEY2Zon9BzNiIh1Grr7563hYpdKTU068MAX5d9REX+pdcckluUhszDOM8ipq5HTp0KB2mueaaK8+KijIlsVwc+F9j9N133z0vC49ycmeccUbpsMSNc9SXBiqKXlRPP/10uuiii/L3TjRFLxGlFA466CDDBpWICSr77bdf7qkT5UdiBnuLFi1yP53oBRLnT7wHyvrmm29y2Z54ffjhh/nh7YABA9Lf/va3XAK4RJw/e++9d5o8eXLukwj13ZQpU9KQIUPSxRdfnEOQWPkeFSIOPPDAtNxyy5XZN8LFCEii5w7MDg2mKV4IFZbqxez1qJELlBU3zGuttVa+kY4LmZ133jk1bdq0ymF6991388Oqk08+2VDCDHz11VelfamAmRcTV+KarWRVFVBW3O5H0B4hYsxcD8svv3w69thjU8+ePQ0XVCJWUMX5seGGG+agfauttsq9QKry5JNP5mbPhx56qPGkXovQsGPHjnnFbkyUjAlg8847b5X7f/nll7lyhJVUzA5CEKjkRqF800Dgf2LZajTZ7NKliyGBavrpp5/Sww8/nDbaaKMK2+6999603nrrpSZNmhhXqMSDDz6YS5XOPffcZT6PWYbt27fPfUOA3/4eCr5rYMaiVFyUwlpmmWUMFVRzcspLL72k1CJ1kp4g1Ft33HFHntVeIpaFR4mFWNIaNXKBihZZZBEBCPxO559/fg47KhOfR1kSoKIoMXLiiSdWCEDCxx9/nA4++GDDBjMhwg8BCPy2pZZaSgACv0M8T9NrirrKShDqpegDstpqq+XZg/PNN1/67rvvcp3PaLQZdQqjWVM0d9ZkE8qaMGFCev7556scllhFFf1AFltssTL1coH/lR+57bbbKr2pfvPNN3M93FdffdVQQTnRVDNWSkVT9Kp6vUWTzehDBVR+/RbfM7GaN+q1T2/llVfODZ+ByldPvf7662n06NG578f02rVrl1coAmXLy08/2biy5wVRTjuev3nexuymeC710uOPP546deqUA5Bw//3353+sYyZu1GSPm4M777wz1zAEfhU3ARtssMFMDUmUzLrgggvSX/7yF0MIKaX33nuvyov9+Dy2AxXFuTGj3gWxSvH9999PnTt3NnxQzplnnplOPfXUPOmrMuedd17q06ePcYNKKkcccsghOQCpTPRGjN4hwK8+//zzmX5eEBOQzz333LTpppsaQmYLIQj1UlzItGnTpvT9I488krp27VralHaVVVZJY8aMqcUjhLopLlRiJnvcUK+00ko54GjevHkuRzJs2LC07rrr5hlRsZLqqquuyr0PXnjhhbT00kvX9qFDrWvVqlV68cUX0zrrrFNhW9TOjdnsQNXnTvfu3Sts+/7773NI4vyBimKCV79+/dK+++6bGzvHKt2GDctWxI6eOkBZY8eOTbvuumu+Zjv77LPzqo/ypeR870BF8T0zYsSIdM455+RJXhGIxLkSKxFvvPHG/FwgQo9YwTtkyJDUo0eP9Oijj+bncVDThCDUS9E8M2a0lzRCHzlyZC5DUmLcuHF5ViFQscZnzHg65ZRTUrdu3cpsi5lScR7FTXb8efjhh+d6oBdffHEaOHCgoaTe22yzzdJhhx2W7r777jJNnONG+9BDDzULCmZw7vTt2zdtvPHGOYAvEat4DzjggFzONB5QAWU9+OCDabfddktXXHGFoYFqiHI+ERDGNVujRo2MHcykKI19zz33pH322Sf16tWrzLYDDzwwh/IhnhXEKsStt946PyuwqorZQWN06qX1118/9wPZa6+98gyPt99+O22zzTal22Ob+p5Q0SeffJLPj/IBSIiZhXvvvXcaNGhQft+4ceN00EEHpVdeecVQQkrp+OOPzysRo/b6tttum5s5x5/xADdWH0bjZ6Ci3XffPTepXXXVVXMQEjfRcf0W59INN9yQzj//fMMGlZh33nn1+4Dfee507NhRAALVFBNU/vOf/+TrtMrsv//+pRMkoz9ITBDzvIDZRQhCvRTL8QYPHpweeOCBdNddd6UTTjghrb766nlb/AM8fvz4SsuVQH335Zdfph9++KHK7VGWJPaZvoRJzAYB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+GN+xYSV8jwvoDYph0W98Nprr+UeBlETN5pmlryfkZJ9gV/Fg9tFFlkk7b777umMM85IjRv/mqV//PHHeUb7vvvum4455hjDBuVcdNFFuQ5unCPbb799WnjhhdMXX3yRbrnlltw/5IILLkh///vfjRuU8/TTT+e+BZtvvnluQhsPo7799ttciuScc85JW221VQ5JoL6L75jfaoRensboUNGNN96Yz6coAbz44osbIqiGeJYWJeQuu+yy3Ax9+gBk4403Tuuuu26+74HZTQgCQLVcffXVqXfv3qlDhw5p7bXXTi1atMjlfe699948k/C5557LzdKBijcEUUrhkEMOqTA0cSNw5ZVXppdfftmwQTkRHMaMwqFDh1YYm6eeeiqXJInyclHKFOqzN998M3344YdlPnvrrbdyr7add945LbfccmnKlCnppZdeSsOHD8+rEzfccEMlGaGcaHweE77+7//+z9hANY0cOTJPUGndunVab731co+QTz75JK+mipW78bzACkRqgxAEyqmqzA/wq9tuuy3fGMQFTDQ/m3/++dPWW2+dP4uLHaCimAn12WefVdpvKvpURdmFSZMmGTooJ26gjz766LwSpDJLL710nrWrPwiUFd8522yzTbr77rsrfPe89957qVevXnlF1fQzdYGUfvrpp7T66qvnECRW7gLVc//996cBAwbkCiwRvjdr1ixtttlm+XlBrOiF2tCwVn4r1AF33HFHnj1Y4oYbbsgNamNW+6WXXlqrxwZ13bbbbptGjRqVJk+enOuzxwPcWCEiAIEZ18iNZeCVUR8Xft+5E5NXoleVflRQUaye6t69e6Xh+xJLLJHL/MSMXaCiCy+8MO2zzz5p8ODB6fXXX8/fQ7HqsOT13XffGTaoQrdu3dIjjzySnxd8//33acKECfmZmwCE2iQEoV6KOtJHHnlkWnbZZfP7uIDZb7/9Uvv27VOPHj3SoYcempfrATMWDZ3nnntuwwQzYZ111smlsOImYHrxHXTYYYfl+rhA5efOiSeeWKHMT6xE7NevX5pjjjnSUkstZeignHhoG5NVqhIPpqoKGKE+u/XWW3OpxbvuuivtueeeqVOnTmmhhRZKrVq1Kn1Fjypgxho2bFhpg3SoDb92tIV65PHHH88XMiV9C2KpXpQgiZ4GUa8wluvdeeedGtRS78XMjSilEGUSoiF6yfsZKdkXKOukk07KfXQWW2yxPDO3pDH6fffdl8+t+G4CKjrooIPSVVddlctebbTRRrknVYSJcc588MEHuSl63GQDZUWJuOhFFQ9xV1lllTLb4uFulMk67rjjDBuUE+fL2WefPcNxKZlQCcy4T1UE7tOLUCRKY8HsJgShXho9enSuvV4ilul17do1ByAlFz1jxoypxSOEuuGFF15Ia621VlpzzTVz+biS9zNSsi9Q1qqrrpof2sYDpxEjRuTwvWnTprkp7amnnqqfAVQh+k498cQTqX///rmcaTy8jZWIXbp0SQMHDszNN4GKdthhh1zSZ7XVVsvhezy0jRVU0Rj9scceSz179kxrrLGGoYNylllmmfwCqu+VV15Je++9d+4fWpmYEFZ+dS/MDkIQ6qVYyhp1PUtqSUct3LhJKBE1Ps1kh//Vi77iiivyOTP9+986v4Cqg5B4gBvfPT/++GMuJ9egQQPDBb8hrsuuueaa/Pc4d2LVYQQhQNUaN26c7rnnnnTKKaekIUOG5L+HKB8Xs9wPP/xwwwfALLXrrrvme514bhCreMuXz45rOKgNDabF/zOhnokmzu3atUs77rhjnokbDZqefvrptPrqq+ft66+/fr5ZiBrUAAAAf3Zx3xOl45o0aVLbhwJ12tixY0snTVYmJrBESZ+YIBarFYFfz52YuBIltE2OpK6xEoR6aYEFFkiDBw/Os5+iSfoJJ5xQGoDE0r3x48cLQKAK0cMgSspFaYXpxczcUaNGpQ022MDYQRW++uqrdMEFF+ReVPH3li1b5nJY0Rg9vpuAGX//vP322/kGu/w8rjiPnENQuVjlHqXk3n///bTpppumddddN3366ac5EIn+VEBZDzzwQJ7NPjPi3ueiiy5Kyy23nGGk3otVH9F7VwBCXWQlCFQyQypq5cbMDqCi7bffPvXq1Sttt912FbbFKqrobRDNn4Gy3nvvvbTeeuvlmVGxNLx169b5oe5bb72VFl100dyfqmPHjoYNKrk2i+bo0QA9rtEq8+STT+b+bkBZt956a26MXtKY9rzzzkt9+vTJ3zknnnhiftgLlPX555+nBx98MJeNi5AjeobONddc+Vpu6NChaaeddkqLL754euedd9Lll1+efvrpp/TGG28I4yGltPPOO6dDDjnExGLqHCEIADMtVknFQ9ooKVeZqNcejTavvPJKowrlRPPmWEU1bNiw3Jy2RNw077LLLvncuv32240blHPyySenM888Mx155JHpL3/5S1pwwQUrjFHMwDWBBcqK75zo//H3v/89HXHEEelf//pX/q6JECSssMIK6ZZbbtEAGsqJ1YbdunXLq3fjPCkfzG+22Wbpsssuy5NaJkyYkEOSeOhbcm5BfTF16tQKzwYidO/fv39edRiTJMuvComebsrIURuUw6JeiuXfsRx8RmJWrhm5UFacN23atJnheRMzpICKYrbto48+WiYAKXl4e/XVV6e//vWvhg0qEbNxIwSJ1SDAzLv55pvTJptskld/hCh/Nb14uPvUU08JQaCS1YXR96N8ABKaNm2aV8THpK+zzjorNW/ePPXu3TuX1Yb65uOPP67yudn1119f6eeLLbZY+vDDD2v4yKAiIQj10o033pj7gcxI1GcfOHDgbDsm+DNo1apVevfdd/PsjnnnnbfC9pdeeskycKjCnHPOmUsnVCYaa8ZNNVBRfN8sueSShgZ+x8SvNdZYo/R9PNSdXqyeip5uQFnRe+qHH36ocljiXujLL78sc48U5U6hvol+bFE2rjpatGhRY8cDMyIEoV7aeuutK9xMT5w4Mb355pvphhtuyDMNo247UFbbtm1zWYUDDjggz36a/qHtyy+/nE477bQ8WxeovD7u8OHD02677VZhWzSs7dmzp2GDSuy111753IkZ7cDMa9myZXr11Ver3P7iiy+mbbbZxpBCOSuttFJ65plncgnT8g3SY9V7lMk6+uijSz97/vnn0+qrr24cqXdiJdRRRx1V24cBM0VPECgn6hluu+22+YHUfPPNZ3ygnPvuuy/XwY2mzlHnM+p5xuqQKPXTpUuXXO6nSZMmxg3K+eSTT9I//vGPXD+6R48epY3R77zzzvT222/nWVSxWqT8Ayyo76If1aBBg/LM3AgR27dvnxo3LjuXK67Zyn8G9V1MUIlrs9tuuy1tueWWua9Ou3btct+CSy+9NH8nRd8Qs3Kh8soQEXasueaaZRqj33333XlS2NNPP51XU8V30xZbbJFLN1a2Uh7qm2+//Ta99tprae211y7z+S+//JLuvffetOmmm9basVG/CUGgEv369cu9DaK5GVBRBB3HHXdceuKJJ9KUKVPyEvCYJXXKKaekZs2aGTKo7KKrXBmSmW3MCfVd165d06hRo36zfnvsB5QVK9wvvvjiXBYryvtE4BGNbKMXyIUXXqjXDszgGizCwjhP3njjjfw+GjzvtNNO6aSTTtLYGWbwvdOpU6d04IEHVtgW588uu+yS++rA7CYEgUocccQReSb7GWecYXxgBuImetKkSWnuuec2TvAb/vWvf1V7jCwvh5SGDh2aexvMSK9evdIiiyxiuKCceHAbK6kuuuiivOowLL/88unYY49VhhFm0s8//5xf7nngt58PRKWI6JFT2fny3//+NweLI0aMMJTMdkIQKLds7/bbb8+J9RVXXJFvqIGq60jHzNyYVRilFbp3725GFABAHfXTTz/lP5UthZkXK9/jvifOn44dO6aNNtpIGAJViPBjxRVXTOPGjat0+yuvvJJXg8TqKpjdFM6lXorkufzs2kisY3ZHiJq50cAWqGjChAm59NVdd91V5vOogXvJJZdU2vQZAP6ob775Jvelih4GUYc96rSvvPLKBhZmkvADZl6sQIySPeXLMUYZ4Ouuuy6HIUBZsQokermNGTMmtW3btsLwvPTSS2mBBRYwbNQKK0Golx5++OHcIHB6jRo1Sm3atMk31Ouss06tHRvUdbvvvnsaOXJkOvzww9P666+fm9F+8MEHefVUNAqMGtOrrbZabR8mAAVy7bXX5hrTsfpwejFxZdiwYZrRwm+IhrRffvll7uU2vbiO08wZKlp33XXT+++/n/7xj3/knjpR2idKyp1//vl5Zcibb75Z6UNeqO8iIJxjjjnS9ddfn5o3b176eZxP8fzgb3/7W/rnP/9Zq8dI/SQEAWCmxayOli1bpsceeywHhuX17Nkz30hffvnlRhWAWeLpp59Oa621Vtp8883zjXOUI4kSpjGp5ZxzzklbbbVVDkmAVGn99RNOOCE999xzOQgp77zzzkt9+vQxdDCdV199NX/vxKz1xRdfvMzYRJC44YYbpk033TQdc8wxxg3KeeGFF/LE4li1G6FHrJ766KOP0r333ps6dOiQnnnmmTLhCMwuQhAAqnVBE6XiShprlhclss4666z00EMPGVUAZol99903/fjjj7lBenmx+vCvf/1rrj3thhrKigdNXbt2Tauuump+YBsPoho2bFhhtnvnzp0NHUwnqkZEmd977rmn0nG5+OKLc0B/zTXXGDeo4rlB//7904MPPpj76cSqw+233z6dccYZeVIl1AY9QajXYgZhzFiPmR7RE2SppZZKe+21V55RCFQ011xzpa+++ipNmzYtNWjQoML2KLMQ+wDArPLOO++ko48+utJt8YA3ZhVGiQX9QaCsO+64I4cfI0aMqPS6Dahc3M/EfU1V3PPAjK2yyip5JWI8N5g4cWIuJwe1rew0EKhHIoGOpXkxc71p06Z59mCU+Nl6663TwQcfXNuHB3XS0ksvnRo3bpz69u1boab0xx9/nAYMGJBnFALA7HgYFTfXEc4L4KHycyfKlwpAoHpWX3319Prrr+f+H/E9M72XX345XXDBBe55oBJRrnT48OGlzwri+0cAQl2hHBb1dkbhsssum44//vg8szBCkBD/UEdz5whB7r///hySAGVdffXVqXfv3nnm7dprr51atGhRWuMzmgNGzelY7goAs8Ipp5ySrrrqqlxSIb57SkR/g6jHHv1APv300wplfqC+i8bN+++/f3rggQdSo0aNavtw4E8leumcdNJJafnll8+hSISK8RwhvotWW2219Pjjj+fJYcCvPvzww9y7bZFFFkl77rlnfm4QFVegLhCCUC9deeWVaciQIbkcVmX22GOP1L59+3zTDVReJzdWU5U02Zx//vnzKqr4rHXr1oYMgFnmm2++yT0NPvnkk7TRRhvlIGTChAn5AdQHH3yQQ5C4dgMquv3229ONN96YS/7Gg6jyq6ZiNbxZulC5mCAZq0FiVUisCIn7nF133TWHI82aNTNsUE6UmY/vneibEwF8nDfRu22fffZJO+ywg+8bapUQhHopApD4BzlmtFcmSvrEbKnjjjtuth8b/JlEADJ58mQXMwDUqM8++yw32IweB1FqIa7TunTpko499li93GAGRo0alQ499NDcxLky5513XurTp48xhBn4+eefc9UIpRdh5r399tvpkksuyZNVYkJLhO4RIkYgEqurYHYTglAvRV3pmEkYPUDmnXfeMtvi4maDDTbIsz6iZBYwc6pqlg4As9KPP/6Y5pxzTuV9YCbKYUVz2ijns/HGG6dWrVpVKBu33nrr5X2AiiZNmpT7G7z66qu5N2KvXr3S+PHj8/OEJZdc0pDBTIjG6MOGDcurQ6KSRFhxxRXTfvvtl8tlWY3I7KKAIfXm4uX7778vfR8PaqPUVc+ePfPS8JVWWinfSMeNQoQf++67b2rXrl2tHjPUVS+88EKuh7vTTjuVvt95551z/c84dy666CJhCACzVNRgjwbPcaM8/c3ys88+m0uYLrTQQkYcyrnhhhtyj8O77rrLtRlU0yuvvJJ69OiRex+GuN+JECTK/XTv3j298cYbVobATD6Pi/AwSpmGNm3a5BKnhxxySDrrrLPSyJEjcygCNU33QOqFSy+9NM98mv4VFzQxq2P77bfP9XEXX3zxtPnmm+deBxGMRHkFoKIDDzywTGPaeB+zcqPxWZSai/MKAGaVWLl74oknVjpT8OOPP04HH3ywwYZKxCSvtdZaSwACv6Pkbzwn6NSpU3r55ZfTf/7zn9Jt0QuxW7du6aabbjKuMAMxUSVWeiy66KLpiCOOSG3bts3nTQSLUeZ0xIgRacEFF0z9+vUzjswWVoJQL0QjprPPPrtaPxN1poGyvv7669yEdo011sjvP//88/TUU0+le++9N8+IinILt9xyi/rsAMwy//73v/NNdGW22267vArxu+++06QWyokmtAcddFCeuV6+DBZQteihE7PXb7311lx+MRqjTy9mrT/55JNpjz32MIxQrrx8TIyM0lcRgkQfkOgBEhMnl1tuuTJjtcUWW+SAJL6rYHYQglAvrLrqqvkF/DEx43aRRRYpff/II4/kmblRaiFETemY0QEAs8p7772XS5hWJb6X3n///dS5c2eDDtOJ8r5777132n333fNDqFj9Xr6xc/RHbNq0qXGD6Xz66af5OyUCkFC+7+E888yTV8IDZY0ZMyZPXImgMIKQ+P4p34d3ehGCbLbZZoaR2UIIAsBMi5rr8aBp8uTJ+aYgSl917do1NW78v6+TcePGpQUWWMCIAjDLRBnTF198Ma84LC96vkVI4rsHKoryvueff37++9ChQysdovPOOy/16dPH8MF0WrZsmd566600bdq0SsvJRU/EKO0DlBXl4h5++OFcjWVmr/EGDRpkGJkthCAAzLRoYlbSPydmd1x//fXp3HPPLd0eS16jcS0AzCoxQ7Bv375p4403TiuttFLp51Gq5IADDkhLLLFEnvEOlLX11lv/5oPamX1QBfVJ3M989dVX6eSTT07//Oc/ywQhUQr46quvTg888ECtHiPURS1atKjye6WqUBFmlwbT4v+FADCTojlg1L+N2VFbbrlluu6661KTJk3SxIkT07LLLptnRpmRC8Cs8tNPP6V11103Pffcc2nDDTdMSy65ZPrmm2/So48+mr744ot09913V7pKBAB+r8GDB6e99torf+e0bt06f99E6H7fffelXXbZJfc9ACp69913c9nskn5u8T76frz66qtpxx13zOfWHHPMYeiY7YQgAMyyJmg//PBDnv0BALNSND4/7rjj0rBhw9KXX36ZyzCuvfba6ZRTTknrrLOOwQZglhs5cmReDfLMM8+kqVOn5lXx+++/fy4116hRIyMOldh2221zP6qtttqq9H1MXNluu+3Srbfemk477bS03377GTtmOyEIAADwpxHNaKORc8OGDWv7UACoB3755Ze8KnGuueaq7UOBOi3CwpgUGeXkolpElC6NPiFXXHFF2m233fJklmuuuSb93//9X20fKvWQOwcAAKDOe+edd9IFF1yQTjrppDRmzJj82dtvv51XiQBATYlVHwIQ+G1jx45N8847bw5AwtNPP50mT56ce4qGVVZZpfQaDmY3jdEBAIA67cQTT8wlSWKGYdhmm21S+/bt0+23356+/fbbXFoBAGbVg9zXX3+9yu3R3HmeeebJPUJiljvwPy1btkxff/11GjduXP778OHD03LLLVfaMzQ+1z+U2iIEAQAA6qw777wznXnmmWnQoEFpp512SltuuWXptqjNvvTSS+feIMpjATArPPDAA2nXXXedqX032GCDdNFFF+UHvVDfRc+2OCfiWu2vf/1rPjcOP/zw0u3PPvtsWnPNNWv1GKm/9AQBAADqrJ133jmtvPLKqX///vn9Wmutlc4777zUtWvX/L5Dhw65tvQyyyxTy0cKQBF8/vnn6cEHH0xnn312fqAbJXyiHNZ7772Xhg4dmgP5xRdfPJdpvPzyy3O/kDfeeMMMd0gpvf/++7n/xwsvvJCDkJtuuik1b948r+Zdfvnl08iRI/MqKpjdrAQBAADqrE8//TTtt99+ZcqQTC9KkkSzdACYFVq3bp0bOQ8ePDitsMIKZbYdeuihabPNNkuXXXZZ2mWXXdJhhx2WQ5LYt0+fPv4HoN6LgPCJJ56odByefPJJJeSoNRqjAwAAdVbUlH7zzTcr3TZhwoQ843DRRRed7ccFQDHFg9oI3MsHIKFp06Zpu+22S1deeWV+HzPce/funV555ZVaOFL484iypXroUJuEIAAAQJ0VM25PPfXUXGpk+pUgU6ZMSUceeWRaaaWV0kILLVTLRwlAkRqj//DDD1Vu//7779OXX35Z+r5Vq1a5XBbwP6NHj87XaFG6NEpgbbjhhulf//pXmjhxoiGi1ghBAACAOmuvvfZKiy22WO4LstFGG+Wa7BGKdOrUKQ0ZMiT3BwGAWSXC9WeeeSYNGzaswrb4DrrgggtS586dSz97/vnnc0ksIKWnn346r6IaNGhQDhNjosrHH3+c+vbtm5uif/3114aJWqExOgAAUKfFTfTxxx+frrvuuvTFF1+kRo0apbXXXjudccYZuVE6AMxK0esjwo54aDt9Y/S77747LbXUUvlBb/SkilUjW2yxRW6kPu+88/ofgXovQsToq3P11Ventm3blo7HqFGj0vbbb5922GGHNHDgwHo/Tsx+QhAAAOBPI0opNGnSJAchAFATpk2bli699NJ04YUX5nKM8T5mtO+0007ppJNO0tsAKjFu3LgcgEQ4uOCCC1bYfuutt+ZJLa+++qrxY7YTggAAAABAJX7++ef8mnvuuY0PzMCECRNShw4dqix59dJLL6V99tknPfvss8aR2U5PEAAAAACoxBxzzCEAgZnQvHnz3Az9scceq3T7HXfckXr27GksqRVWggAAAAAA8LtNnTo1vfvuu+noo49O6623Xtpwww1zWaxPPvkkXX/99WnSpElpwIABqUGDBqU/E+VN559/fqNOjROCAAAAAADwu3344YepY8eO1fqZxRZbLP8c1LTGNf4bAAAAAAAorAUWWCCdffbZ1fqZFi1a1NjxwPSsBAEAAAAAAApJY3QAAAAAAKCQhCAAAAAAAEAhCUEAAAAAAIBCEoIAAAAAAACFJAQBAAAAAAAKSQgCAAAAAAAUkhAEAAAAAAAoJCEIAAAAAABQSEIQAAAAAACgkIQgAAAAAABAKqL/B8IeNbfHYoL7AAAAAElFTkSuQmCC",
      "text/plain": [
       "<Figure size 2000x500 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",
   "id": "cell-5",
   "metadata": {},
   "source": [
    "## Optimise and train Multinomial Naive Bayes classifier\n",
    "\n",
    "Each paper may have several accepted labels. We expand it into one training row per label for this single-label classifier, but keep all rows with the same paper text in one cross-validation fold using `GroupKFold`. The final train/test split was already made by paper in Part 1, before expansion.\n",
    "\n",
    "The search uses macro F1 on the expanded single-label validation rows as a training surrogate. This differs from the top-1 hit rate and fixed-target multilabel metrics used to evaluate the deployed label sets in [Part 3](https://great-ai.schmelczer.dev/examples/simple/deploy). Rerun the search to obtain results for these grouped folds; the previous ungrouped outputs have been removed."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "cell-6",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-28T22:47:34.676373Z",
     "iopub.status.busy": "2026-10-28T22:47:34.676316Z",
     "iopub.status.idle": "2026-10-28T22:47:34.683015Z",
     "shell.execute_reply": "2026-10-28T22:47:34.682660Z"
    }
   },
   "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": 5,
   "id": "cell-7",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-28T22:47:34.683793Z",
     "iopub.status.busy": "2026-10-28T22:47:34.683737Z",
     "iopub.status.idle": "2026-10-28T22:47:35.666188Z",
     "shell.execute_reply": "2026-10-28T22:47:35.665816Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Fitting 3 folds for each of 8 candidates, totalling 24 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>2</th>\n",
       "      <td>0.002220</td>\n",
       "      <td>0.000173</td>\n",
       "      <td>0.001228</td>\n",
       "      <td>0.000017</td>\n",
       "      <td>0.5</td>\n",
       "      <td>False</td>\n",
       "      <td>0.9</td>\n",
       "      <td>1</td>\n",
       "      <td>{'classifier__alpha': 0.5, 'classifier__fit_pr...</td>\n",
       "      <td>0.455431</td>\n",
       "      <td>0.434571</td>\n",
       "      <td>0.423547</td>\n",
       "      <td>0.437850</td>\n",
       "      <td>0.013221</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>0.002214</td>\n",
       "      <td>0.000084</td>\n",
       "      <td>0.001206</td>\n",
       "      <td>0.000011</td>\n",
       "      <td>1.0</td>\n",
       "      <td>False</td>\n",
       "      <td>0.9</td>\n",
       "      <td>1</td>\n",
       "      <td>{'classifier__alpha': 1, 'classifier__fit_prio...</td>\n",
       "      <td>0.458154</td>\n",
       "      <td>0.415951</td>\n",
       "      <td>0.406097</td>\n",
       "      <td>0.426734</td>\n",
       "      <td>0.022578</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>0.008167</td>\n",
       "      <td>0.004108</td>\n",
       "      <td>0.001306</td>\n",
       "      <td>0.000036</td>\n",
       "      <td>0.5</td>\n",
       "      <td>True</td>\n",
       "      <td>0.9</td>\n",
       "      <td>1</td>\n",
       "      <td>{'classifier__alpha': 0.5, 'classifier__fit_pr...</td>\n",
       "      <td>0.422790</td>\n",
       "      <td>0.389784</td>\n",
       "      <td>0.352330</td>\n",
       "      <td>0.388301</td>\n",
       "      <td>0.028784</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>0.002201</td>\n",
       "      <td>0.000114</td>\n",
       "      <td>0.001167</td>\n",
       "      <td>0.000094</td>\n",
       "      <td>1.0</td>\n",
       "      <td>True</td>\n",
       "      <td>0.9</td>\n",
       "      <td>1</td>\n",
       "      <td>{'classifier__alpha': 1, 'classifier__fit_prio...</td>\n",
       "      <td>0.381607</td>\n",
       "      <td>0.382587</td>\n",
       "      <td>0.285005</td>\n",
       "      <td>0.349733</td>\n",
       "      <td>0.045772</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>0.001697</td>\n",
       "      <td>0.000039</td>\n",
       "      <td>0.001383</td>\n",
       "      <td>0.000154</td>\n",
       "      <td>0.5</td>\n",
       "      <td>False</td>\n",
       "      <td>0.9</td>\n",
       "      <td>3</td>\n",
       "      <td>{'classifier__alpha': 0.5, 'classifier__fit_pr...</td>\n",
       "      <td>0.348260</td>\n",
       "      <td>0.358595</td>\n",
       "      <td>0.329416</td>\n",
       "      <td>0.345424</td>\n",
       "      <td>0.012080</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>0.001766</td>\n",
       "      <td>0.000113</td>\n",
       "      <td>0.001158</td>\n",
       "      <td>0.000053</td>\n",
       "      <td>1.0</td>\n",
       "      <td>False</td>\n",
       "      <td>0.9</td>\n",
       "      <td>3</td>\n",
       "      <td>{'classifier__alpha': 1, 'classifier__fit_prio...</td>\n",
       "      <td>0.344794</td>\n",
       "      <td>0.332797</td>\n",
       "      <td>0.323581</td>\n",
       "      <td>0.333724</td>\n",
       "      <td>0.008685</td>\n",
       "      <td>6</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>0.001895</td>\n",
       "      <td>0.000174</td>\n",
       "      <td>0.001272</td>\n",
       "      <td>0.000105</td>\n",
       "      <td>0.5</td>\n",
       "      <td>True</td>\n",
       "      <td>0.9</td>\n",
       "      <td>3</td>\n",
       "      <td>{'classifier__alpha': 0.5, 'classifier__fit_pr...</td>\n",
       "      <td>0.349248</td>\n",
       "      <td>0.328047</td>\n",
       "      <td>0.277855</td>\n",
       "      <td>0.318383</td>\n",
       "      <td>0.029937</td>\n",
       "      <td>7</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>0.001901</td>\n",
       "      <td>0.000075</td>\n",
       "      <td>0.001156</td>\n",
       "      <td>0.000107</td>\n",
       "      <td>1.0</td>\n",
       "      <td>True</td>\n",
       "      <td>0.9</td>\n",
       "      <td>3</td>\n",
       "      <td>{'classifier__alpha': 1, 'classifier__fit_prio...</td>\n",
       "      <td>0.337362</td>\n",
       "      <td>0.306776</td>\n",
       "      <td>0.292058</td>\n",
       "      <td>0.312065</td>\n",
       "      <td>0.018870</td>\n",
       "      <td>8</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   mean_fit_time  std_fit_time  mean_score_time  std_score_time  \\\n",
       "2       0.002220      0.000173         0.001228        0.000017   \n",
       "6       0.002214      0.000084         0.001206        0.000011   \n",
       "0       0.008167      0.004108         0.001306        0.000036   \n",
       "4       0.002201      0.000114         0.001167        0.000094   \n",
       "3       0.001697      0.000039         0.001383        0.000154   \n",
       "7       0.001766      0.000113         0.001158        0.000053   \n",
       "1       0.001895      0.000174         0.001272        0.000105   \n",
       "5       0.001901      0.000075         0.001156        0.000107   \n",
       "\n",
       "   param_classifier__alpha  param_classifier__fit_prior  \\\n",
       "2                      0.5                        False   \n",
       "6                      1.0                        False   \n",
       "0                      0.5                         True   \n",
       "4                      1.0                         True   \n",
       "3                      0.5                        False   \n",
       "7                      1.0                        False   \n",
       "1                      0.5                         True   \n",
       "5                      1.0                         True   \n",
       "\n",
       "   param_vectorizer__max_df  param_vectorizer__min_df  \\\n",
       "2                       0.9                         1   \n",
       "6                       0.9                         1   \n",
       "0                       0.9                         1   \n",
       "4                       0.9                         1   \n",
       "3                       0.9                         3   \n",
       "7                       0.9                         3   \n",
       "1                       0.9                         3   \n",
       "5                       0.9                         3   \n",
       "\n",
       "                                              params  split0_test_score  \\\n",
       "2  {'classifier__alpha': 0.5, 'classifier__fit_pr...           0.455431   \n",
       "6  {'classifier__alpha': 1, 'classifier__fit_prio...           0.458154   \n",
       "0  {'classifier__alpha': 0.5, 'classifier__fit_pr...           0.422790   \n",
       "4  {'classifier__alpha': 1, 'classifier__fit_prio...           0.381607   \n",
       "3  {'classifier__alpha': 0.5, 'classifier__fit_pr...           0.348260   \n",
       "7  {'classifier__alpha': 1, 'classifier__fit_prio...           0.344794   \n",
       "1  {'classifier__alpha': 0.5, 'classifier__fit_pr...           0.349248   \n",
       "5  {'classifier__alpha': 1, 'classifier__fit_prio...           0.337362   \n",
       "\n",
       "   split1_test_score  split2_test_score  mean_test_score  std_test_score  \\\n",
       "2           0.434571           0.423547         0.437850        0.013221   \n",
       "6           0.415951           0.406097         0.426734        0.022578   \n",
       "0           0.389784           0.352330         0.388301        0.028784   \n",
       "4           0.382587           0.285005         0.349733        0.045772   \n",
       "3           0.358595           0.329416         0.345424        0.012080   \n",
       "7           0.332797           0.323581         0.333724        0.008685   \n",
       "1           0.328047           0.277855         0.318383        0.029937   \n",
       "5           0.306776           0.292058         0.312065        0.018870   \n",
       "\n",
       "   rank_test_score  \n",
       "2                1  \n",
       "6                2  \n",
       "0                3  \n",
       "4                4  \n",
       "3                5  \n",
       "7                6  \n",
       "1                7  \n",
       "5                8  "
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn.model_selection import GridSearchCV, GroupKFold\n",
    "import pandas as pd\n",
    "\n",
    "optimisation_pipeline = GridSearchCV(\n",
    "    create_pipeline(),\n",
    "    {\n",
    "        \"vectorizer__min_df\": ([5, 20, 100] if FULL_RUN else [1, 3]),\n",
    "        \"vectorizer__max_df\": ([0.05, 0.1] if FULL_RUN else [0.9]),\n",
    "        \"classifier__alpha\": [0.5, 1],\n",
    "        \"classifier__fit_prior\": [True, False],\n",
    "    },\n",
    "    scoring=\"f1_macro\",\n",
    "    cv=GroupKFold(n_splits=3),\n",
    "    n_jobs=2,\n",
    "    verbose=1,\n",
    ")\n",
    "# Group by paper text so that expanded labels and duplicate texts stay together.\n",
    "optimisation_pipeline.fit(X, y, groups=X)\n",
    "\n",
    "results = pd.DataFrame(optimisation_pipeline.cv_results_)\n",
    "results.sort_values(\"rank_test_score\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "cell-8",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-28T22:47:35.667075Z",
     "iopub.status.busy": "2026-10-28T22:47:35.667011Z",
     "iopub.status.idle": "2026-10-28T22:47:35.717496Z",
     "shell.execute_reply": "2026-10-28T22:47:35.716936Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<style>.sk-global {\n",
       "  /* Definition of color scheme common for light and dark mode */\n",
       "  --sklearn-color-text: #000;\n",
       "  --sklearn-color-text-muted: #666;\n",
       "  --sklearn-color-line: gray;\n",
       "  /* Definition of color scheme for unfitted estimators */\n",
       "  --sklearn-color-unfitted-level-0: #fff5e6;\n",
       "  --sklearn-color-unfitted-level-1: #f6e4d2;\n",
       "  --sklearn-color-unfitted-level-2: #ffe0b3;\n",
       "  --sklearn-color-unfitted-level-3: chocolate;\n",
       "  /* Definition of color scheme for fitted estimators */\n",
       "  --sklearn-color-fitted-level-0: #f0f8ff;\n",
       "  --sklearn-color-fitted-level-1: #d4ebff;\n",
       "  --sklearn-color-fitted-level-2: #b3dbfd;\n",
       "  --sklearn-color-fitted-level-3: cornflowerblue;\n",
       "}\n",
       "\n",
       ".sk-global.light {\n",
       "  /* Specific color for light theme */\n",
       "  --sklearn-color-text-on-default-background: black;\n",
       "  --sklearn-color-background: white;\n",
       "  --sklearn-color-border-box: black;\n",
       "  --sklearn-color-icon: #696969;\n",
       "}\n",
       "\n",
       ".sk-global.dark {\n",
       "  --sklearn-color-text-on-default-background: white;\n",
       "  --sklearn-color-background: #111;\n",
       "  --sklearn-color-border-box: white;\n",
       "  --sklearn-color-icon: #878787;\n",
       "}\n",
       "\n",
       ".sk-global {\n",
       "  color: var(--sklearn-color-text);\n",
       "}\n",
       "\n",
       ".sk-global pre {\n",
       "  padding: 0;\n",
       "}\n",
       "\n",
       ".sk-global input.sk-hidden--visually {\n",
       "  border: 0;\n",
       "  clip-path: inset(100%);\n",
       "  height: 1px;\n",
       "  margin: -1px;\n",
       "  overflow: hidden;\n",
       "  padding: 0;\n",
       "  position: absolute;\n",
       "  width: 1px;\n",
       "}\n",
       "\n",
       ".sk-global div.sk-dashed-wrapped {\n",
       "  border: 1px dashed var(--sklearn-color-line);\n",
       "  margin: 0 0.4em 0.5em 0.4em;\n",
       "  box-sizing: border-box;\n",
       "  padding-bottom: 0.4em;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "}\n",
       "\n",
       ".sk-global div.sk-container {\n",
       "  /* jupyter's `normalize.less` sets `[hidden] { display: none; }`\n",
       "     but bootstrap.min.css set `[hidden] { display: none !important; }`\n",
       "     so we also need the `!important` here to be able to override the\n",
       "     default hidden behavior on the sphinx rendered scikit-learn.org.\n",
       "     See: https://github.com/scikit-learn/scikit-learn/issues/21755 */\n",
       "  display: inline-block !important;\n",
       "  position: relative;\n",
       "}\n",
       "\n",
       ".sk-global div.sk-text-repr-fallback {\n",
       "  display: none;\n",
       "}\n",
       "\n",
       "div.sk-parallel-item,\n",
       "div.sk-serial,\n",
       "div.sk-item {\n",
       "  /* draw centered vertical line to link estimators */\n",
       "  background-image: linear-gradient(var(--sklearn-color-text-on-default-background), var(--sklearn-color-text-on-default-background));\n",
       "  background-size: 2px 100%;\n",
       "  background-repeat: no-repeat;\n",
       "  background-position: center center;\n",
       "}\n",
       "\n",
       "/* Parallel-specific style estimator block */\n",
       "\n",
       ".sk-global div.sk-parallel-item::after {\n",
       "  content: \"\";\n",
       "  width: 100%;\n",
       "  border-bottom: 2px solid var(--sklearn-color-text-on-default-background);\n",
       "  flex-grow: 1;\n",
       "}\n",
       "\n",
       ".sk-global div.sk-parallel {\n",
       "  display: flex;\n",
       "  align-items: stretch;\n",
       "  justify-content: center;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  position: relative;\n",
       "}\n",
       "\n",
       ".sk-global div.sk-parallel-item {\n",
       "  display: flex;\n",
       "  flex-direction: column;\n",
       "}\n",
       "\n",
       ".sk-global div.sk-parallel-item:first-child::after {\n",
       "  align-self: flex-end;\n",
       "  width: 50%;\n",
       "}\n",
       "\n",
       ".sk-global div.sk-parallel-item:last-child::after {\n",
       "  align-self: flex-start;\n",
       "  width: 50%;\n",
       "}\n",
       "\n",
       ".sk-global div.sk-parallel-item:only-child::after {\n",
       "  width: 0;\n",
       "}\n",
       "\n",
       "/* Serial-specific style estimator block */\n",
       "\n",
       ".sk-global div.sk-serial {\n",
       "  display: flex;\n",
       "  flex-direction: column;\n",
       "  align-items: center;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  padding-right: 1em;\n",
       "  padding-left: 1em;\n",
       "}\n",
       "\n",
       "\n",
       "/* Toggleable style: style used for estimator/Pipeline/ColumnTransformer box that is\n",
       "clickable and can be expanded/collapsed.\n",
       "- Pipeline and ColumnTransformer use this feature and define the default style\n",
       "- Estimators will overwrite some part of the style using the `sk-estimator` class\n",
       "*/\n",
       "\n",
       "/* Pipeline and ColumnTransformer style (default) */\n",
       "\n",
       ".sk-global div.sk-toggleable {\n",
       "  /* Default theme specific background. It is overwritten whether we have a\n",
       "  specific estimator or a Pipeline/ColumnTransformer */\n",
       "  background-color: var(--sklearn-color-background);\n",
       "}\n",
       "\n",
       "/* Toggleable label */\n",
       ".sk-global label.sk-toggleable__label {\n",
       "  cursor: pointer;\n",
       "  display: flex;\n",
       "  width: 100%;\n",
       "  margin-bottom: 0;\n",
       "  padding: 0.5em;\n",
       "  box-sizing: border-box;\n",
       "  text-align: center;\n",
       "  align-items: center;\n",
       "  justify-content: center;\n",
       "  gap: 0.5em;\n",
       "}\n",
       "\n",
       ".sk-global label.sk-toggleable__label .caption {\n",
       "  font-size: 0.6rem;\n",
       "  font-weight: lighter;\n",
       "  color: var(--sklearn-color-text-muted);\n",
       "}\n",
       "\n",
       ".sk-global label.sk-toggleable__label-arrow:before {\n",
       "  /* Arrow on the left of the label */\n",
       "  content: \"▸\";\n",
       "  float: left;\n",
       "  margin-right: 0.25em;\n",
       "  color: var(--sklearn-color-icon);\n",
       "}\n",
       "\n",
       ".sk-global label.sk-toggleable__label-arrow:hover:before {\n",
       "  color: var(--sklearn-color-text);\n",
       "}\n",
       "\n",
       "/* Toggleable content - dropdown */\n",
       "\n",
       ".sk-global div.sk-toggleable__content {\n",
       "  display: none;\n",
       "  text-align: left;\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "}\n",
       "\n",
       ".sk-global div.sk-toggleable__content.fitted {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "}\n",
       "\n",
       ".sk-global div.sk-toggleable__content pre {\n",
       "  margin: 0.2em;\n",
       "  border-radius: 0.25em;\n",
       "  color: var(--sklearn-color-text);\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "}\n",
       "\n",
       ".sk-global div.sk-toggleable__content.fitted pre {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "}\n",
       "\n",
       ".sk-global input.sk-toggleable__control:checked~div.sk-toggleable__content {\n",
       "  /* Expand drop-down */\n",
       "  display: block;\n",
       "  width: 100%;\n",
       "  overflow: visible;\n",
       "}\n",
       "\n",
       ".sk-global input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {\n",
       "  content: \"▾\";\n",
       "}\n",
       "\n",
       "/* Pipeline/ColumnTransformer-specific style */\n",
       "\n",
       ".sk-global div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  color: var(--sklearn-color-text);\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       ".sk-global div.sk-label.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "/* Estimator-specific style */\n",
       "\n",
       "/* Colorize estimator box */\n",
       ".sk-global div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       ".sk-global div.sk-estimator.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       ".sk-global div.sk-label label.sk-toggleable__label,\n",
       ".sk-global div.sk-label label {\n",
       "  /* The background is the default theme color */\n",
       "  color: var(--sklearn-color-text-on-default-background);\n",
       "}\n",
       "\n",
       "/* On hover, darken the color of the background */\n",
       ".sk-global div.sk-label:hover label.sk-toggleable__label {\n",
       "  color: var(--sklearn-color-text);\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "/* Label box, darken color on hover, fitted */\n",
       ".sk-global div.sk-label.fitted:hover label.sk-toggleable__label.fitted {\n",
       "  color: var(--sklearn-color-text);\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "/* Estimator label */\n",
       "\n",
       ".sk-global div.sk-label label {\n",
       "  font-family: monospace;\n",
       "  font-weight: bold;\n",
       "  line-height: 1.2em;\n",
       "}\n",
       "\n",
       ".sk-global div.sk-label-container {\n",
       "  text-align: center;\n",
       "}\n",
       "\n",
       "/* Estimator-specific */\n",
       ".sk-global div.sk-estimator {\n",
       "  font-family: monospace;\n",
       "  border: 1px dotted var(--sklearn-color-border-box);\n",
       "  border-radius: 0.25em;\n",
       "  box-sizing: border-box;\n",
       "  margin-bottom: 0.5em;\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "}\n",
       "\n",
       ".sk-global div.sk-estimator.fitted {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "}\n",
       "\n",
       "/* on hover */\n",
       ".sk-global div.sk-estimator:hover {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       ".sk-global div.sk-estimator.fitted:hover {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "/* Specification for estimator info (e.g. \"i\" and \"?\") */\n",
       "\n",
       "/* Common style for \"i\" and \"?\" */\n",
       "\n",
       ".sk-estimator-doc-link,\n",
       "a:link.sk-estimator-doc-link,\n",
       "a:visited.sk-estimator-doc-link {\n",
       "  float: right;\n",
       "  font-size: smaller;\n",
       "  line-height: 1em;\n",
       "  font-family: monospace;\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "  border-radius: 1em;\n",
       "  height: 1em;\n",
       "  width: 1em;\n",
       "  text-decoration: none !important;\n",
       "  margin-left: 0.5em;\n",
       "  text-align: center;\n",
       "  /* unfitted */\n",
       "  border: var(--sklearn-color-unfitted-level-3) 1pt solid;\n",
       "  color: var(--sklearn-color-unfitted-level-3);\n",
       "}\n",
       "\n",
       ".sk-estimator-doc-link.fitted,\n",
       "a:link.sk-estimator-doc-link.fitted,\n",
       "a:visited.sk-estimator-doc-link.fitted {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "  border: var(--sklearn-color-fitted-level-3) 1pt solid;\n",
       "  color: var(--sklearn-color-fitted-level-3);\n",
       "}\n",
       "\n",
       "/* On hover */\n",
       "div.sk-estimator:hover .sk-estimator-doc-link:hover,\n",
       ".sk-estimator-doc-link:hover,\n",
       "div.sk-label-container:hover .sk-estimator-doc-link:hover,\n",
       ".sk-estimator-doc-link:hover {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-3);\n",
       "  border: var(--sklearn-color-fitted-level-0) 1pt solid;\n",
       "  color: var(--sklearn-color-unfitted-level-0);\n",
       "  text-decoration: none;\n",
       "}\n",
       "\n",
       "div.sk-estimator.fitted:hover .sk-estimator-doc-link.fitted:hover,\n",
       ".sk-estimator-doc-link.fitted:hover,\n",
       "div.sk-label-container:hover .sk-estimator-doc-link.fitted:hover,\n",
       ".sk-estimator-doc-link.fitted:hover {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-3);\n",
       "  border: var(--sklearn-color-fitted-level-0) 1pt solid;\n",
       "  color: var(--sklearn-color-fitted-level-0);\n",
       "  text-decoration: none;\n",
       "}\n",
       "\n",
       "/* Span, style for the box shown on hovering the info icon */\n",
       ".sk-estimator-doc-link span {\n",
       "  display: none;\n",
       "  z-index: 9999;\n",
       "  position: relative;\n",
       "  font-weight: normal;\n",
       "  right: .2ex;\n",
       "  padding: .5ex;\n",
       "  margin: .5ex;\n",
       "  width: min-content;\n",
       "  min-width: 20ex;\n",
       "  max-width: 50ex;\n",
       "  color: var(--sklearn-color-text);\n",
       "  box-shadow: 2pt 2pt 4pt #999;\n",
       "  /* unfitted */\n",
       "  background: var(--sklearn-color-unfitted-level-0);\n",
       "  border: .5pt solid var(--sklearn-color-unfitted-level-3);\n",
       "}\n",
       "\n",
       ".sk-estimator-doc-link.fitted span {\n",
       "  /* fitted */\n",
       "  background: var(--sklearn-color-fitted-level-0);\n",
       "  border: var(--sklearn-color-fitted-level-3);\n",
       "}\n",
       "\n",
       ".sk-estimator-doc-link:hover span {\n",
       "  display: block;\n",
       "}\n",
       "\n",
       "/* \"?\"-specific style due to the `<a>` HTML tag */\n",
       "\n",
       ".sk-global a.estimator_doc_link {\n",
       "  float: right;\n",
       "  font-size: 1rem;\n",
       "  line-height: 1em;\n",
       "  font-family: monospace;\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "  border-radius: 1rem;\n",
       "  height: 1rem;\n",
       "  width: 1rem;\n",
       "  text-decoration: none;\n",
       "  /* unfitted */\n",
       "  color: var(--sklearn-color-unfitted-level-1);\n",
       "  border: var(--sklearn-color-unfitted-level-1) 1pt solid;\n",
       "}\n",
       "\n",
       ".sk-global a.estimator_doc_link.fitted {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "  border: var(--sklearn-color-fitted-level-1) 1pt solid;\n",
       "  color: var(--sklearn-color-fitted-level-1);\n",
       "}\n",
       "\n",
       "/* On hover */\n",
       ".sk-global a.estimator_doc_link:hover {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-3);\n",
       "  color: var(--sklearn-color-background);\n",
       "  text-decoration: none;\n",
       "}\n",
       "\n",
       ".sk-global a.estimator_doc_link.fitted:hover {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-3);\n",
       "}\n",
       "\n",
       ".sk-top-container.sk-global {\n",
       "  /* pydata-sphinx-theme hides overflow, so scrolling is disabled.\n",
       "   We need to set it to !important and add tabindex=\"0\" in the HTML\n",
       "   to allow keyboard-only users to navigate the display. */\n",
       "  overflow-x: scroll !important;\n",
       "  max-width: 100%;\n",
       "}\n",
       "\n",
       ".estimator-table {\n",
       "    font-family: monospace;\n",
       "}\n",
       "\n",
       ".estimator-table summary {\n",
       "    padding: .5rem;\n",
       "    cursor: pointer;\n",
       "}\n",
       "\n",
       ".estimator-table summary::marker {\n",
       "    font-size: 0.7rem;\n",
       "}\n",
       "\n",
       ".estimator-table details[open] {\n",
       "    padding-left: 0.1rem;\n",
       "    padding-right: 0.1rem;\n",
       "    padding-bottom: 0.3rem;\n",
       "}\n",
       "\n",
       ".estimator-table .parameters-table {\n",
       "    margin-left: auto !important;\n",
       "    margin-right: auto !important;\n",
       "    margin-top: 0;\n",
       "}\n",
       "\n",
       ".estimator-table .parameters-table tr:nth-child(odd) {\n",
       "    background-color: #fff;\n",
       "}\n",
       "\n",
       ".estimator-table .parameters-table tr:nth-child(even) {\n",
       "    background-color: #f6f6f6;\n",
       "}\n",
       "\n",
       ".estimator-table .parameters-table tr:hover td {\n",
       "    background-color: #e0e0e0;\n",
       "}\n",
       "\n",
       ".estimator-table table :is(td, th) {\n",
       "    border: 1px solid rgba(106, 105, 104, 0.232);\n",
       "}\n",
       "\n",
       "/*\n",
       "    `table td`is set in notebook with right text-align.\n",
       "    We need to overwrite it.\n",
       "*/\n",
       ".estimator-table table td.param {\n",
       "    text-align: left;\n",
       "    position: relative;\n",
       "    padding: 0;\n",
       "}\n",
       "\n",
       ".user-set td {\n",
       "    color:rgb(255, 94, 0);\n",
       "    text-align: left !important;\n",
       "}\n",
       "\n",
       ".user-set td.value {\n",
       "    color:rgb(255, 94, 0);\n",
       "    background-color: transparent;\n",
       "}\n",
       "\n",
       ".default td, .estimator-table th {\n",
       "    color: black;\n",
       "    text-align: left !important;\n",
       "}\n",
       "\n",
       ".user-set td i,\n",
       ".default td i {\n",
       "    color: black;\n",
       "}\n",
       "\n",
       "td.fitted-att-type {\n",
       "    white-space: preserve nowrap;\n",
       "}\n",
       "\n",
       "/*\n",
       "    Styles for parameter documentation links\n",
       "    We need styling for visited so jupyter doesn't overwrite it\n",
       "*/\n",
       "a.param-doc-link,\n",
       "a.param-doc-link:link,\n",
       "a.param-doc-link:visited {\n",
       "    text-decoration: underline dashed;\n",
       "    text-underline-offset: .3em;\n",
       "    color: inherit;\n",
       "    display: block;\n",
       "    padding: .5em;\n",
       "}\n",
       "\n",
       "@supports(anchor-name: --doc-link) {\n",
       "    a.param-doc-link,\n",
       "    a.param-doc-link:link,\n",
       "    a.param-doc-link:visited {\n",
       "    anchor-name: --doc-link;\n",
       "    }\n",
       "}\n",
       "\n",
       "/* \"hack\" to make the entire area of the cell containing the link clickable */\n",
       "a.param-doc-link::before {\n",
       "    position: absolute;\n",
       "    content: \"\";\n",
       "    inset: 0;\n",
       "}\n",
       "\n",
       ".param-doc-description {\n",
       "    display: none;\n",
       "    position: absolute;\n",
       "    z-index: 9999;\n",
       "    left: 0;\n",
       "    padding: .5ex;\n",
       "    margin-left: 1.5em;\n",
       "    color: var(--sklearn-color-text);\n",
       "    box-shadow: .3em .3em .4em #999;\n",
       "    width: max-content;\n",
       "    text-align: left;\n",
       "    max-height: 10em;\n",
       "    overflow-y: auto;\n",
       "\n",
       "    /* unfitted */\n",
       "    background: var(--sklearn-color-unfitted-level-0);\n",
       "    border: thin solid var(--sklearn-color-unfitted-level-3);\n",
       "}\n",
       "\n",
       "@supports(position-area: center right) {\n",
       "    .param-doc-description {\n",
       "    position-area: center right;\n",
       "    position: fixed;\n",
       "    margin-left: 0;\n",
       "    }\n",
       "}\n",
       "\n",
       "/* Fitted state for parameter tooltips */\n",
       ".fitted .param-doc-description {\n",
       "    /* fitted */\n",
       "    background: var(--sklearn-color-fitted-level-0);\n",
       "    border: thin solid var(--sklearn-color-fitted-level-3);\n",
       "}\n",
       "\n",
       ".param-doc-link:hover .param-doc-description {\n",
       "    display: block;\n",
       "}\n",
       "\n",
       ".copy-paste-icon {\n",
       "    background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0NDggNTEyIj48IS0tIUZvbnQgQXdlc29tZSBGcmVlIDYuNy4yIGJ5IEBmb250YXdlc29tZSAtIGh0dHBzOi8vZm9udGF3ZXNvbWUuY29tIExpY2Vuc2UgLSBodHRwczovL2ZvbnRhd2Vzb21lLmNvbS9saWNlbnNlL2ZyZWUgQ29weXJpZ2h0IDIwMjUgRm9udGljb25zLCBJbmMuLS0+PHBhdGggZD0iTTIwOCAwTDMzMi4xIDBjMTIuNyAwIDI0LjkgNS4xIDMzLjkgMTQuMWw2Ny45IDY3LjljOSA5IDE0LjEgMjEuMiAxNC4xIDMzLjlMNDQ4IDMzNmMwIDI2LjUtMjEuNSA0OC00OCA0OGwtMTkyIDBjLTI2LjUgMC00OC0yMS41LTQ4LTQ4bDAtMjg4YzAtMjYuNSAyMS41LTQ4IDQ4LTQ4ek00OCAxMjhsODAgMCAwIDY0LTY0IDAgMCAyNTYgMTkyIDAgMC0zMiA2NCAwIDAgNDhjMCAyNi41LTIxLjUgNDgtNDggNDhMNDggNTEyYy0yNi41IDAtNDgtMjEuNS00OC00OEwwIDE3NmMwLTI2LjUgMjEuNS00OCA0OC00OHoiLz48L3N2Zz4=);\n",
       "    background-repeat: no-repeat;\n",
       "    background-size: 14px 14px;\n",
       "    background-position: 0;\n",
       "    display: inline-block;\n",
       "    width: 14px;\n",
       "    height: 14px;\n",
       "    cursor: pointer;\n",
       "    border: none;\n",
       "    padding: 0;\n",
       "    background-color: transparent;\n",
       "}\n",
       "\n",
       ".copy-paste-icon:focus-visible {\n",
       "    outline: 1px solid currentColor;\n",
       "    outline-offset: 1px;\n",
       "}\n",
       "\n",
       ".features {\n",
       "  font-family: monospace;\n",
       "  cursor: pointer;\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "  border: 1px dotted var(--sklearn-color-border-box);\n",
       "  border-radius: .20em;\n",
       "  margin-bottom: 0.5em;\n",
       "  font-size: inherit; /* Needed for jupyter */\n",
       "}\n",
       "\n",
       ".features.fitted {\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "}\n",
       "\n",
       ".features summary {\n",
       "  cursor: pointer;\n",
       "  display: flex;\n",
       "  margin-bottom: 0;\n",
       "  text-align: center;\n",
       "  align-items: center;\n",
       "  justify-content: center;\n",
       "  gap: 0.5em;\n",
       "  padding: .25em;\n",
       "}\n",
       "\n",
       ".features details[open] > summary {\n",
       "  color: var(--sklearn-color-text);\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "  border-radius: .20em 0 0 0;\n",
       "}\n",
       "\n",
       ".features.fitted details[open] > summary {\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "  border-radius: .20em 0 0 0;\n",
       "}\n",
       "\n",
       ".features details > summary .arrow::before {\n",
       "  content: \"▸\";\n",
       "  color: grey;\n",
       "}\n",
       "\n",
       ".features details[open] > summary .arrow::before {\n",
       "  content: \"▾\";\n",
       "}\n",
       "\n",
       ".features details:hover > summary {\n",
       "  margin: 0;\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       ".features.fitted details:hover > summary {\n",
       "  margin: 0;\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       ".features .features-container {\n",
       "  max-height: 10em;\n",
       "  overflow: auto;\n",
       "  scrollbar-width: thin;\n",
       "  padding: .25em 0.1rem;\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "  border-radius: 0 0 .5em .5em;\n",
       "}\n",
       "\n",
       ".features.fitted .features-container {\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "}\n",
       "\n",
       ".features .image-container {\n",
       "  block-size: 1em;\n",
       "  inline-size: 1em;\n",
       "  padding: 0;\n",
       "  margin: 0%;\n",
       "  display: flex;\n",
       "  justify-content: center;\n",
       "  align-items: center;\n",
       "}\n",
       "\n",
       ".features .copy-paste-icon {\n",
       "  background-size: 1em 1em;\n",
       "  width: 1em;\n",
       "  height: 1em;\n",
       "  filter: grayscale(100%) opacity(60%);\n",
       "}\n",
       "\n",
       ".features .features-container table {\n",
       "  width: 100%;\n",
       "  margin: 0.01em;\n",
       "}\n",
       "\n",
       ".features .features-container table tr:nth-child(odd) {\n",
       "  background-color: #fff;\n",
       "}\n",
       "\n",
       ".features .features-container table tr:nth-child(even) {\n",
       "  background-color: #f6f6f6;\n",
       "}\n",
       "\n",
       ".features .features-container table tr:hover {\n",
       "  background-color: #e0e0e0;\n",
       "}\n",
       "\n",
       ".features .features-container table {\n",
       "  table-layout: inherit;\n",
       "}\n",
       "\n",
       ".features .features-container table td {\n",
       "  text-align: left;\n",
       "  padding: 0 0.5em;\n",
       "  border: 1px solid rgba(106, 105, 104, 0.232);\n",
       "  white-space: nowrap;\n",
       "  color: var(--sklearn-color-text);\n",
       "}\n",
       "\n",
       ".total_features {\n",
       "  display: flex;\n",
       "  justify-content: center;\n",
       "  margin-top: 0.5em;\n",
       "}\n",
       "</style><body><div id=\"sk-container-id-1\" tabindex=\"0\" class=\"sk-top-container sk-global\"><div class=\"sk-text-repr-fallback\"><pre>Pipeline(steps=[(&#x27;vectorizer&#x27;, TfidfVectorizer(max_df=0.9, 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 fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually sk-global\" id=\"sk-estimator-id-1\" type=\"checkbox\" ><label for=\"sk-estimator-id-1\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow\"><div><div>Pipeline</div></div><div><a class=\"sk-estimator-doc-link fitted\" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.pipeline.Pipeline.html\">?<span>Documentation for Pipeline</span></a><span class=\"sk-estimator-doc-link fitted\">i<span>Fitted</span></span></div></label><div class=\"sk-toggleable__content fitted\" data-param-prefix=\"\">\n",
       "        <div class=\"estimator-table\">\n",
       "            <details>\n",
       "                <summary>Parameters</summary>\n",
       "                <table class=\"parameters-table\">\n",
       "                  <tbody>\n",
       "                    \n",
       "        <tr class=\"user-set\">\n",
       "            <td><button type=\"button\" class=\"copy-paste-icon\"\n",
       "                 aria-label=\"Copy steps to clipboard\"\n",
       "                 onclick=\"copyToClipboard('steps',\n",
       "                          this.parentElement.nextElementSibling)\"\n",
       "            ></button></td>\n",
       "            <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-steps;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.pipeline.Pipeline.html#:~:text=steps,-list%20of%20tuples\">\n",
       "            steps\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-steps;\">\n",
       "            steps: list of tuples<br><br>List of (name of step, estimator) tuples that are to be chained in<br>sequential order. To be compatible with the scikit-learn API, all steps<br>must define `fit`. All non-last steps must also define `transform`. See<br>:ref:`Combining Estimators &lt;combining_estimators&gt;` for more details.</span>\n",
       "        </a>\n",
       "    </td>\n",
       "            <td class=\"value\">[(&#x27;vectorizer&#x27;, ...), (&#x27;classifier&#x27;, ...)]</td>\n",
       "        </tr>\n",
       "    \n",
       "\n",
       "        <tr class=\"default\">\n",
       "            <td><button type=\"button\" class=\"copy-paste-icon\"\n",
       "                 aria-label=\"Copy transform_input to clipboard\"\n",
       "                 onclick=\"copyToClipboard('transform_input',\n",
       "                          this.parentElement.nextElementSibling)\"\n",
       "            ></button></td>\n",
       "            <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-transform_input;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.pipeline.Pipeline.html#:~:text=transform_input,-list%20of%20str%2C%20default%3DNone\">\n",
       "            transform_input\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-transform_input;\">\n",
       "            transform_input: list of str, default=None<br><br>The names of the :term:`metadata` parameters that should be transformed by the<br>pipeline before passing it to the step consuming it.<br><br>This enables transforming some input arguments to ``fit`` (other than ``X``)<br>to be transformed by the steps of the pipeline up to the step which requires<br>them. Requirement is defined via :ref:`metadata routing &lt;metadata_routing&gt;`.<br>For instance, this can be used to pass a validation set through the pipeline.<br><br>You can only set this if metadata routing is enabled, which you<br>can enable using ``sklearn.set_config(enable_metadata_routing=True)``.<br><br>.. versionadded:: 1.6</span>\n",
       "        </a>\n",
       "    </td>\n",
       "            <td class=\"value\">None</td>\n",
       "        </tr>\n",
       "    \n",
       "\n",
       "        <tr class=\"default\">\n",
       "            <td><button type=\"button\" class=\"copy-paste-icon\"\n",
       "                 aria-label=\"Copy memory to clipboard\"\n",
       "                 onclick=\"copyToClipboard('memory',\n",
       "                          this.parentElement.nextElementSibling)\"\n",
       "            ></button></td>\n",
       "            <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-memory;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.pipeline.Pipeline.html#:~:text=memory,-str%20or%20object%20with%20the%20joblib.Memory%20interface%2C%20default%3DNone\">\n",
       "            memory\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-memory;\">\n",
       "            memory: str or object with the joblib.Memory interface, default=None<br><br>Used to cache the fitted transformers of the pipeline. The last step<br>will never be cached, even if it is a transformer. By default, no<br>caching is performed. If a string is given, it is the path to the<br>caching directory. Enabling caching triggers a clone of the transformers<br>before fitting. Therefore, the transformer instance given to the<br>pipeline cannot be inspected directly. Use the attribute ``named_steps``<br>or ``steps`` to inspect estimators within the pipeline. Caching the<br>transformers is advantageous when fitting is time consuming. See<br>:ref:`sphx_glr_auto_examples_neighbors_plot_caching_nearest_neighbors.py`<br>for an example on how to enable caching.</span>\n",
       "        </a>\n",
       "    </td>\n",
       "            <td class=\"value\">None</td>\n",
       "        </tr>\n",
       "    \n",
       "\n",
       "        <tr class=\"default\">\n",
       "            <td><button type=\"button\" class=\"copy-paste-icon\"\n",
       "                 aria-label=\"Copy verbose to clipboard\"\n",
       "                 onclick=\"copyToClipboard('verbose',\n",
       "                          this.parentElement.nextElementSibling)\"\n",
       "            ></button></td>\n",
       "            <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-verbose;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.pipeline.Pipeline.html#:~:text=verbose,-bool%2C%20default%3DFalse\">\n",
       "            verbose\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-verbose;\">\n",
       "            verbose: bool, default=False<br><br>If True, the time elapsed while fitting each step will be printed as it<br>is completed.</span>\n",
       "        </a>\n",
       "    </td>\n",
       "            <td class=\"value\">False</td>\n",
       "        </tr>\n",
       "    \n",
       "                  </tbody>\n",
       "                </table>\n",
       "            </details>\n",
       "        </div>\n",
       "    \n",
       "        <div class=\"estimator-table\">\n",
       "            <details>\n",
       "                <summary>Fitted attributes</summary>\n",
       "                <table class=\"parameters-table\">\n",
       "                    <tbody>\n",
       "                        <tr>\n",
       "                        <th>Name</th>\n",
       "                        <th>Type</th>\n",
       "                        <th>Value</th>\n",
       "                        </tr>\n",
       "                        \n",
       "       <tr class=\"default\">\n",
       "           <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-classes_;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.pipeline.Pipeline.html#:~:text=classes_,-ndarray%20of%20shape%20%28n_classes%2C%29\">\n",
       "            classes_\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-classes_;\">\n",
       "            classes_: ndarray of shape (n_classes,)<br><br>The classes labels. Only exist if the last step of the pipeline is a<br>classifier.</span>\n",
       "        </a>\n",
       "    </td>\n",
       "           <td class=\"fitted-att-type\">ndarray[&lt;U10](7,)</td>\n",
       "           <td>[&#x27;business&#x27;,&#x27;economics&#x27;,&#x27;geography&#x27;,...,&#x27;politics&#x27;,&#x27;psychology&#x27;,\n",
       " &#x27;sociology&#x27;]</td>\n",
       "\n",
       "\n",
       "       </tr>\n",
       "    \n",
       "                    </tbody>\n",
       "                </table>\n",
       "            </details>\n",
       "        </div>\n",
       "    </div></div></div><div class=\"sk-serial\"><div class=\"sk-item\"><div class=\"sk-estimator fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually sk-global\" id=\"sk-estimator-id-2\" type=\"checkbox\" ><label for=\"sk-estimator-id-2\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow\"><div><div>TfidfVectorizer</div></div><div><a class=\"sk-estimator-doc-link fitted\" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html\">?<span>Documentation for TfidfVectorizer</span></a></div></label><div class=\"sk-toggleable__content fitted\" data-param-prefix=\"vectorizer__\">\n",
       "        <div class=\"estimator-table\">\n",
       "            <details>\n",
       "                <summary>Parameters</summary>\n",
       "                <table class=\"parameters-table\">\n",
       "                  <tbody>\n",
       "                    \n",
       "        <tr class=\"user-set\">\n",
       "            <td><button type=\"button\" class=\"copy-paste-icon\"\n",
       "                 aria-label=\"Copy max_df to clipboard\"\n",
       "                 onclick=\"copyToClipboard('max_df',\n",
       "                          this.parentElement.nextElementSibling)\"\n",
       "            ></button></td>\n",
       "            <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-max_df;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html#:~:text=max_df,-float%20or%20int%2C%20default%3D1.0\">\n",
       "            max_df\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-max_df;\">\n",
       "            max_df: float or int, default=1.0<br><br>When building the vocabulary ignore terms that have a document<br>frequency strictly higher than the given threshold (corpus-specific<br>stop words).<br>If float in range [0.0, 1.0], the parameter represents a proportion of<br>documents, integer absolute counts.<br>This parameter is ignored if vocabulary is not None.</span>\n",
       "        </a>\n",
       "    </td>\n",
       "            <td class=\"value\">0.9</td>\n",
       "        </tr>\n",
       "    \n",
       "\n",
       "        <tr class=\"user-set\">\n",
       "            <td><button type=\"button\" class=\"copy-paste-icon\"\n",
       "                 aria-label=\"Copy sublinear_tf to clipboard\"\n",
       "                 onclick=\"copyToClipboard('sublinear_tf',\n",
       "                          this.parentElement.nextElementSibling)\"\n",
       "            ></button></td>\n",
       "            <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-sublinear_tf;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html#:~:text=sublinear_tf,-bool%2C%20default%3DFalse\">\n",
       "            sublinear_tf\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-sublinear_tf;\">\n",
       "            sublinear_tf: bool, default=False<br><br>Apply sublinear tf scaling, i.e. replace tf with 1 + log(tf).</span>\n",
       "        </a>\n",
       "    </td>\n",
       "            <td class=\"value\">True</td>\n",
       "        </tr>\n",
       "    \n",
       "\n",
       "        <tr class=\"default\">\n",
       "            <td><button type=\"button\" class=\"copy-paste-icon\"\n",
       "                 aria-label=\"Copy input to clipboard\"\n",
       "                 onclick=\"copyToClipboard('input',\n",
       "                          this.parentElement.nextElementSibling)\"\n",
       "            ></button></td>\n",
       "            <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-input;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html#:~:text=input,-%7B%27filename%27%2C%20%27file%27%2C%20%27content%27%7D%2C%20default%3D%27content%27\">\n",
       "            input\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-input;\">\n",
       "            input: {&#x27;filename&#x27;, &#x27;file&#x27;, &#x27;content&#x27;}, default=&#x27;content&#x27;<br><br>- If `&#x27;filename&#x27;`, the sequence passed as an argument to fit is<br>  expected to be a list of filenames that need reading to fetch<br>  the raw content to analyze.<br><br>- If `&#x27;file&#x27;`, the sequence items must have a &#x27;read&#x27; method (file-like<br>  object) that is called to fetch the bytes in memory.<br><br>- If `&#x27;content&#x27;`, the input is expected to be a sequence of items that<br>  can be of type string or byte.</span>\n",
       "        </a>\n",
       "    </td>\n",
       "            <td class=\"value\">&#x27;content&#x27;</td>\n",
       "        </tr>\n",
       "    \n",
       "\n",
       "        <tr class=\"default\">\n",
       "            <td><button type=\"button\" class=\"copy-paste-icon\"\n",
       "                 aria-label=\"Copy encoding to clipboard\"\n",
       "                 onclick=\"copyToClipboard('encoding',\n",
       "                          this.parentElement.nextElementSibling)\"\n",
       "            ></button></td>\n",
       "            <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-encoding;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html#:~:text=encoding,-str%2C%20default%3D%27utf-8%27\">\n",
       "            encoding\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-encoding;\">\n",
       "            encoding: str, default=&#x27;utf-8&#x27;<br><br>If bytes or files are given to analyze, this encoding is used to<br>decode.</span>\n",
       "        </a>\n",
       "    </td>\n",
       "            <td class=\"value\">&#x27;utf-8&#x27;</td>\n",
       "        </tr>\n",
       "    \n",
       "\n",
       "        <tr class=\"default\">\n",
       "            <td><button type=\"button\" class=\"copy-paste-icon\"\n",
       "                 aria-label=\"Copy decode_error to clipboard\"\n",
       "                 onclick=\"copyToClipboard('decode_error',\n",
       "                          this.parentElement.nextElementSibling)\"\n",
       "            ></button></td>\n",
       "            <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-decode_error;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html#:~:text=decode_error,-%7B%27strict%27%2C%20%27ignore%27%2C%20%27replace%27%7D%2C%20default%3D%27strict%27\">\n",
       "            decode_error\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-decode_error;\">\n",
       "            decode_error: {&#x27;strict&#x27;, &#x27;ignore&#x27;, &#x27;replace&#x27;}, default=&#x27;strict&#x27;<br><br>Instruction on what to do if a byte sequence is given to analyze that<br>contains characters not of the given `encoding`. By default, it is<br>&#x27;strict&#x27;, meaning that a UnicodeDecodeError will be raised. Other<br>values are &#x27;ignore&#x27; and &#x27;replace&#x27;.</span>\n",
       "        </a>\n",
       "    </td>\n",
       "            <td class=\"value\">&#x27;strict&#x27;</td>\n",
       "        </tr>\n",
       "    \n",
       "\n",
       "        <tr class=\"default\">\n",
       "            <td><button type=\"button\" class=\"copy-paste-icon\"\n",
       "                 aria-label=\"Copy strip_accents to clipboard\"\n",
       "                 onclick=\"copyToClipboard('strip_accents',\n",
       "                          this.parentElement.nextElementSibling)\"\n",
       "            ></button></td>\n",
       "            <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-strip_accents;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html#:~:text=strip_accents,-%7B%27ascii%27%2C%20%27unicode%27%7D%20or%20callable%2C%20default%3DNone\">\n",
       "            strip_accents\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-strip_accents;\">\n",
       "            strip_accents: {&#x27;ascii&#x27;, &#x27;unicode&#x27;} or callable, default=None<br><br>Remove accents and perform other character normalization<br>during the preprocessing step.<br>&#x27;ascii&#x27; is a fast method that only works on characters that have<br>a direct ASCII mapping.<br>&#x27;unicode&#x27; is a slightly slower method that works on any characters.<br>None (default) means no character normalization is performed.<br><br>Both &#x27;ascii&#x27; and &#x27;unicode&#x27; use NFKD normalization from<br>:func:`unicodedata.normalize`.</span>\n",
       "        </a>\n",
       "    </td>\n",
       "            <td class=\"value\">None</td>\n",
       "        </tr>\n",
       "    \n",
       "\n",
       "        <tr class=\"default\">\n",
       "            <td><button type=\"button\" class=\"copy-paste-icon\"\n",
       "                 aria-label=\"Copy lowercase to clipboard\"\n",
       "                 onclick=\"copyToClipboard('lowercase',\n",
       "                          this.parentElement.nextElementSibling)\"\n",
       "            ></button></td>\n",
       "            <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-lowercase;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html#:~:text=lowercase,-bool%2C%20default%3DTrue\">\n",
       "            lowercase\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-lowercase;\">\n",
       "            lowercase: bool, default=True<br><br>Convert all characters to lowercase before tokenizing.</span>\n",
       "        </a>\n",
       "    </td>\n",
       "            <td class=\"value\">True</td>\n",
       "        </tr>\n",
       "    \n",
       "\n",
       "        <tr class=\"default\">\n",
       "            <td><button type=\"button\" class=\"copy-paste-icon\"\n",
       "                 aria-label=\"Copy preprocessor to clipboard\"\n",
       "                 onclick=\"copyToClipboard('preprocessor',\n",
       "                          this.parentElement.nextElementSibling)\"\n",
       "            ></button></td>\n",
       "            <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-preprocessor;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html#:~:text=preprocessor,-callable%2C%20default%3DNone\">\n",
       "            preprocessor\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-preprocessor;\">\n",
       "            preprocessor: callable, default=None<br><br>Override the preprocessing (string transformation) stage while<br>preserving the tokenizing and n-grams generation steps.<br>Only applies if ``analyzer`` is not callable.</span>\n",
       "        </a>\n",
       "    </td>\n",
       "            <td class=\"value\">None</td>\n",
       "        </tr>\n",
       "    \n",
       "\n",
       "        <tr class=\"default\">\n",
       "            <td><button type=\"button\" class=\"copy-paste-icon\"\n",
       "                 aria-label=\"Copy tokenizer to clipboard\"\n",
       "                 onclick=\"copyToClipboard('tokenizer',\n",
       "                          this.parentElement.nextElementSibling)\"\n",
       "            ></button></td>\n",
       "            <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-tokenizer;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html#:~:text=tokenizer,-callable%2C%20default%3DNone\">\n",
       "            tokenizer\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-tokenizer;\">\n",
       "            tokenizer: callable, default=None<br><br>Override the string tokenization step while preserving the<br>preprocessing and n-grams generation steps.<br>Only applies if ``analyzer == &#x27;word&#x27;``.</span>\n",
       "        </a>\n",
       "    </td>\n",
       "            <td class=\"value\">None</td>\n",
       "        </tr>\n",
       "    \n",
       "\n",
       "        <tr class=\"default\">\n",
       "            <td><button type=\"button\" class=\"copy-paste-icon\"\n",
       "                 aria-label=\"Copy analyzer to clipboard\"\n",
       "                 onclick=\"copyToClipboard('analyzer',\n",
       "                          this.parentElement.nextElementSibling)\"\n",
       "            ></button></td>\n",
       "            <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-analyzer;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html#:~:text=analyzer,-%7B%27word%27%2C%20%27char%27%2C%20%27char_wb%27%7D%20or%20callable%2C%20default%3D%27word%27\">\n",
       "            analyzer\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-analyzer;\">\n",
       "            analyzer: {&#x27;word&#x27;, &#x27;char&#x27;, &#x27;char_wb&#x27;} or callable, default=&#x27;word&#x27;<br><br>Whether the feature should be made of word or character n-grams.<br>Option &#x27;char_wb&#x27; creates character n-grams only from text inside<br>word boundaries; n-grams at the edges of words are padded with space.<br><br>If a callable is passed it is used to extract the sequence of features<br>out of the raw, unprocessed input.<br><br>.. versionchanged:: 0.21<br>    Since v0.21, if ``input`` is ``&#x27;filename&#x27;`` or ``&#x27;file&#x27;``, the data<br>    is first read from the file and then passed to the given callable<br>    analyzer.</span>\n",
       "        </a>\n",
       "    </td>\n",
       "            <td class=\"value\">&#x27;word&#x27;</td>\n",
       "        </tr>\n",
       "    \n",
       "\n",
       "        <tr class=\"default\">\n",
       "            <td><button type=\"button\" class=\"copy-paste-icon\"\n",
       "                 aria-label=\"Copy stop_words to clipboard\"\n",
       "                 onclick=\"copyToClipboard('stop_words',\n",
       "                          this.parentElement.nextElementSibling)\"\n",
       "            ></button></td>\n",
       "            <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-stop_words;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html#:~:text=stop_words,-%7B%27english%27%7D%2C%20list%2C%20default%3DNone\">\n",
       "            stop_words\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-stop_words;\">\n",
       "            stop_words: {&#x27;english&#x27;}, list, default=None<br><br>If a string, it is passed to _check_stop_list and the appropriate stop<br>list is returned. &#x27;english&#x27; is currently the only supported string<br>value.<br>There are several known issues with &#x27;english&#x27; and you should<br>consider an alternative (see :ref:`stop_words`).<br><br>If a list, that list is assumed to contain stop words, all of which<br>will be removed from the resulting tokens.<br>Only applies if ``analyzer == &#x27;word&#x27;``.<br><br>If None, no stop words will be used. In this case, setting `max_df`<br>to a higher value, such as in the range (0.7, 1.0), can automatically detect<br>and filter stop words based on intra corpus document frequency of terms.</span>\n",
       "        </a>\n",
       "    </td>\n",
       "            <td class=\"value\">None</td>\n",
       "        </tr>\n",
       "    \n",
       "\n",
       "        <tr class=\"default\">\n",
       "            <td><button type=\"button\" class=\"copy-paste-icon\"\n",
       "                 aria-label=\"Copy token_pattern to clipboard\"\n",
       "                 onclick=\"copyToClipboard('token_pattern',\n",
       "                          this.parentElement.nextElementSibling)\"\n",
       "            ></button></td>\n",
       "            <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-token_pattern;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html#:~:text=token_pattern,-str%2C%20default%3Dr%22%28%3Fu%29%5C%5Cb%5C%5Cw%5C%5Cw%2B%5C%5Cb%22\">\n",
       "            token_pattern\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-token_pattern;\">\n",
       "            token_pattern: str, default=r&quot;(?u)\\\\b\\\\w\\\\w+\\\\b&quot;<br><br>Regular expression denoting what constitutes a &quot;token&quot;, only used<br>if ``analyzer == &#x27;word&#x27;``. The default regexp selects tokens of 2<br>or more alphanumeric characters (punctuation is completely ignored<br>and always treated as a token separator).<br><br>If there is a capturing group in token_pattern then the<br>captured group content, not the entire match, becomes the token.<br>At most one capturing group is permitted.</span>\n",
       "        </a>\n",
       "    </td>\n",
       "            <td class=\"value\">&#x27;(?u)\\\\b\\\\w\\\\w+\\\\b&#x27;</td>\n",
       "        </tr>\n",
       "    \n",
       "\n",
       "        <tr class=\"default\">\n",
       "            <td><button type=\"button\" class=\"copy-paste-icon\"\n",
       "                 aria-label=\"Copy ngram_range to clipboard\"\n",
       "                 onclick=\"copyToClipboard('ngram_range',\n",
       "                          this.parentElement.nextElementSibling)\"\n",
       "            ></button></td>\n",
       "            <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-ngram_range;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html#:~:text=ngram_range,-tuple%20%28min_n%2C%20max_n%29%2C%20default%3D%281%2C%201%29\">\n",
       "            ngram_range\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-ngram_range;\">\n",
       "            ngram_range: tuple (min_n, max_n), default=(1, 1)<br><br>The lower and upper boundary of the range of n-values for different<br>n-grams to be extracted. All values of n such that min_n &lt;= n &lt;= max_n<br>will be used. For example an ``ngram_range`` of ``(1, 1)`` means only<br>unigrams, ``(1, 2)`` means unigrams and bigrams, and ``(2, 2)`` means<br>only bigrams.<br>Only applies if ``analyzer`` is not callable.</span>\n",
       "        </a>\n",
       "    </td>\n",
       "            <td class=\"value\">(1, ...)</td>\n",
       "        </tr>\n",
       "    \n",
       "\n",
       "        <tr class=\"default\">\n",
       "            <td><button type=\"button\" class=\"copy-paste-icon\"\n",
       "                 aria-label=\"Copy min_df to clipboard\"\n",
       "                 onclick=\"copyToClipboard('min_df',\n",
       "                          this.parentElement.nextElementSibling)\"\n",
       "            ></button></td>\n",
       "            <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-min_df;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html#:~:text=min_df,-float%20or%20int%2C%20default%3D1\">\n",
       "            min_df\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-min_df;\">\n",
       "            min_df: float or int, default=1<br><br>When building the vocabulary ignore terms that have a document<br>frequency strictly lower than the given threshold. This value is also<br>called cut-off in the literature.<br>If float in range of [0.0, 1.0], the parameter represents a proportion<br>of documents, integer absolute counts.<br>This parameter is ignored if vocabulary is not None.</span>\n",
       "        </a>\n",
       "    </td>\n",
       "            <td class=\"value\">1</td>\n",
       "        </tr>\n",
       "    \n",
       "\n",
       "        <tr class=\"default\">\n",
       "            <td><button type=\"button\" class=\"copy-paste-icon\"\n",
       "                 aria-label=\"Copy max_features to clipboard\"\n",
       "                 onclick=\"copyToClipboard('max_features',\n",
       "                          this.parentElement.nextElementSibling)\"\n",
       "            ></button></td>\n",
       "            <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-max_features;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html#:~:text=max_features,-int%2C%20default%3DNone\">\n",
       "            max_features\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-max_features;\">\n",
       "            max_features: int, default=None<br><br>If not None, build a vocabulary that only consider the top<br>`max_features` ordered by term frequency across the corpus.<br>Otherwise, all features are used.<br><br>This parameter is ignored if vocabulary is not None.</span>\n",
       "        </a>\n",
       "    </td>\n",
       "            <td class=\"value\">None</td>\n",
       "        </tr>\n",
       "    \n",
       "\n",
       "        <tr class=\"default\">\n",
       "            <td><button type=\"button\" class=\"copy-paste-icon\"\n",
       "                 aria-label=\"Copy vocabulary to clipboard\"\n",
       "                 onclick=\"copyToClipboard('vocabulary',\n",
       "                          this.parentElement.nextElementSibling)\"\n",
       "            ></button></td>\n",
       "            <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-vocabulary;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html#:~:text=vocabulary,-Mapping%20or%20iterable%2C%20default%3DNone\">\n",
       "            vocabulary\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-vocabulary;\">\n",
       "            vocabulary: Mapping or iterable, default=None<br><br>Either a Mapping (e.g., a dict) where keys are terms and values are<br>indices in the feature matrix, or an iterable over terms. If not<br>given, a vocabulary is determined from the input documents.</span>\n",
       "        </a>\n",
       "    </td>\n",
       "            <td class=\"value\">None</td>\n",
       "        </tr>\n",
       "    \n",
       "\n",
       "        <tr class=\"default\">\n",
       "            <td><button type=\"button\" class=\"copy-paste-icon\"\n",
       "                 aria-label=\"Copy binary to clipboard\"\n",
       "                 onclick=\"copyToClipboard('binary',\n",
       "                          this.parentElement.nextElementSibling)\"\n",
       "            ></button></td>\n",
       "            <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-binary;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html#:~:text=binary,-bool%2C%20default%3DFalse\">\n",
       "            binary\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-binary;\">\n",
       "            binary: bool, default=False<br><br>If True, all non-zero term counts are set to 1. This does not mean<br>outputs will have only 0/1 values, only that the tf term in tf-idf<br>is binary. (Set `binary` to True, `use_idf` to False and<br>`norm` to None to get 0/1 outputs).</span>\n",
       "        </a>\n",
       "    </td>\n",
       "            <td class=\"value\">False</td>\n",
       "        </tr>\n",
       "    \n",
       "\n",
       "        <tr class=\"default\">\n",
       "            <td><button type=\"button\" class=\"copy-paste-icon\"\n",
       "                 aria-label=\"Copy dtype to clipboard\"\n",
       "                 onclick=\"copyToClipboard('dtype',\n",
       "                          this.parentElement.nextElementSibling)\"\n",
       "            ></button></td>\n",
       "            <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-dtype;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html#:~:text=dtype,-dtype%2C%20default%3Dfloat64\">\n",
       "            dtype\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-dtype;\">\n",
       "            dtype: dtype, default=float64<br><br>Type of the matrix returned by fit_transform() or transform().</span>\n",
       "        </a>\n",
       "    </td>\n",
       "            <td class=\"value\">&lt;class &#x27;numpy.float64&#x27;&gt;</td>\n",
       "        </tr>\n",
       "    \n",
       "\n",
       "        <tr class=\"default\">\n",
       "            <td><button type=\"button\" class=\"copy-paste-icon\"\n",
       "                 aria-label=\"Copy norm to clipboard\"\n",
       "                 onclick=\"copyToClipboard('norm',\n",
       "                          this.parentElement.nextElementSibling)\"\n",
       "            ></button></td>\n",
       "            <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-norm;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html#:~:text=norm,-%7B%27l1%27%2C%20%27l2%27%7D%20or%20None%2C%20default%3D%27l2%27\">\n",
       "            norm\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-norm;\">\n",
       "            norm: {&#x27;l1&#x27;, &#x27;l2&#x27;} or None, default=&#x27;l2&#x27;<br><br>Each output row will have unit norm, either:<br><br>- &#x27;l2&#x27;: Sum of squares of vector elements is 1. The cosine<br>  similarity between two vectors is their dot product when l2 norm has<br>  been applied.<br>- &#x27;l1&#x27;: Sum of absolute values of vector elements is 1.<br>  See :func:`~sklearn.preprocessing.normalize`.<br>- None: No normalization.</span>\n",
       "        </a>\n",
       "    </td>\n",
       "            <td class=\"value\">&#x27;l2&#x27;</td>\n",
       "        </tr>\n",
       "    \n",
       "\n",
       "        <tr class=\"default\">\n",
       "            <td><button type=\"button\" class=\"copy-paste-icon\"\n",
       "                 aria-label=\"Copy use_idf to clipboard\"\n",
       "                 onclick=\"copyToClipboard('use_idf',\n",
       "                          this.parentElement.nextElementSibling)\"\n",
       "            ></button></td>\n",
       "            <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-use_idf;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html#:~:text=use_idf,-bool%2C%20default%3DTrue\">\n",
       "            use_idf\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-use_idf;\">\n",
       "            use_idf: bool, default=True<br><br>Enable inverse-document-frequency reweighting. If False, idf(t) = 1.</span>\n",
       "        </a>\n",
       "    </td>\n",
       "            <td class=\"value\">True</td>\n",
       "        </tr>\n",
       "    \n",
       "\n",
       "        <tr class=\"default\">\n",
       "            <td><button type=\"button\" class=\"copy-paste-icon\"\n",
       "                 aria-label=\"Copy smooth_idf to clipboard\"\n",
       "                 onclick=\"copyToClipboard('smooth_idf',\n",
       "                          this.parentElement.nextElementSibling)\"\n",
       "            ></button></td>\n",
       "            <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-smooth_idf;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html#:~:text=smooth_idf,-bool%2C%20default%3DTrue\">\n",
       "            smooth_idf\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-smooth_idf;\">\n",
       "            smooth_idf: bool, default=True<br><br>Smooth idf weights by adding one to document frequencies, as if an<br>extra document was seen containing every term in the collection<br>exactly once. Prevents zero divisions.</span>\n",
       "        </a>\n",
       "    </td>\n",
       "            <td class=\"value\">True</td>\n",
       "        </tr>\n",
       "    \n",
       "                  </tbody>\n",
       "                </table>\n",
       "            </details>\n",
       "        </div>\n",
       "    \n",
       "        <div class=\"estimator-table\">\n",
       "            <details>\n",
       "                <summary>Fitted attributes</summary>\n",
       "                <table class=\"parameters-table\">\n",
       "                    <tbody>\n",
       "                        <tr>\n",
       "                        <th>Name</th>\n",
       "                        <th>Type</th>\n",
       "                        <th>Value</th>\n",
       "                        </tr>\n",
       "                        \n",
       "       <tr class=\"default\">\n",
       "           <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-fixed_vocabulary_;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html#:~:text=fixed_vocabulary_,-bool\">\n",
       "            fixed_vocabulary_\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-fixed_vocabulary_;\">\n",
       "            fixed_vocabulary_: bool<br><br>True if a fixed vocabulary of term to indices mapping<br>is provided by the user.</span>\n",
       "        </a>\n",
       "    </td>\n",
       "           <td class=\"fitted-att-type\">bool</td>\n",
       "           <td>False</td>\n",
       "\n",
       "\n",
       "       </tr>\n",
       "    \n",
       "\n",
       "       <tr class=\"default\">\n",
       "           <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-idf_;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html#:~:text=idf_,-array%20of%20shape%20%28n_features%2C%29\">\n",
       "            idf_\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-idf_;\">\n",
       "            idf_: array of shape (n_features,)<br><br>The inverse document frequency (IDF) vector; only defined<br>if ``use_idf`` is True.</span>\n",
       "        </a>\n",
       "    </td>\n",
       "           <td class=\"fitted-att-type\">ndarray[float64](2093,)</td>\n",
       "           <td>[5.43,5.72,6.13,...,6.13,6.13,6.13]</td>\n",
       "\n",
       "\n",
       "       </tr>\n",
       "    \n",
       "\n",
       "       <tr class=\"default\">\n",
       "           <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-vocabulary_;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html#:~:text=vocabulary_,-dict\">\n",
       "            vocabulary_\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-vocabulary_;\">\n",
       "            vocabulary_: dict<br><br>A mapping of terms to feature indices.</span>\n",
       "        </a>\n",
       "    </td>\n",
       "           <td class=\"fitted-att-type\">dict</td>\n",
       "           <td>{&#x27;00&#x27;: 0, &#x27;10&#x27;: 1, &#x27;1258&#x27;: 2, &#x27;14...71&#x27;: 3, ...}</td>\n",
       "\n",
       "\n",
       "       </tr>\n",
       "    \n",
       "                    </tbody>\n",
       "                </table>\n",
       "            </details>\n",
       "        </div>\n",
       "    </div></div></div>\n",
       "        <div class=\"features fitted\">\n",
       "          <details>\n",
       "            <summary>\n",
       "              <div class=\"arrow\"></div>\n",
       "              <div>100 of 2,093 features</div>\n",
       "              <div class=\"image-container\">\n",
       "                <button type=\"button\" class=\"copy-paste-icon\"\n",
       "                  title=\"Copy output features (max 100)\"\n",
       "                  aria-label=\"Copy output features (max 100)\"\n",
       "                  onclick=\"\n",
       "                  event.stopPropagation();\n",
       "                  event.preventDefault();\n",
       "                  copyFeatureNamesToClipboard(this);\n",
       "                  \"\n",
       "                >\n",
       "                </button>\n",
       "              </div>\n",
       "            </summary>\n",
       "            <div class=\"features-container\">\n",
       "                <table class=\"features-table\">\n",
       "                  <tbody>\n",
       "                    \n",
       "        <tr>\n",
       "          <td>00</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>10</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>1258</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>1472454871</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>15</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>16</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>1750</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>1769</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>1782</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>1810</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>1821</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>1846</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>1850</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>1872</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>1880</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>1881</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>18th</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>1919</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>1924</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>1933</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>1970</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>1972</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>1986</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>1988</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>1990</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>1991</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>1992</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>1st</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>2002</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>2005</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>2006</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>2009</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>200pp</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>2011</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>2013</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>2014</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>2015</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>2017</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>20th</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>234</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>251</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>267</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>28332</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>29</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>299</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>30</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>300</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>302</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>31st</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>338</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>369</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>3d</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>3rd</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>42</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>45488</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>569</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>58</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>669</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>7th</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>90</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>99</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>abilities</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>abolitionism</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>about</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>abuse</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>accessibilite</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>accident</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>accommodation</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>aconseguir</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>acquired</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>acreage</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>across</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>acting</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>action</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>activation</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>activity</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>adaptacion</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>added</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>address</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>adhd</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>adjustment</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>administration</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>adopting</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>adoption</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>adrenoceptor</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>adults</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>advanced</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>advantages</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>advertising</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>advices</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>aesthetics</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>affect</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>affecting</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>affordability</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>affordable</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>africa</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>african</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>after</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>again</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "        <tr>\n",
       "          <td>against</td>\n",
       "        </tr>\n",
       "\n",
       "    \n",
       "                  </tbody>\n",
       "                </table>\n",
       "            </div>\n",
       "          </details>\n",
       "        </div>\n",
       "    <div class=\"sk-item\"><div class=\"sk-estimator fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually sk-global\" id=\"sk-estimator-id-3\" type=\"checkbox\" ><label for=\"sk-estimator-id-3\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow\"><div><div>MultinomialNB</div></div><div><a class=\"sk-estimator-doc-link fitted\" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.naive_bayes.MultinomialNB.html\">?<span>Documentation for MultinomialNB</span></a></div></label><div class=\"sk-toggleable__content fitted\" data-param-prefix=\"classifier__\">\n",
       "        <div class=\"estimator-table\">\n",
       "            <details>\n",
       "                <summary>Parameters</summary>\n",
       "                <table class=\"parameters-table\">\n",
       "                  <tbody>\n",
       "                    \n",
       "        <tr class=\"user-set\">\n",
       "            <td><button type=\"button\" class=\"copy-paste-icon\"\n",
       "                 aria-label=\"Copy alpha to clipboard\"\n",
       "                 onclick=\"copyToClipboard('alpha',\n",
       "                          this.parentElement.nextElementSibling)\"\n",
       "            ></button></td>\n",
       "            <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-alpha;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.naive_bayes.MultinomialNB.html#:~:text=alpha,-float%20or%20array-like%20of%20shape%20%28n_features%2C%29%2C%20default%3D1.0\">\n",
       "            alpha\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-alpha;\">\n",
       "            alpha: float or array-like of shape (n_features,), default=1.0<br><br>Additive (Laplace/Lidstone) smoothing parameter<br>(set alpha=0 and force_alpha=True, for no smoothing).</span>\n",
       "        </a>\n",
       "    </td>\n",
       "            <td class=\"value\">0.5</td>\n",
       "        </tr>\n",
       "    \n",
       "\n",
       "        <tr class=\"user-set\">\n",
       "            <td><button type=\"button\" class=\"copy-paste-icon\"\n",
       "                 aria-label=\"Copy fit_prior to clipboard\"\n",
       "                 onclick=\"copyToClipboard('fit_prior',\n",
       "                          this.parentElement.nextElementSibling)\"\n",
       "            ></button></td>\n",
       "            <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-fit_prior;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.naive_bayes.MultinomialNB.html#:~:text=fit_prior,-bool%2C%20default%3DTrue\">\n",
       "            fit_prior\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-fit_prior;\">\n",
       "            fit_prior: bool, default=True<br><br>Whether to learn class prior probabilities or not.<br>If false, a uniform prior will be used.</span>\n",
       "        </a>\n",
       "    </td>\n",
       "            <td class=\"value\">False</td>\n",
       "        </tr>\n",
       "    \n",
       "\n",
       "        <tr class=\"default\">\n",
       "            <td><button type=\"button\" class=\"copy-paste-icon\"\n",
       "                 aria-label=\"Copy force_alpha to clipboard\"\n",
       "                 onclick=\"copyToClipboard('force_alpha',\n",
       "                          this.parentElement.nextElementSibling)\"\n",
       "            ></button></td>\n",
       "            <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-force_alpha;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.naive_bayes.MultinomialNB.html#:~:text=force_alpha,-bool%2C%20default%3DTrue\">\n",
       "            force_alpha\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-force_alpha;\">\n",
       "            force_alpha: bool, default=True<br><br>If False and alpha is less than 1e-10, it will set alpha to<br>1e-10. If True, alpha will remain unchanged. This may cause<br>numerical errors if alpha is too close to 0.<br><br>.. versionadded:: 1.2<br>.. versionchanged:: 1.4<br>   The default value of `force_alpha` changed to `True`.</span>\n",
       "        </a>\n",
       "    </td>\n",
       "            <td class=\"value\">True</td>\n",
       "        </tr>\n",
       "    \n",
       "\n",
       "        <tr class=\"default\">\n",
       "            <td><button type=\"button\" class=\"copy-paste-icon\"\n",
       "                 aria-label=\"Copy class_prior to clipboard\"\n",
       "                 onclick=\"copyToClipboard('class_prior',\n",
       "                          this.parentElement.nextElementSibling)\"\n",
       "            ></button></td>\n",
       "            <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-class_prior;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.naive_bayes.MultinomialNB.html#:~:text=class_prior,-array-like%20of%20shape%20%28n_classes%2C%29%2C%20default%3DNone\">\n",
       "            class_prior\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-class_prior;\">\n",
       "            class_prior: array-like of shape (n_classes,), default=None<br><br>Prior probabilities of the classes. If specified, the priors are not<br>adjusted according to the data.</span>\n",
       "        </a>\n",
       "    </td>\n",
       "            <td class=\"value\">None</td>\n",
       "        </tr>\n",
       "    \n",
       "                  </tbody>\n",
       "                </table>\n",
       "            </details>\n",
       "        </div>\n",
       "    \n",
       "        <div class=\"estimator-table\">\n",
       "            <details>\n",
       "                <summary>Fitted attributes</summary>\n",
       "                <table class=\"parameters-table\">\n",
       "                    <tbody>\n",
       "                        <tr>\n",
       "                        <th>Name</th>\n",
       "                        <th>Type</th>\n",
       "                        <th>Value</th>\n",
       "                        </tr>\n",
       "                        \n",
       "       <tr class=\"default\">\n",
       "           <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-class_count_;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.naive_bayes.MultinomialNB.html#:~:text=class_count_,-ndarray%20of%20shape%20%28n_classes%2C%29\">\n",
       "            class_count_\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-class_count_;\">\n",
       "            class_count_: ndarray of shape (n_classes,)<br><br>Number of samples encountered for each class during fitting. This<br>value is weighted by the sample weight when provided.</span>\n",
       "        </a>\n",
       "    </td>\n",
       "           <td class=\"fitted-att-type\">ndarray[float64](7,)</td>\n",
       "           <td>[51.,49.,46.,...,49.,44.,51.]</td>\n",
       "\n",
       "\n",
       "       </tr>\n",
       "    \n",
       "\n",
       "       <tr class=\"default\">\n",
       "           <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-class_log_prior_;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.naive_bayes.MultinomialNB.html#:~:text=class_log_prior_,-ndarray%20of%20shape%20%28n_classes%2C%29\">\n",
       "            class_log_prior_\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-class_log_prior_;\">\n",
       "            class_log_prior_: ndarray of shape (n_classes,)<br><br>Smoothed empirical log probability for each class.</span>\n",
       "        </a>\n",
       "    </td>\n",
       "           <td class=\"fitted-att-type\">ndarray[float64](7,)</td>\n",
       "           <td>[-1.95,-1.95,-1.95,...,-1.95,-1.95,-1.95]</td>\n",
       "\n",
       "\n",
       "       </tr>\n",
       "    \n",
       "\n",
       "       <tr class=\"default\">\n",
       "           <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-classes_;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.naive_bayes.MultinomialNB.html#:~:text=classes_,-ndarray%20of%20shape%20%28n_classes%2C%29\">\n",
       "            classes_\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-classes_;\">\n",
       "            classes_: ndarray of shape (n_classes,)<br><br>Class labels known to the classifier</span>\n",
       "        </a>\n",
       "    </td>\n",
       "           <td class=\"fitted-att-type\">ndarray[&lt;U10](7,)</td>\n",
       "           <td>[&#x27;business&#x27;,&#x27;economics&#x27;,&#x27;geography&#x27;,...,&#x27;politics&#x27;,&#x27;psychology&#x27;,\n",
       " &#x27;sociology&#x27;]</td>\n",
       "\n",
       "\n",
       "       </tr>\n",
       "    \n",
       "\n",
       "       <tr class=\"default\">\n",
       "           <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-feature_count_;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.naive_bayes.MultinomialNB.html#:~:text=feature_count_,-ndarray%20of%20shape%20%28n_classes%2C%20n_features%29\">\n",
       "            feature_count_\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-feature_count_;\">\n",
       "            feature_count_: ndarray of shape (n_classes, n_features)<br><br>Number of samples encountered for each (class, feature)<br>during fitting. This value is weighted by the sample weight when<br>provided.</span>\n",
       "        </a>\n",
       "    </td>\n",
       "           <td class=\"fitted-att-type\">ndarray[float64](7, 2093)</td>\n",
       "           <td>[[0.21,0.  ,0.  ,...,0.  ,0.  ,0.  ],\n",
       " [0.  ,0.31,0.  ,...,0.39,0.  ,0.29],\n",
       " [0.  ,0.  ,0.  ,...,0.  ,0.  ,0.  ],\n",
       " ...,\n",
       " [0.  ,0.18,0.  ,...,0.  ,0.  ,0.  ],\n",
       " [0.  ,0.  ,0.  ,...,0.  ,0.  ,0.  ],\n",
       " [0.37,0.  ,0.41,...,0.  ,0.24,0.  ]]</td>\n",
       "\n",
       "\n",
       "       </tr>\n",
       "    \n",
       "\n",
       "       <tr class=\"default\">\n",
       "           <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-feature_log_prob_;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.naive_bayes.MultinomialNB.html#:~:text=feature_log_prob_,-ndarray%20of%20shape%20%28n_classes%2C%20n_features%29\">\n",
       "            feature_log_prob_\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-feature_log_prob_;\">\n",
       "            feature_log_prob_: ndarray of shape (n_classes, n_features)<br><br>Empirical log probability of features<br>given a class, ``P(x_i|y)``.</span>\n",
       "        </a>\n",
       "    </td>\n",
       "           <td class=\"fitted-att-type\">ndarray[float64](7, 2093)</td>\n",
       "           <td>[[-7.43,-7.78,-7.78,...,-7.78,-7.78,-7.78],\n",
       " [-7.77,-7.29,-7.77,...,-7.19,-7.77,-7.32],\n",
       " [-7.78,-7.78,-7.78,...,-7.78,-7.78,-7.78],\n",
       " ...,\n",
       " [-7.78,-7.48,-7.78,...,-7.78,-7.78,-7.78],\n",
       " [-7.77,-7.77,-7.77,...,-7.77,-7.77,-7.77],\n",
       " [-7.24,-7.79,-7.19,...,-7.79,-7.4 ,-7.79]]</td>\n",
       "\n",
       "\n",
       "       </tr>\n",
       "    \n",
       "\n",
       "       <tr class=\"default\">\n",
       "           <td class=\"param\">\n",
       "        <a class=\"param-doc-link\"\n",
       "            style=\"anchor-name: --doc-link-n_features_in_;\"\n",
       "            rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.9/modules/generated/sklearn.naive_bayes.MultinomialNB.html#:~:text=n_features_in_,-int\">\n",
       "            n_features_in_\n",
       "            <span class=\"param-doc-description\"\n",
       "            style=\"position-anchor: --doc-link-n_features_in_;\">\n",
       "            n_features_in_: int<br><br>Number of features seen during :term:`fit`.<br><br>.. versionadded:: 0.24</span>\n",
       "        </a>\n",
       "    </td>\n",
       "           <td class=\"fitted-att-type\">int</td>\n",
       "           <td>2093</td>\n",
       "\n",
       "\n",
       "       </tr>\n",
       "    \n",
       "                    </tbody>\n",
       "                </table>\n",
       "            </details>\n",
       "        </div>\n",
       "    </div></div></div></div></div></div></div><script>/*  Authors: The scikit-learn developers\n",
       " SPDX-License-Identifier: BSD-3-Clause\n",
       "*/\n",
       "\n",
       "function copyToClipboard(text, element) {\n",
       "    // Get the parameter prefix from the closest toggleable content\n",
       "    const toggleableContent = element.closest('.sk-toggleable__content');\n",
       "    const paramPrefix = toggleableContent ? toggleableContent.dataset.paramPrefix : '';\n",
       "    const fullParamName = paramPrefix ? `${paramPrefix}${text}` : text;\n",
       "\n",
       "    const originalStyle = element.style;\n",
       "    const computedStyle = window.getComputedStyle(element);\n",
       "    const originalWidth = computedStyle.width;\n",
       "    const originalHTML = element.innerHTML.replace('Copied!', '');\n",
       "\n",
       "    navigator.clipboard.writeText(fullParamName)\n",
       "        .then(() => {\n",
       "            element.style.width = originalWidth;\n",
       "            element.style.color = 'green';\n",
       "            element.innerHTML = \"Copied!\";\n",
       "\n",
       "            setTimeout(() => {\n",
       "                element.innerHTML = originalHTML;\n",
       "                element.style = originalStyle;\n",
       "            }, 2000);\n",
       "        })\n",
       "        .catch(err => {\n",
       "            console.error('Failed to copy:', err);\n",
       "            element.style.color = 'red';\n",
       "            element.innerHTML = \"Failed!\";\n",
       "            setTimeout(() => {\n",
       "                element.innerHTML = originalHTML;\n",
       "                element.style = originalStyle;\n",
       "            }, 2000);\n",
       "        });\n",
       "    return false;\n",
       "}\n",
       "\n",
       "document.querySelectorAll('.copy-paste-icon').forEach(function(element) {\n",
       "    const toggleableContent = element.closest('.sk-toggleable__content');\n",
       "    const paramPrefix = toggleableContent ? toggleableContent.dataset.paramPrefix : '';\n",
       "\n",
       "    const parent = element.parentElement;\n",
       "    if (!parent || !parent.nextElementSibling) {\n",
       "        console.warn('Expected copy-paste icon is missing from the DOM structure');\n",
       "        return;\n",
       "    }\n",
       "\n",
       "    const paramName = element.parentElement.nextElementSibling\n",
       "        .textContent.trim().split(' ')[0];\n",
       "    const fullParamName = paramPrefix ? `${paramPrefix}${paramName}` : paramName;\n",
       "\n",
       "    element.setAttribute('title', fullParamName);\n",
       "});\n",
       "\n",
       "/**\n",
       " * Copy the list of feature names formatted as a Python list.\n",
       " *\n",
       " * @param {HTMLElement} element - The copy button inside a `.features` block; its siblings\n",
       " *   contain a `details` element and a table containing feature named.\n",
       " * @returns {boolean} Always returns `false` so callers can prevent the default click behavior.\n",
       " */\n",
       "function copyFeatureNamesToClipboard(element) {\n",
       "    var detailsElem = element.closest('.features').querySelector('details');\n",
       "    var wasOpen = detailsElem.open;\n",
       "    detailsElem.open = true;\n",
       "    var content = element.closest('.features').querySelector('tbody')\n",
       "                  .innerText.trim();\n",
       "    if (!wasOpen) detailsElem.open = false;\n",
       "    const rows = content.split('\\n').map(row => `    \"${row}\"`);\n",
       "    const formattedText = `[\\n${rows.join(',\\n')},\\n]`;\n",
       "    const originalHTML = element.innerHTML.replace('✔', '');\n",
       "    const originalStyle = element.style;\n",
       "    const copyMark = document.createElement('span');\n",
       "    copyMark.innerHTML = '✔';\n",
       "    copyMark.style.color = 'blue';\n",
       "    copyMark.style.fontSize = '1em';\n",
       "\n",
       "    navigator.clipboard.writeText(formattedText)\n",
       "        .then(() => {\n",
       "            element.style.display = 'none';\n",
       "            element.parentElement.appendChild(copyMark);\n",
       "\n",
       "            setTimeout(() => {\n",
       "                copyMark.remove();\n",
       "                element.innerHTML = originalHTML;\n",
       "                element.style = originalStyle;\n",
       "            }, 1000);\n",
       "        })\n",
       "        .catch(err => {\n",
       "            console.error('Failed to copy:', err);\n",
       "            element.style.color = 'orange';\n",
       "            element.innerHTML = \"Failed!\";\n",
       "            setTimeout(() => {\n",
       "                element.innerHTML = originalHTML;\n",
       "                element.style = originalStyle;\n",
       "            }, 1000);\n",
       "        });\n",
       "    return false;\n",
       "}\n",
       "/**\n",
       " * Adapted from Skrub\n",
       " * https://github.com/skrub-data/skrub/blob/403466d1d5d4dc76a7ef569b3f8228db59a31dc3/skrub/_reporting/_data/templates/report.js#L789\n",
       " * @returns \"light\" or \"dark\"\n",
       " */\n",
       "function detectTheme(element) {\n",
       "    const body = document.querySelector('body');\n",
       "\n",
       "    // Check VSCode theme\n",
       "    const themeKindAttr = body.getAttribute('data-vscode-theme-kind');\n",
       "    const themeNameAttr = body.getAttribute('data-vscode-theme-name');\n",
       "\n",
       "    if (themeKindAttr && themeNameAttr) {\n",
       "        const themeKind = themeKindAttr.toLowerCase();\n",
       "        const themeName = themeNameAttr.toLowerCase();\n",
       "\n",
       "        if (themeKind.includes(\"dark\") || themeName.includes(\"dark\")) {\n",
       "            return \"dark\";\n",
       "        }\n",
       "        if (themeKind.includes(\"light\") || themeName.includes(\"light\")) {\n",
       "            return \"light\";\n",
       "        }\n",
       "    }\n",
       "\n",
       "    // Check Jupyter theme\n",
       "    if (body.getAttribute('data-jp-theme-light') === 'false') {\n",
       "        return 'dark';\n",
       "    } else if (body.getAttribute('data-jp-theme-light') === 'true') {\n",
       "        return 'light';\n",
       "    }\n",
       "\n",
       "    // Guess based on a parent element's color\n",
       "    const color = window.getComputedStyle(element.parentNode, null).getPropertyValue('color');\n",
       "    const match = color.match(/^rgb\\s*\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*\\)\\s*$/i);\n",
       "    if (match) {\n",
       "        const [r, g, b] = [\n",
       "            parseFloat(match[1]),\n",
       "            parseFloat(match[2]),\n",
       "            parseFloat(match[3])\n",
       "        ];\n",
       "\n",
       "        // https://en.wikipedia.org/wiki/HSL_and_HSV#Lightness\n",
       "        const luma = 0.299 * r + 0.587 * g + 0.114 * b;\n",
       "\n",
       "        if (luma > 180) {\n",
       "            // If the text is very bright we have a dark theme\n",
       "            return 'dark';\n",
       "        }\n",
       "        if (luma < 75) {\n",
       "            // If the text is very dark we have a light theme\n",
       "            return 'light';\n",
       "        }\n",
       "        // Otherwise fall back to the next heuristic.\n",
       "    }\n",
       "\n",
       "    // Fallback to system preference\n",
       "    return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n",
       "}\n",
       "\n",
       "\n",
       "function forceTheme(elementId) {\n",
       "    const estimatorElement = document.querySelector(`#${elementId}`);\n",
       "    if (estimatorElement === null) {\n",
       "        console.error(`Element with id ${elementId} not found.`);\n",
       "    } else {\n",
       "        const theme = detectTheme(estimatorElement);\n",
       "        estimatorElement.classList.add(theme);\n",
       "    }\n",
       "}\n",
       "\n",
       "forceTheme('sk-container-id-1');</script></body>"
      ],
      "text/plain": [
       "Pipeline(steps=[('vectorizer', TfidfVectorizer(max_df=0.9, sublinear_tf=True)),\n",
       "                ('classifier', MultinomialNB(alpha=0.5, fit_prior=False))])"
      ]
     },
     "execution_count": 6,
     "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",
   "id": "cell-9",
   "metadata": {},
   "source": [
    "## Export the model using GreatAI"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "cell-10",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-28T22:47:35.718404Z",
     "iopub.status.busy": "2026-10-28T22:47:35.718242Z",
     "iopub.status.idle": "2026-10-28T22:47:35.738575Z",
     "shell.execute_reply": "2026-10-28T22:47:35.738292Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;39mFetching cached versions of small-domain-prediction\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;39mFetching cached versions of small-domain-prediction\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;39mFetching cached versions of small-domain-prediction\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;39mModel small-domain-prediction uploaded with version 0\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'small-domain-prediction:0'"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from great_ai import save_model\n",
    "\n",
    "save_model(classifier, key=\"small-domain-prediction\", keep_last_n=5)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-11",
   "metadata": {},
   "source": [
    "## Next: [Part 3](https://great-ai.schmelczer.dev/examples/simple/deploy)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv (3.13.5)",
   "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.13.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
