{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "ed62e9f7",
   "metadata": {},
   "source": [
    "# 03 · Validation: an honest score we can compute ourselves\n",
    "\n",
    "In 02 the model scored ~1.00 on training data but much less on the leaderboard. Here we:\n",
    "1. hide part of our own training data and grade the model on it (**hold-out validation**),\n",
    "2. watch **overfitting** happen in a picture,\n",
    "3. see how noisy one split is on a *small* dataset,\n",
    "4. upgrade to **repeated K-fold cross-validation (CV)**, the score we'll trust for the rest of the project."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "d637ee3e",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-23T06:11:36.947057Z",
     "iopub.status.busy": "2026-10-23T06:11:36.947057Z",
     "iopub.status.idle": "2026-10-23T06:11:41.709449Z",
     "shell.execute_reply": "2026-10-23T06:11:41.709449Z"
    }
   },
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "from sklearn.ensemble import RandomForestClassifier\n",
    "from sklearn.tree import DecisionTreeClassifier\n",
    "from sklearn.metrics import accuracy_score\n",
    "from sklearn.model_selection import train_test_split, StratifiedKFold\n",
    "from utils import load_data, basic_prep, cv_score, TARGET, TIER_TO_NUM, SEED\n",
    "from score import score\n",
    "\n",
    "train, test = load_data()\n",
    "tr, te = basic_prep(train, test)\n",
    "FEATURES = [c for c in tr.columns if c not in (\"id\", TARGET)]\n",
    "X, y = tr[FEATURES], tr[TARGET].map(TIER_TO_NUM)\n",
    "\n",
    "def rf():\n",
    "    return RandomForestClassifier(n_estimators=300, random_state=SEED, n_jobs=-1)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8f1a7507",
   "metadata": {},
   "source": [
    "## 1. Hold-out validation\n",
    "Split train into 80% \"study material\" and 20% \"practice exam\". The model never sees the practice exam while learning.\n",
    "\n",
    "`stratify=y` keeps the same tier mix (⅓ each) in both parts."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "8b87eda6",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-23T06:11:41.712373Z",
     "iopub.status.busy": "2026-10-23T06:11:41.712373Z",
     "iopub.status.idle": "2026-10-23T06:11:42.346944Z",
     "shell.execute_reply": "2026-10-23T06:11:42.346944Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(326, 12) (82, 12)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "train accuracy:      1.0000\n",
      "validation accuracy: 0.6707\n",
      "leaderboard (from 02): {'public': 0.629}\n"
     ]
    }
   ],
   "source": [
    "X_tr, X_va, y_tr, y_va = train_test_split(X, y, test_size=0.2, random_state=SEED, stratify=y)\n",
    "print(X_tr.shape, X_va.shape)\n",
    "\n",
    "m = rf().fit(X_tr, y_tr)\n",
    "print(f\"train accuracy:      {accuracy_score(y_tr, m.predict(X_tr)):.4f}\")\n",
    "print(f\"validation accuracy: {accuracy_score(y_va, m.predict(X_va)):.4f}\")\n",
    "print(\"leaderboard (from 02):\", score(\"submissions/02_random_forest.csv\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7cbe69b2",
   "metadata": {},
   "source": [
    "The validation score is far below the training score and much closer to the leaderboard. Now we have a leaderboard-like score without submitting anything."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ee17c1c5",
   "metadata": {},
   "source": [
    "## 2. Overfitting, in a picture\n",
    "A single decision tree asks yes/no questions (\"area > 6000?\"). `max_depth` = how many questions in a row it may ask.\n",
    "Shallow tree = too simple (**underfitting**). Very deep tree = memorises every row (**overfitting**)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "3ffee2fe",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-23T06:11:42.348250Z",
     "iopub.status.busy": "2026-10-23T06:11:42.348250Z",
     "iopub.status.idle": "2026-10-23T06:11:42.563309Z",
     "shell.execute_reply": "2026-10-23T06:11:42.563309Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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1LJlS9y4cUOVJCT09OnT58Lr4sWL9f+WkVWZqFa3bl39aKuLiwtHXInIYnBklogok0mQlHA6ePBgVWYgdbGbN29OdBuppZVuBFOmTFFlBtIZQIKt1OImDaZJ1axZU3UcaN26NUaMGKHahv3666+JygykfZjsQ7du3TB06FCULl1aLXIgrbikhjZh0F6yZAmcnZ1V+zCp2/X09FQdFoSUMkirrsmTJ6uaYBkVTtiai4goq3FklojISHKaXsJgwtpQmSgl26QOVid79uxqm5eXl7os7bekt6v0lZWWVjKSKqOvchsdGTF988031WiskDD5559/qpFQ6duaGrmtBNkDBw6o8gJpqSUTwvLly6e/zZdffqmCtLQHkxIHaQcmdbzSbzYhGTWWfZZSh8aNG2PXrl0q0OrIZLBKlSqpx5J+s4aOi+jQocNz9bdERKbmIC0NTP6oRERkdWREV0Zo9+7dq18IgojI0rHMgIjIwsniBLKylyESPmXFLiIie8UwS0Rk4aSeNuGkrITkNL6pwmxy5QJERJaMZQZEREREZLU4AYyIiIiIrBbDLBERERFZLYZZIiIiIrJaDLNEREREZLUYZomIiIjIajHMEhEREZHVYpglIiIiIqvFMEtEREREVothloiIiIhgrf4PPYwUH62Aa74AAAAASUVORK5CYII=",
      "text/plain": [
       "<Figure size 800x400 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "depths = range(1, 16)\n",
    "train_scores, val_scores = [], []\n",
    "for d in depths:\n",
    "    tree = DecisionTreeClassifier(max_depth=d, random_state=SEED).fit(X_tr, y_tr)\n",
    "    train_scores.append(accuracy_score(y_tr, tree.predict(X_tr)))\n",
    "    val_scores.append(accuracy_score(y_va, tree.predict(X_va)))\n",
    "\n",
    "plt.figure(figsize=(8, 4))\n",
    "plt.plot(depths, train_scores, label=\"train\")\n",
    "plt.plot(depths, val_scores, label=\"validation\")\n",
    "plt.xlabel(\"max_depth\"); plt.ylabel(\"accuracy\"); plt.legend(); plt.title(\"Train vs validation accuracy\");"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a18a6867",
   "metadata": {},
   "source": [
    "- **Left side:** both scores are low → the tree is too simple.\n",
    "- **Right side:** train shoots up towards 1.0 while validation stays flat or drops → it is memorising noise.\n",
    "\n",
    "The **gap between train and validation** is how you spot overfitting."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "05a6d05b",
   "metadata": {},
   "source": [
    "## 3. How noisy is one split? (very, on small data)\n",
    "Same model, 10 different random 80/20 splits:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "1eb5d721",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-23T06:11:42.563309Z",
     "iopub.status.busy": "2026-10-23T06:11:42.563309Z",
     "iopub.status.idle": "2026-10-23T06:11:47.883421Z",
     "shell.execute_reply": "2026-10-23T06:11:47.882404Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "split 0: 0.6829\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "split 1: 0.7439\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "split 2: 0.7317\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "split 3: 0.7683\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "split 4: 0.7805\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "split 5: 0.6585\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "split 6: 0.7073\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "split 7: 0.7317\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "split 8: 0.7439\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "split 9: 0.7195\n",
      "range: 0.659 – 0.780\n"
     ]
    }
   ],
   "source": [
    "split_scores = []\n",
    "for seed in range(10):\n",
    "    a, b, c, d = train_test_split(X, y, test_size=0.2, random_state=seed, stratify=y)\n",
    "    split_scores.append(accuracy_score(d, rf().fit(a, c).predict(b)))\n",
    "    print(f\"split {seed}: {split_scores[-1]:.4f}\")\n",
    "print(f\"range: {min(split_scores):.3f} – {max(split_scores):.3f}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c5f8e0e4",
   "metadata": {},
   "source": [
    "The validation part has only ~80 houses, so each house is worth more than 1% of the score. Just *which* houses land in the 20% moves the result by several percent.\n",
    "If a new idea \"improves\" the score by 2%, one split can't tell us if it's real or luck.\n",
    "\n",
    "## 4. K-fold cross-validation\n",
    "Cut the training data into 5 equal **folds**. Train on 4, score on the 5th, and repeat so every fold gets a turn as the exam:\n",
    "\n",
    "```\n",
    "fold 0: [VAL][ tr ][ tr ][ tr ][ tr ]\n",
    "fold 1: [ tr ][VAL][ tr ][ tr ][ tr ]\n",
    "...\n",
    "fold 4: [ tr ][ tr ][ tr ][ tr ][VAL]\n",
    "```\n",
    "CV score = the average of the 5. Every row is used for validation exactly once."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "8406e709",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-23T06:11:47.883421Z",
     "iopub.status.busy": "2026-10-23T06:11:47.883421Z",
     "iopub.status.idle": "2026-10-23T06:11:50.581981Z",
     "shell.execute_reply": "2026-10-23T06:11:50.580956Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "fold 0: 0.6951\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "fold 1: 0.7195\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "fold 2: 0.7561\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "fold 3: 0.6914\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "fold 4: 0.6543\n",
      "CV accuracy: 0.7033 ± 0.0336\n"
     ]
    }
   ],
   "source": [
    "skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=SEED)\n",
    "scores = []\n",
    "for fold, (tr_idx, va_idx) in enumerate(skf.split(X, y)):\n",
    "    m = rf().fit(X.iloc[tr_idx], y.iloc[tr_idx])\n",
    "    scores.append(accuracy_score(y.iloc[va_idx], m.predict(X.iloc[va_idx])))\n",
    "    print(f\"fold {fold}: {scores[-1]:.4f}\")\n",
    "print(f\"CV accuracy: {np.mean(scores):.4f} ± {np.std(scores):.4f}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e06b2ac5",
   "metadata": {},
   "source": [
    "### Repeated K-fold: for small data\n",
    "Because our data is tiny, we go one step further: run the 5-fold **3 times** with different shuffles, and average all 15 scores.\n",
    "This is `cv_score()` in `utils.py`, and every later notebook calls it in one line:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "d6a02031",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-23T06:11:50.581981Z",
     "iopub.status.busy": "2026-10-23T06:11:50.581981Z",
     "iopub.status.idle": "2026-10-23T06:11:58.673299Z",
     "shell.execute_reply": "2026-10-23T06:11:58.673299Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  repeat 0 fold 0: 0.6951\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  repeat 0 fold 1: 0.7195\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  repeat 0 fold 2: 0.7561\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  repeat 0 fold 3: 0.6914\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  repeat 0 fold 4: 0.6543\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  repeat 1 fold 0: 0.6951\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  repeat 1 fold 1: 0.6829\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  repeat 1 fold 2: 0.6829\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  repeat 1 fold 3: 0.6420\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  repeat 1 fold 4: 0.7160\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  repeat 2 fold 0: 0.6829\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  repeat 2 fold 1: 0.6585\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  repeat 2 fold 2: 0.7195\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  repeat 2 fold 3: 0.7037\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  repeat 2 fold 4: 0.7407\n",
      "CV accuracy: 0.6961 ± 0.0303\n"
     ]
    }
   ],
   "source": [
    "mean, std, oof = cv_score(rf, X, y)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7a3c6190",
   "metadata": {},
   "source": [
    "(`oof` = \"out-of-fold\" predictions: every training row predicted by models that never saw it. We'll use these in 06.)\n",
    "\n",
    "## The rule for the rest of the project\n",
    "> **Trust your CV score, not the public leaderboard.**\n",
    "\n",
    "Here the public leaderboard is only ~60 houses, so one house = ~1.6%. Our CV uses all ~400 training houses, 3 times over.\n",
    "If CV improves but public drops a little, believe CV. Teams that chase the public leaderboard often fall when the private leaderboard is revealed (a \"shake-up\").\n",
    "\n",
    "Next: **04_feature_engineering**, to push the CV score up."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "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.12.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
