{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Manual CPE matching evaluation\n",
    "\n",
    "This notebook assists the manual matching evaluation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sec_certs.dataset import CCDataset\n",
    "import pandas as pd\n",
    "import json\n",
    "import tempfile\n",
    "from sec_certs.utils.label_studio_utils import to_label_studio_json"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Prepare the input data for label studio"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Downloading CC Dataset: 100%|██████████| 139M/139M [00:15<00:00, 9.61MB/s] \n"
     ]
    }
   ],
   "source": [
    "dset = CCDataset.from_web()\n",
    "df = dset.to_pandas()\n",
    "\n",
    "eval_digests = pd.read_csv(\"./../../data/cpe_eval/random.csv\", sep=\";\").set_index(\"dgst\").index\n",
    "eval_certs = df.loc[(df.index.isin(eval_digests)) & (df.cpe_matches.notnull())].copy()\n",
    "\n",
    "# It may be handy to display max number of assigned cpe matches here\n",
    "eval_certs[\"n_cpes\"] = eval_certs.cpe_matches.map(len)\n",
    "max_n_cpes = eval_certs.n_cpes.max()\n",
    "print(f\"Max CPE matches: {max_n_cpes}\")\n",
    "\n",
    "# Now you may want to adjust the key `cpe_n_max_matches` config in sec_certs/config/settings.yml according to max_n_cpes\n",
    "# This helps to avoid clutter in label studio interface\n",
    "with tempfile.TemporaryDirectory() as tmp_dir:\n",
    "    dset.root_dir = tmp_dir\n",
    "    dset.certs = {x.dgst: x for x in dset if x.dgst in eval_certs.index.tolist()}\n",
    "    to_label_studio_json(dset, \"./label_studio_input_data.json\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`Now you import this data to label studio and label it`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Load the data from label studio and show the results"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Evaluated 607 CPE matches in 100 certificates\n",
      "In total, 546 (89.95%) are correct (precision of the positive class).\n",
      "Also, 81 (81.00%) certificates have perfect matches.\n",
      "\\newcommand{\\evalCcPrecision}{$89.95\\%$}\n",
      "\\newcommand{\\evalCcRatioErrorFree}{$81\\%$}\n"
     ]
    }
   ],
   "source": [
    "with open(\"./../../data/cpe_eval/manual_cpe_labels.json\", \"r\") as handle:\n",
    "    data = json.load(handle)\n",
    "\n",
    "results = []\n",
    "for sample in data:\n",
    "    option_keys = [key for key in sample.keys() if \"option_\" in key]\n",
    "    n_cpe_matches = len([sample[key] for key in option_keys if sample[key] != \"No good match\"])\n",
    "\n",
    "    if not \"verified_cpe_match\" in sample.keys():\n",
    "        n_wrong = 0\n",
    "    elif isinstance(sample[\"verified_cpe_match\"], str):\n",
    "        n_wrong = 1\n",
    "    else:\n",
    "        n_wrong = len(sample[\"verified_cpe_match\"][\"choices\"])\n",
    "\n",
    "    results.append((n_cpe_matches, n_wrong))\n",
    "\n",
    "correct = [x[0] - x[1] for x in results]\n",
    "wrong = [x[1] for x in results]\n",
    "n_candidates = [x[0] for x in results]\n",
    "completely_right = [x == 0 for x in wrong]\n",
    "\n",
    "precision = 100 * sum(correct) / sum(n_candidates)\n",
    "completely_right_ratio = 100 * sum(completely_right) / len(n_candidates)\n",
    "\n",
    "print(f\"Evaluated {sum(n_candidates)} CPE matches in {len(results)} certificates\")\n",
    "print(f\"In total, {sum(correct)} ({precision:.2f}%) are correct (precision of the positive class).\")\n",
    "print(f\"Also, {sum(completely_right)} ({completely_right_ratio:.2f}%) certificates have perfect matches.\")\n",
    "\n",
    "print(f\"\\\\newcommand{{\\\\evalCcPrecision}}{{${precision:.2f}\\%$}}\")\n",
    "print(f\"\\\\newcommand{{\\\\evalCcRatioErrorFree}}{{${completely_right_ratio:.0f}\\%$}}\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3.8.13 ('venv': venv)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.13"
  },
  "orig_nbformat": 4,
  "vscode": {
   "interpreter": {
    "hash": "a5b8c5b127d2cfe5bc3a1c933e197485eb9eba25154c3661362401503b4ef9d4"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
