{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "baea9925",
   "metadata": {},
   "source": [
    "# Ch 03 — Classification (notebook)\n",
    "\n",
    "`[← 02 end-to-end-ml-project]` · **this notebook** · `[04 training-models →]`\n",
    "\n",
    "Runs top-to-bottom in ~2 min on free Colab CPU. Last verified 2026-06-11.\n",
    "\n",
    "**What you'll build**\n",
    "- A digit classifier from a one-line baseline, then a real model you can defend.\n",
    "- The confusion matrix, precision/recall, and the ROC and PR curves — computed by hand from the same predictions, then checked against scikit-learn.\n",
    "- A threshold you *choose* on purpose, and the evidence that 91% accuracy can be the worst model in the room.\n",
    "\n",
    "**How this notebook works.** Code cells with a `# TODO` are yours to fill in. Run the cell to grade yourself: `[ ok ]` passed, `[FAIL]` shows what went wrong, `[ -- ]` means not attempted yet. Every exercise has a hint ladder (open only as many as you need) and a folded solution below it. The notebook runs top-to-bottom even if you fill in nothing — the solutions make the later cells work. See Ch 00 for the full protocol.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ddb6a001",
   "metadata": {},
   "source": [
    "## Before you start\n",
    "\n",
    "1. A spam filter flags 1 in 1000 emails as spam. A model that labels *everything* \"not spam\" — how accurate is it? <details><summary>Answer</summary>99.9%. Accuracy is a trap on imbalanced data; this whole notebook is about what to measure instead.</details>\n",
    "2. You raise a classifier's decision threshold from 0.5 to 0.9. Does recall go up or down? <details><summary>Answer</summary>Down. Higher bar to call something positive → fewer positives caught → recall falls (precision usually rises). This is the precision/recall tradeoff.</details>\n",
    "3. Predict before you run: for MNIST \"is it a 5?\", what fraction of the 70,000 images are 5s? <details><summary>Answer</summary>About 9% (5s are ~1/10 of digits). That base rate is why a \"never a 5\" model already scores ~91%.</details>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e3fb3091",
   "metadata": {},
   "source": [
    "## Setup\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "37f517e7",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-06-10T18:34:04.621604Z",
     "iopub.status.busy": "2026-06-10T18:34:04.621516Z",
     "iopub.status.idle": "2026-06-10T18:34:05.207055Z",
     "shell.execute_reply": "2026-06-10T18:34:05.206645Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "numpy 2.2.6 · sklearn 1.7.2\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import sklearn\n",
    "print(f\"numpy {np.__version__} · sklearn {sklearn.__version__}\")\n",
    "if np.__version__ < \"2.0\":\n",
    "    print(\"WARN: written for NumPy 2.x; older versions may differ slightly\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "6d818ba1",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-06-10T18:34:05.208309Z",
     "iopub.status.busy": "2026-06-10T18:34:05.208180Z",
     "iopub.status.idle": "2026-06-10T18:34:05.212078Z",
     "shell.execute_reply": "2026-06-10T18:34:05.211761Z"
    }
   },
   "outputs": [],
   "source": [
    "import os\n",
    "SEED = 0\n",
    "FAST = bool(os.environ.get('NB_FAST'))  # CI smoke mode\n",
    "rng = np.random.default_rng(SEED)\n",
    "\n",
    "# ── house self-check harness (identical across all chapter notebooks) ──\n",
    "import numpy as _np\n",
    "\n",
    "def check(label, test_fn, required=False):\n",
    "    \"\"\"Run one self-check. test_fn raises AssertionError (with a teaching\n",
    "    message) on failure, NotImplementedError if the stub is unfilled.\n",
    "    required=True is used only in solution cells; it is what CI grades.\"\"\"\n",
    "    try:\n",
    "        test_fn()\n",
    "    except NotImplementedError:\n",
    "        if required:\n",
    "            raise AssertionError(f\"{label}: reference solution incomplete\")\n",
    "        print(f\"[ -- ] {label}: not attempted yet — fill in the TODO above, then re-run.\")\n",
    "        return False\n",
    "    except AssertionError as e:\n",
    "        if required:\n",
    "            raise\n",
    "        print(f\"[FAIL] {label}: {e}\")\n",
    "        return False\n",
    "    print(f\"[ ok ] {label}\")\n",
    "    return True\n",
    "\n",
    "def attempted(*vals):\n",
    "    \"\"\"Treat None placeholders as 'not attempted'.\"\"\"\n",
    "    if any(v is None for v in vals):\n",
    "        raise NotImplementedError\n",
    "\n",
    "def check_shape(x, want):\n",
    "    assert tuple(x.shape) == tuple(want), \\\n",
    "        f\"shape {tuple(x.shape)}, expected {tuple(want)} — check your reshape/transpose order\"\n",
    "\n",
    "def check_close(got, want, atol=1e-5, rtol=1e-4, msg=\"\"):\n",
    "    g, w = _np.asarray(got, dtype=float), _np.asarray(want, dtype=float)\n",
    "    assert g.shape == w.shape, f\"shape {g.shape} vs expected {w.shape}. {msg}\"\n",
    "    bad = ~_np.isclose(g, w, atol=atol, rtol=rtol)\n",
    "    assert not bad.any(), \\\n",
    "        f\"{bad.mean():.2%} of values wrong (max diff {abs(g - w).max():.3g}). {msg}\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e7201523",
   "metadata": {},
   "source": [
    "> **Note:** seeds make this notebook's printed numbers reproduce on CPU. Library versions and BLAS threading can shift the last digit or two; quoted numbers hold for the pinned environment. If your accuracy is 0.968 and the page says 0.969, you did nothing wrong.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b16277df",
   "metadata": {},
   "source": [
    "## The map\n",
    "\n",
    "> **Part 1 — The baseline that lies.** Build the \"never a 5\" classifier and watch it score 91%.\n",
    "> **Part 2 — Confusion, by hand.** Count TP/FP/FN/TN, derive precision and recall, check against sklearn.\n",
    "> **Part 3 — The threshold is a choice.** Sweep it; draw the PR and ROC curves; pick a point on purpose.\n",
    "> **Part 4 — A deliberate failure.** Optimize for accuracy on imbalanced data and see it pick the wrong model.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "56b07421",
   "metadata": {},
   "source": [
    "## Part 1 — The baseline that lies\n",
    "\n",
    "We use a small synthetic stand-in for \"is this digit a 5?\": a 9%-positive, imbalanced binary problem with a real signal a model can find. (The full MNIST version is the capstone; the lesson is identical and runs instantly here.)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "7c79ec2a",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-06-10T18:34:05.212872Z",
     "iopub.status.busy": "2026-06-10T18:34:05.212802Z",
     "iopub.status.idle": "2026-06-10T18:34:05.244120Z",
     "shell.execute_reply": "2026-06-10T18:34:05.243514Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "train (1400, 20), positives 9.4%\n"
     ]
    }
   ],
   "source": [
    "from sklearn.datasets import make_classification\n",
    "X, y = make_classification(\n",
    "    n_samples=2000, n_features=20, n_informative=6, n_redundant=2,\n",
    "    weights=[0.91, 0.09], flip_y=0.01, class_sep=0.9, random_state=SEED)\n",
    "from sklearn.model_selection import train_test_split\n",
    "Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.3, stratify=y, random_state=SEED)\n",
    "print(f\"train {Xtr.shape}, positives {ytr.mean():.1%}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd4c76d6",
   "metadata": {},
   "source": [
    "The \"never positive\" baseline: predict 0 for everything. Its accuracy is just the negative rate.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "34d662c8",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-06-10T18:34:05.244991Z",
     "iopub.status.busy": "2026-06-10T18:34:05.244916Z",
     "iopub.status.idle": "2026-06-10T18:34:05.247130Z",
     "shell.execute_reply": "2026-06-10T18:34:05.246773Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "'never a 5' accuracy: 90.5%\n"
     ]
    }
   ],
   "source": [
    "never_pos = np.zeros_like(yte)\n",
    "acc = (never_pos == yte).mean()\n",
    "print(f\"'never a 5' accuracy: {acc:.1%}\")\n",
    "assert acc > 0.88, \"baseline should score ~91% purely from the base rate\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4296f295",
   "metadata": {},
   "source": [
    "> **Interpretation.** ~91% accuracy, and the model has learned nothing — it can't find a single positive. Accuracy rewarded it for ignoring the minority class. That single number is why we need the rest of this notebook.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8dfec3b8",
   "metadata": {},
   "source": [
    "## Part 2 — Confusion, by hand\n",
    "\n",
    "Train a logistic-regression classifier (a real model with calibrated-ish scores), get its predictions, and build the confusion matrix yourself before trusting any library.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "880e4d31",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-06-10T18:34:05.247989Z",
     "iopub.status.busy": "2026-06-10T18:34:05.247913Z",
     "iopub.status.idle": "2026-06-10T18:34:05.263490Z",
     "shell.execute_reply": "2026-06-10T18:34:05.263169Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "accuracy at threshold 0.5: 95.3%\n"
     ]
    }
   ],
   "source": [
    "from sklearn.linear_model import LogisticRegression\n",
    "clf = LogisticRegression(max_iter=1000, random_state=SEED).fit(Xtr, ytr)\n",
    "scores = clf.predict_proba(Xte)[:, 1]   # P(positive)\n",
    "pred = (scores >= 0.5).astype(int)\n",
    "print(f\"accuracy at threshold 0.5: {(pred == yte).mean():.1%}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "277cc4d9",
   "metadata": {},
   "source": [
    "### Exercise 3.1 — Confusion matrix from counts\n",
    "`Difficulty 2/5 · ~10 min`\n",
    "\n",
    "Fill in `confusion(y_true, y_pred)` returning `(tp, fp, fn, tn)` as plain Python ints. No sklearn. Then precision and recall fall out of those four numbers.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "7c62e161",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-06-10T18:34:05.264492Z",
     "iopub.status.busy": "2026-06-10T18:34:05.264414Z",
     "iopub.status.idle": "2026-06-10T18:34:05.270395Z",
     "shell.execute_reply": "2026-06-10T18:34:05.270104Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ -- ] 3.1 confusion (toy): not attempted yet — fill in the TODO above, then re-run.\n",
      "[ -- ] 3.1 vs sklearn: not attempted yet — fill in the TODO above, then re-run.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def confusion(y_true, y_pred):\n",
    "    \"\"\"Return (tp, fp, fn, tn) for binary labels in {0,1}.\"\"\"\n",
    "    y_true, y_pred = np.asarray(y_true), np.asarray(y_pred)\n",
    "    # TODO 1: true positives  = predicted 1 and actually 1\n",
    "    tp = None\n",
    "    # TODO 2: false positives = predicted 1 but actually 0\n",
    "    fp = None\n",
    "    # TODO 3: false negatives = predicted 0 but actually 1\n",
    "    fn = None\n",
    "    # TODO 4: true negatives  = predicted 0 and actually 0\n",
    "    tn = None\n",
    "    attempted(tp, fp, fn, tn)\n",
    "    return int(tp), int(fp), int(fn), int(tn)\n",
    "\n",
    "def precision_recall(y_true, y_pred):\n",
    "    tp, fp, fn, tn = confusion(y_true, y_pred)\n",
    "    # TODO 5: precision = tp / (tp + fp);  recall = tp / (tp + fn)\n",
    "    prec = None\n",
    "    rec = None\n",
    "    attempted(prec, rec)\n",
    "    return prec, rec\n",
    "\n",
    "# self-checks (run this cell) — define helpers first, then call the checks\n",
    "def _toy():\n",
    "    yt = np.array([1,1,1,0,0]); yp = np.array([1,0,1,1,0])\n",
    "    assert confusion(yt, yp) == (2,1,1,1), \\\n",
    "        f\"toy confusion {confusion(yt,yp)}, expected (2,1,1,1): 2 hits, 1 false alarm, 1 miss, 1 correct-reject\"\n",
    "\n",
    "def _vs_sklearn(fn, yp, yt):\n",
    "    from sklearn.metrics import confusion_matrix\n",
    "    tn, fp, fn_, tp = confusion_matrix(yt, yp).ravel()\n",
    "    got = fn(yt, yp)\n",
    "    assert got == (int(tp), int(fp), int(fn_), int(tn)), \\\n",
    "        f\"counts {got} disagree with sklearn (tp,fp,fn,tn)=({tp},{fp},{fn_},{tn})\"\n",
    "\n",
    "check(\"3.1 confusion (toy)\", _toy)\n",
    "check(\"3.1 vs sklearn\", lambda: _vs_sklearn(confusion, pred, yte))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "66f204e6",
   "metadata": {},
   "source": [
    "<details><summary>Hint 1 (conceptual)</summary>Each of the four counts is a boolean mask AND'd with another, then summed. `(y_pred == 1) & (y_true == 1)` is the TP mask.</details>\n",
    "\n",
    "<details><summary>Hint 2 (the line)</summary>`tp = int(((y_pred == 1) & (y_true == 1)).sum())`. The other three swap the 1s and 0s.</details>\n",
    "\n",
    "<details><summary>Help — \"unsupported operand\" or counts look like floats</summary>`.sum()` on a bool array gives a numpy int; wrap in `int(...)`. Division for precision needs floats, which Python gives you automatically.</details>\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "a43635c5",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-06-10T18:34:05.271428Z",
     "iopub.status.busy": "2026-06-10T18:34:05.271355Z",
     "iopub.status.idle": "2026-06-10T18:34:05.275118Z",
     "shell.execute_reply": "2026-06-10T18:34:05.274765Z"
    },
    "collapsed": true,
    "jupyter": {
     "source_hidden": true
    },
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ ok ] 3.1 confusion (toy)\n",
      "[ ok ] 3.1 vs sklearn\n",
      "precision 0.94 · recall 0.54  (accuracy 95.3%)\n"
     ]
    }
   ],
   "source": [
    "#@title Solution { display-mode: \"form\" }\n",
    "# solution: redefines the functions; the checks below re-verify the reference.\n",
    "def confusion(y_true, y_pred):\n",
    "    y_true, y_pred = np.asarray(y_true), np.asarray(y_pred)\n",
    "    tp = int(((y_pred == 1) & (y_true == 1)).sum())\n",
    "    fp = int(((y_pred == 1) & (y_true == 0)).sum())\n",
    "    fn = int(((y_pred == 0) & (y_true == 1)).sum())\n",
    "    tn = int(((y_pred == 0) & (y_true == 0)).sum())\n",
    "    return tp, fp, fn, tn\n",
    "\n",
    "def precision_recall(y_true, y_pred):\n",
    "    tp, fp, fn, tn = confusion(y_true, y_pred)\n",
    "    prec = tp / (tp + fp) if (tp + fp) else 0.0\n",
    "    rec = tp / (tp + fn) if (tp + fn) else 0.0\n",
    "    return prec, rec\n",
    "\n",
    "check(\"3.1 confusion (toy)\", _toy, required=True)\n",
    "check(\"3.1 vs sklearn\", lambda: _vs_sklearn(confusion, pred, yte), required=True)\n",
    "p, r = precision_recall(yte, pred)\n",
    "print(f\"precision {p:.2f} · recall {r:.2f}  (accuracy {(pred==yte).mean():.1%})\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8eef3fb9",
   "metadata": {},
   "source": [
    "> **Interpretation.** The real model's accuracy is barely above the do-nothing baseline, but precision and recall reveal what it's actually doing with the minority class — information accuracy threw away.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a9061d00",
   "metadata": {},
   "source": [
    "## Part 3 — The threshold is a choice\n",
    "\n",
    "`predict_proba` gives a *score*, not a decision. The 0.5 cutoff is a default, not a law. Sweep it and watch precision and recall trade off.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "2b9f8102",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-06-10T18:34:05.276002Z",
     "iopub.status.busy": "2026-06-10T18:34:05.275923Z",
     "iopub.status.idle": "2026-06-10T18:34:05.401665Z",
     "shell.execute_reply": "2026-06-10T18:34:05.401311Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 1000x400 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ROC-AUC 0.929 · average precision 0.795\n"
     ]
    }
   ],
   "source": [
    "from sklearn.metrics import precision_recall_curve, roc_curve, roc_auc_score, average_precision_score\n",
    "prec_c, rec_c, thr = precision_recall_curve(yte, scores)\n",
    "fpr, tpr, _ = roc_curve(yte, scores)\n",
    "auc = roc_auc_score(yte, scores)\n",
    "ap = average_precision_score(yte, scores)\n",
    "\n",
    "fig, ax = plt.subplots(1, 2, figsize=(10, 4))\n",
    "ax[0].plot(rec_c, prec_c, color=\"#1E40FF\"); ax[0].set_xlabel(\"recall\"); ax[0].set_ylabel(\"precision\")\n",
    "ax[0].set_title(f\"PR curve (AP={ap:.2f})\"); ax[0].axhline(yte.mean(), ls=\":\", c=\"#888\", label=\"no-skill\")\n",
    "ax[0].legend()\n",
    "ax[1].plot(fpr, tpr, color=\"#1E40FF\"); ax[1].plot([0,1],[0,1], ls=\":\", c=\"#888\")\n",
    "ax[1].set_xlabel(\"false positive rate\"); ax[1].set_ylabel(\"true positive rate\")\n",
    "ax[1].set_title(f\"ROC curve (AUC={auc:.2f})\")\n",
    "plt.tight_layout(); plt.show()\n",
    "print(f\"ROC-AUC {auc:.3f} · average precision {ap:.3f}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "911046e5",
   "metadata": {},
   "source": [
    "> **Predict:** the no-skill line on the PR plot sits at the positive rate (~0.09), not at 0.5 like ROC. Why? <details><summary>Answer</summary>A random classifier's precision equals the base rate (of everything it flags, ~9% are truly positive). PR curves are honest about imbalance; ROC's diagonal hides it. On rare-positive problems, prefer average precision over AUC.</details>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "55456f9b",
   "metadata": {},
   "source": [
    "## Part 4 — A deliberate failure: optimizing the wrong metric\n",
    "\n",
    "Two models. Model A has higher accuracy. Model B has far better recall on the minority class. If you select by accuracy, you ship A — and miss almost every positive. Watch it happen.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "d6a583a8",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-06-10T18:34:05.403288Z",
     "iopub.status.busy": "2026-06-10T18:34:05.403205Z",
     "iopub.status.idle": "2026-06-10T18:34:05.410798Z",
     "shell.execute_reply": "2026-06-10T18:34:05.410080Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "A (accuracy-tuned)     acc=92.8%  recall=0.25\n",
      "B (balanced)           acc=86.2%  recall=0.82\n",
      "\n",
      "Selecting by accuracy ships A, which catches far fewer 5s. The metric chose the worse model.\n"
     ]
    }
   ],
   "source": [
    "# Model A: tuned to maximize accuracy (drifts toward the majority class)\n",
    "A = LogisticRegression(max_iter=1000, C=0.01, class_weight=None, random_state=SEED).fit(Xtr, ytr)\n",
    "# Model B: balanced class weights (cares about the minority)\n",
    "B = LogisticRegression(max_iter=1000, class_weight=\"balanced\", random_state=SEED).fit(Xtr, ytr)\n",
    "for name, m in [(\"A (accuracy-tuned)\", A), (\"B (balanced)\", B)]:\n",
    "    yp = m.predict(Xte)\n",
    "    pr, rc = precision_recall(yte, yp)\n",
    "    print(f\"{name:22} acc={ (yp==yte).mean():.1%}  recall={rc:.2f}\")\n",
    "print(\"\\nSelecting by accuracy ships A, which catches far fewer 5s. The metric chose the worse model.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "867d9bd0",
   "metadata": {},
   "source": [
    "> **Key takeaways.** Accuracy is a single number that lies on imbalanced data. Precision/recall split the error by *type*. The threshold is yours to set against the cost of a miss vs a false alarm. On rare positives, read the PR curve and average precision, not accuracy.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d2b2e6c7",
   "metadata": {},
   "source": [
    "## Safety lens\n",
    "\n",
    "A \"99% accurate\" content classifier on a 1%-harmful stream can miss *every* harmful item and still report 99%. Whenever a model gates a real decision, report the confusion matrix and the minority-class recall, not accuracy, and state the threshold and who chose it. Calibration and base rates are the difference between a number that sounds safe and one that is.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e8a4ac7b",
   "metadata": {},
   "source": [
    "## Going further\n",
    "- Géron, *Hands-On ML* 3e, Ch 3 — the MNIST is-it-a-5 arc this notebook compresses.\n",
    "- scikit-learn, *Receiver Operating Characteristic* and *Precision-Recall* user-guide pages.\n",
    "\n",
    "## What this enables\n",
    "- **Ch 04 — Training Models**: the scores you thresholded come from a loss you'll now minimize by hand.\n",
    "- **Ch 23 — Eval Science**: confidence intervals on these metrics, contamination, and judge bias.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6386c042",
   "metadata": {},
   "source": [
    "## Test yourself\n",
    "\n",
    "Three parts: concept self-checks, an auto-checked problem, and a capstone. Solutions are folded; try before you peek.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fdbfd74c",
   "metadata": {},
   "source": [
    "### Part A — Concepts\n",
    "1. You have 90% precision and 30% recall. In one sentence, what is the model doing? <details><summary>Answer</summary>When it flags something it is almost always right (high precision), but it stays silent on 70% of the real positives (low recall) — a cautious model that misses a lot.</details>\n",
    "2. Why can two models with identical accuracy be very differently useful? <details><summary>Answer</summary>Accuracy ignores *which* errors. One model's errors can all be false alarms (annoying), another's all misses (dangerous). The confusion matrix distinguishes them.</details>\n",
    "3. When is ROC-AUC misleading? <details><summary>Answer</summary>Under heavy class imbalance: AUC can stay high while the model is useless at the operating point you care about. Average precision (PR-AUC) is the honest summary there.</details>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "59539067",
   "metadata": {},
   "source": [
    "### Part B — F-beta from scratch\n",
    "`Difficulty 2/5 · ~8 min`\n",
    "\n",
    "Implement `fbeta(prec, rec, beta)` = (1+β²)·P·R / (β²·P + R). β>1 weights recall; β=1 is the F1 score.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "2128ede4",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-06-10T18:34:05.411635Z",
     "iopub.status.busy": "2026-06-10T18:34:05.411553Z",
     "iopub.status.idle": "2026-06-10T18:34:05.414689Z",
     "shell.execute_reply": "2026-06-10T18:34:05.414387Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ -- ] B fbeta: not attempted yet — fill in the TODO above, then re-run.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def fbeta(prec, rec, beta=1.0):\n",
    "    # TODO: implement the F-beta formula; return 0.0 if the denominator is 0\n",
    "    result = None\n",
    "    attempted(result)\n",
    "    return result\n",
    "\n",
    "def _fb():\n",
    "    # F1 of P=R=0.5 is 0.5; F2 weights recall, so with P=0.3,R=0.9 it exceeds F1\n",
    "    check_close(fbeta(0.5, 0.5, 1.0), 0.5, msg=\"F1 of (0.5,0.5) is 0.5\")\n",
    "    f1 = fbeta(0.3, 0.9, 1.0); f2 = fbeta(0.3, 0.9, 2.0)\n",
    "    assert f2 > f1, f\"F2 ({f2:.3f}) should exceed F1 ({f1:.3f}) when recall>precision\"\n",
    "check(\"B fbeta\", _fb)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6790c3ab",
   "metadata": {},
   "source": [
    "<details><summary>Hint 1</summary>Translate the formula directly; guard the denominator `beta**2 * prec + rec == 0`.</details>\n",
    "<details><summary>Solution</summary>\n",
    "\n",
    "```python\n",
    "def fbeta(prec, rec, beta=1.0):\n",
    "    denom = beta**2 * prec + rec\n",
    "    if denom == 0:\n",
    "        return 0.0\n",
    "    return (1 + beta**2) * prec * rec / denom\n",
    "```\n",
    "</details>\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "e6dec235",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-06-10T18:34:05.415663Z",
     "iopub.status.busy": "2026-06-10T18:34:05.415584Z",
     "iopub.status.idle": "2026-06-10T18:34:05.418191Z",
     "shell.execute_reply": "2026-06-10T18:34:05.417876Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ ok ] B fbeta\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def fbeta(prec, rec, beta=1.0):\n",
    "    denom = beta**2 * prec + rec\n",
    "    return (1 + beta**2) * prec * rec / denom if denom else 0.0\n",
    "check(\"B fbeta\", _fb, required=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "77c6e3b0",
   "metadata": {},
   "source": [
    "### Part C — Capstone: the real MNIST is-it-a-5\n",
    "\n",
    "Redo Parts 1-3 on real MNIST. Deliverables:\n",
    "1. Load MNIST via `sklearn.datasets.fetch_openml('mnist_784', version=1)`, build the binary `y == '5'` target, split.\n",
    "2. Train `SGDClassifier`, produce the confusion matrix with *your* `confusion()`, and the PR + ROC curves.\n",
    "3. Pick a threshold for a precision ≥ 0.90 operating point and report the recall you get there.\n",
    "\n",
    "Self-assessment (pass / partial / fail): (a) your `confusion()` matches sklearn on real data; (b) the PR curve's no-skill line sits at MNIST's 5-rate (~0.09); (c) you justify your threshold against a stated cost of misses vs false alarms; (d) accuracy is *not* your headline metric; (e) the notebook runs top-to-bottom.\n",
    "\n",
    "<details><summary>My solution (reference, ~1 min on CPU)</summary>\n",
    "\n",
    "```python\n",
    "from sklearn.datasets import fetch_openml\n",
    "from sklearn.linear_model import SGDClassifier\n",
    "mnist = fetch_openml('mnist_784', version=1, as_frame=False)\n",
    "Xm, ym = mnist.data, (mnist.target == '5').astype(int)\n",
    "Xmtr, Xmte, ymtr, ymte = Xm[:60000], Xm[60000:], ym[:60000], ym[60000:]\n",
    "sgd = SGDClassifier(loss='log_loss', random_state=SEED).fit(Xmtr, ymtr)\n",
    "s = sgd.predict_proba(Xmte)[:, 1]\n",
    "prec_c, rec_c, thr = precision_recall_curve(ymte, s)\n",
    "# smallest threshold reaching precision >= 0.90:\n",
    "i = np.argmax(prec_c >= 0.90)\n",
    "print(f\"precision {prec_c[i]:.2f} at recall {rec_c[i]:.2f}, threshold {thr[i]:.2f}\")\n",
    "```\n",
    "The reference catches the lesson: at precision 0.90 you keep maybe ~70-80% recall, and you *chose* that tradeoff.</details>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0572cfcd",
   "metadata": {},
   "source": [
    "---\n",
    "*Built top-to-bottom. If every check above printed `[ ok ]`, you've reproduced the chapter. Runtime stamp written by CI.*\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "obvix-nb",
   "language": "python",
   "name": "obvix-nb"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.12"
  },
  "obvix": {
   "title": "Ch 03 — Classification"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
