{"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.13"},"kaggle":{"accelerator":"none","dataSources":[{"sourceType":"competition","sourceId":3004},{"sourceType":"datasetVersion","sourceId":1934358}],"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false},"papermill":{"default_parameters":{},"duration":178.179645,"end_time":"2026-08-26T10:00:34.651621+00:00","environment_variables":{},"exception":null,"input_path":"__notebook__.ipynb","output_path":"__notebook__.ipynb","parameters":{},"start_time":"2026-08-26T09:57:36.471976+00:00","version":"2.7.0"}},"nbformat_minor":4,"nbformat":4,"cells":[{"id":"0fd75440","cell_type":"markdown","source":"<div style=\"background: linear-gradient(135deg, #0a0a1a 0%, #1a1035 50%, #0d1a2e 100%); padding: 48px 40px; border-radius: 16px; margin-bottom: 8px; border: 1px solid #2d2060;\">\n  <div style=\"display: flex; align-items: center; gap: 12px; margin-bottom: 16px;\">\n    <span style=\"background: #7c3aed; color: #fff; font-size: 11px; font-weight: 700; letter-spacing: 2px; padding: 4px 12px; border-radius: 20px; text-transform: uppercase;\">ML Series · Episode 39</span>\n  </div>\n  <h1 style=\"color: #ffffff; font-size: 38px; font-weight: 800; margin: 0 0 12px 0; line-height: 1.2;\">📊 Confusion Matrix &amp; Classification Metrics</h1>\n  <p style=\"color: #a89dd0; font-size: 16px; margin: 0 0 28px 0; max-width: 680px; line-height: 1.6;\">Why accuracy alone lies to you — mastering Precision, Recall, F1 Score, and the Confusion Matrix to build classifiers you can actually trust.</p>\n  <div style=\"display: flex; gap: 20px; flex-wrap: wrap;\">\n    <div style=\"background: rgba(255,255,255,0.06); border: 1px solid #2d2060; border-radius: 10px; padding: 14px 20px;\">\n      <div style=\"color: #a78bfa; font-size: 22px; font-weight: 700;\">2 Datasets</div>\n      <div style=\"color: #a89dd0; font-size: 12px; margin-top: 2px;\">Heart Disease + MNIST</div>\n    </div>\n    <div style=\"background: rgba(255,255,255,0.06); border: 1px solid #2d2060; border-radius: 10px; padding: 14px 20px;\">\n      <div style=\"color: #a78bfa; font-size: 22px; font-weight: 700;\">4 Metrics</div>\n      <div style=\"color: #a89dd0; font-size: 12px; margin-top: 2px;\">Accuracy · Precision · Recall · F1</div>\n    </div>\n    <div style=\"background: rgba(255,255,255,0.06); border: 1px solid #2d2060; border-radius: 10px; padding: 14px 20px;\">\n      <div style=\"color: #a78bfa; font-size: 22px; font-weight: 700;\">Binary + Multi</div>\n      <div style=\"color: #a89dd0; font-size: 12px; margin-top: 2px;\">Both classification types</div>\n    </div>\n  </div>\n</div>","metadata":{"papermill":{"duration":0.006108,"end_time":"2026-08-26T09:57:39.309143+00:00","exception":false,"start_time":"2026-08-26T09:57:39.303035+00:00","status":"completed"},"tags":[]}},{"id":"ab5ec288","cell_type":"markdown","source":"<div style=\"background: #0d0d20; border-left: 5px solid #7c3aed; border-radius: 0 10px 10px 0; padding: 20px 24px; margin: 24px 0; border: 1px solid #2d2060; border-left: 5px solid #7c3aed;\">\n  <h2 style=\"color: #a78bfa; font-size: 15px; font-weight: 700; text-transform: uppercase; letter-spacing: 1.5px; margin: 0 0 10px 0;\">📋 Table of Contents</h2>\n  <ol style=\"margin: 0; padding-left: 20px; color: #818cf8; line-height: 2.1; font-size: 14px;\">\n    <li><a href='#imports' style='color: #818cf8; text-decoration: none;'>Imports &amp; Setup</a></li>\n    <li><a href='#data' style='color: #818cf8; text-decoration: none;'>Dataset — Heart Disease (Binary Classification)</a></li>\n    <li><a href='#models' style='color: #818cf8; text-decoration: none;'>Training — Logistic Regression vs Decision Tree</a></li>\n    <li><a href='#accuracy' style='color: #818cf8; text-decoration: none;'>Accuracy Score — And Why It Can Mislead</a></li>\n    <li><a href='#confusion' style='color: #818cf8; text-decoration: none;'>Confusion Matrix — Reading TP, FP, FN, TN</a></li>\n    <li><a href='#errors' style='color: #818cf8; text-decoration: none;'>Type 1 &amp; Type 2 Errors</a></li>\n    <li><a href='#metrics' style='color: #818cf8; text-decoration: none;'>Precision, Recall &amp; F1 Score</a></li>\n    <li><a href='#averaging' style='color: #818cf8; text-decoration: none;'>Averaging Strategies — None, Macro, Weighted</a></li>\n    <li><a href='#multiclass' style='color: #818cf8; text-decoration: none;'>Multi-class Classification — MNIST Digits</a></li>\n    <li><a href='#report' style='color: #818cf8; text-decoration: none;'>Classification Report</a></li>\n    <li><a href='#summary' style='color: #818cf8; text-decoration: none;'>Summary &amp; When to Use Each Metric</a></li>\n  </ol>\n</div>","metadata":{"papermill":{"duration":0.004498,"end_time":"2026-08-26T09:57:39.318565+00:00","exception":false,"start_time":"2026-08-26T09:57:39.314067+00:00","status":"completed"},"tags":[]}},{"id":"f196e811","cell_type":"markdown","source":"<a id='imports'></a>\n<div style=\"border-bottom: 2px solid #7c3aed; padding-bottom: 8px; margin: 32px 0 20px 0;\">\n  <span style=\"background: #7c3aed; color: #fff; font-size: 11px; font-weight: 700; letter-spacing: 1.5px; padding: 3px 10px; border-radius: 4px; text-transform: uppercase;\">Section 1</span>\n  <h2 style=\"color: #e2e0f0; font-size: 22px; font-weight: 700; margin: 10px 0 0 0;\">Imports &amp; Setup</h2>\n</div>","metadata":{"papermill":{"duration":0.004464,"end_time":"2026-08-26T09:57:39.327633+00:00","exception":false,"start_time":"2026-08-26T09:57:39.323169+00:00","status":"completed"},"tags":[]}},{"id":"01beec0f","cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\nfrom sklearn.linear_model import LogisticRegression\nfrom sklearn.tree import DecisionTreeClassifier\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import (\n    accuracy_score, confusion_matrix,\n    precision_score, recall_score,\n    f1_score, classification_report,\n    ConfusionMatrixDisplay\n)","metadata":{"execution":{"iopub.status.busy":"2026-08-27T14:22:23.107355Z","iopub.execute_input":"2026-08-27T14:22:23.107760Z","iopub.status.idle":"2026-08-27T14:22:25.146011Z","shell.execute_reply.started":"2026-08-27T14:22:23.107725Z","shell.execute_reply":"2026-08-27T14:22:25.145172Z"},"papermill":{"duration":3.580255,"end_time":"2026-08-26T09:57:42.912468+00:00","exception":false,"start_time":"2026-08-26T09:57:39.332213+00:00","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"id":"f867bdcf","cell_type":"markdown","source":"<a id='data'></a>\n<div style=\"border-bottom: 2px solid #7c3aed; padding-bottom: 8px; margin: 32px 0 20px 0;\">\n  <span style=\"background: #7c3aed; color: #fff; font-size: 11px; font-weight: 700; letter-spacing: 1.5px; padding: 3px 10px; border-radius: 4px; text-transform: uppercase;\">Section 2</span>\n  <h2 style=\"color: #e2e0f0; font-size: 22px; font-weight: 700; margin: 10px 0 0 0;\">Dataset — Heart Disease (Binary Classification)</h2>\n</div>\n\nThe **UCI Heart Disease dataset** contains 303 patients with 13 clinical features. The target is binary — `1` means heart disease present, `0` means absent. This is a real medical classification problem where **the cost of errors is asymmetric** — missing a sick patient (false negative) is far more dangerous than a false alarm (false positive).\n\n<div style=\"background: #0d0d20; border: 1px solid #2d2060; border-radius: 10px; padding: 18px 24px; margin: 16px 0; font-size: 13px;\">\n  <div style=\"display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; text-align: center;\">\n    <div><div style=\"color: #a78bfa; font-size: 22px; font-weight: 700;\">303</div><div style=\"color: #a89dd0;\">patients</div></div>\n    <div><div style=\"color: #a78bfa; font-size: 22px; font-weight: 700;\">13</div><div style=\"color: #a89dd0;\">features</div></div>\n    <div><div style=\"color: #a78bfa; font-size: 22px; font-weight: 700;\">2</div><div style=\"color: #a89dd0;\">classes (binary)</div></div>\n    <div><div style=\"color: #a78bfa; font-size: 22px; font-weight: 700;\">Medical</div><div style=\"color: #a89dd0;\">real-world stakes</div></div>\n  </div>\n</div>","metadata":{"papermill":{"duration":0.004797,"end_time":"2026-08-26T09:57:42.922294+00:00","exception":false,"start_time":"2026-08-26T09:57:42.917497+00:00","status":"completed"},"tags":[]}},{"id":"f48be66b","cell_type":"code","source":"df = pd.read_csv(\"/kaggle/input/datasets/mragpavank/heart-diseaseuci/heart.csv\")\n\nprint(f\"Shape   : {df.shape}\")\nprint(f\"Nulls   : {df.isnull().sum().sum()}\")\nprint(f\"\\nTarget distribution:\")\nprint(df['target'].value_counts().rename({0: 'No Disease', 1: 'Disease'}).to_string())\n\ndf.head()","metadata":{"execution":{"iopub.status.busy":"2026-08-27T14:22:25.147780Z","iopub.execute_input":"2026-08-27T14:22:25.148259Z","iopub.status.idle":"2026-08-27T14:22:25.221332Z","shell.execute_reply.started":"2026-08-27T14:22:25.148227Z","shell.execute_reply":"2026-08-27T14:22:25.220428Z"},"papermill":{"duration":0.069664,"end_time":"2026-08-26T09:57:42.996752+00:00","exception":false,"start_time":"2026-08-26T09:57:42.927088+00:00","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"id":"3f970955","cell_type":"code","source":"X = df.drop(columns=['target'])\ny = df['target']\n\nX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42)\n\nprint(f\"Train : {X_train.shape}  |  Test : {X_test.shape}\")","metadata":{"execution":{"iopub.status.busy":"2026-08-27T14:22:25.222288Z","iopub.execute_input":"2026-08-27T14:22:25.222614Z","iopub.status.idle":"2026-08-27T14:22:25.233981Z","shell.execute_reply.started":"2026-08-27T14:22:25.222582Z","shell.execute_reply":"2026-08-27T14:22:25.233117Z"},"papermill":{"duration":0.019603,"end_time":"2026-08-26T09:57:43.021563+00:00","exception":false,"start_time":"2026-08-26T09:57:43.00196+00:00","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"id":"892f4c82","cell_type":"markdown","source":"<a id='models'></a>\n<div style=\"border-bottom: 2px solid #7c3aed; padding-bottom: 8px; margin: 32px 0 20px 0;\">\n  <span style=\"background: #7c3aed; color: #fff; font-size: 11px; font-weight: 700; letter-spacing: 1.5px; padding: 3px 10px; border-radius: 4px; text-transform: uppercase;\">Section 3</span>\n  <h2 style=\"color: #e2e0f0; font-size: 22px; font-weight: 700; margin: 10px 0 0 0;\">Training — Logistic Regression vs Decision Tree</h2>\n</div>\n\nWe train two classifiers to compare their performance across multiple metrics. Comparing models on a single metric (accuracy) is misleading — we need the full picture.","metadata":{"papermill":{"duration":0.005119,"end_time":"2026-08-26T09:57:43.032903+00:00","exception":false,"start_time":"2026-08-26T09:57:43.027784+00:00","status":"completed"},"tags":[]}},{"id":"1593079a","cell_type":"code","source":"clf1 = LogisticRegression(max_iter=1000)\nclf2 = DecisionTreeClassifier(random_state=42)\n\nclf1.fit(X_train, y_train)\nclf2.fit(X_train, y_train)\n\ny_pred1 = clf1.predict(X_test)   # Logistic Regression predictions\ny_pred2 = clf2.predict(X_test)   # Decision Tree predictions\n\nprint(\"Both models trained successfully.\")","metadata":{"execution":{"iopub.status.busy":"2026-08-27T14:22:25.235859Z","iopub.execute_input":"2026-08-27T14:22:25.236204Z","iopub.status.idle":"2026-08-27T14:22:25.422981Z","shell.execute_reply.started":"2026-08-27T14:22:25.236172Z","shell.execute_reply":"2026-08-27T14:22:25.422226Z"},"papermill":{"duration":0.186075,"end_time":"2026-08-26T09:57:43.224442+00:00","exception":false,"start_time":"2026-08-26T09:57:43.038367+00:00","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"id":"edb93314","cell_type":"markdown","source":"<a id='accuracy'></a>\n<div style=\"border-bottom: 2px solid #7c3aed; padding-bottom: 8px; margin: 32px 0 20px 0;\">\n  <span style=\"background: #7c3aed; color: #fff; font-size: 11px; font-weight: 700; letter-spacing: 1.5px; padding: 3px 10px; border-radius: 4px; text-transform: uppercase;\">Section 4</span>\n  <h2 style=\"color: #e2e0f0; font-size: 22px; font-weight: 700; margin: 10px 0 0 0;\">Accuracy Score — And Why It Can Mislead</h2>\n</div>\n\n**Accuracy** = (Correct predictions) / (Total predictions). It's the most intuitive metric — and the most dangerous one to use alone.\n\n<div style=\"background: #0d0d20; border: 1px solid #2d2060; border-radius: 12px; padding: 20px 26px; margin: 16px 0;\">\n  <div style=\"color: #a89dd0; font-size: 11px; letter-spacing: 1.5px; text-transform: uppercase; margin-bottom: 10px;\">When Accuracy Fails — Classic Example</div>\n  <div style=\"color: #e2e0f0; font-size: 14px; line-height: 1.8;\">\n    Imagine a cancer screening model on 1000 patients where only 10 have cancer.<br/>\n    A model that <strong style='color:#e74c3c;'>always predicts No Cancer</strong> gets <strong style='color:#e74c3c;'>99% accuracy</strong> — but it's completely useless.<br/>\n    It misses all 10 cancer patients. <strong style='color:#a78bfa;'>Accuracy hid a catastrophic failure.</strong>\n  </div>\n</div>\n\n<div style=\"display: flex; gap: 14px; margin: 16px 0;\">\n  <div style=\"flex: 1; background: #0d0d20; border: 1px solid #2d2060; border-top: 2px solid #e74c3c; border-radius: 0 0 8px 8px; padding: 14px 16px;\">\n    <div style=\"color: #e74c3c; font-weight: 700; font-size: 13px; margin-bottom: 4px;\">⚠️ Imbalanced classes</div>\n    <div style=\"color: #a89dd0; font-size: 13px;\">Rare events (fraud, disease) make accuracy trivially high by always predicting the majority class</div>\n  </div>\n  <div style=\"flex: 1; background: #0d0d20; border: 1px solid #2d2060; border-top: 2px solid #e74c3c; border-radius: 0 0 8px 8px; padding: 14px 16px;\">\n    <div style=\"color: #e74c3c; font-weight: 700; font-size: 13px; margin-bottom: 4px;\">⚠️ Unequal error costs</div>\n    <div style=\"color: #a89dd0; font-size: 13px;\">Missing a sick patient costs more than a false alarm — accuracy treats both errors identically</div>\n  </div>\n  <div style=\"flex: 1; background: #0d0d20; border: 1px solid #2d2060; border-top: 2px solid #a78bfa; border-radius: 0 0 8px 8px; padding: 14px 16px;\">\n    <div style=\"color: #a78bfa; font-weight: 700; font-size: 13px; margin-bottom: 4px;\">✅ Solution</div>\n    <div style=\"color: #a89dd0; font-size: 13px;\">Use Confusion Matrix, Precision, Recall, and F1 to understand <em>which</em> errors your model makes</div>\n  </div>\n</div>","metadata":{"papermill":{"duration":0.008299,"end_time":"2026-08-26T09:57:43.241433+00:00","exception":false,"start_time":"2026-08-26T09:57:43.233134+00:00","status":"completed"},"tags":[]}},{"id":"92eb5a56","cell_type":"code","source":"acc1 = accuracy_score(y_test, y_pred1)\nacc2 = accuracy_score(y_test, y_pred2)\n\nprint(f\"Logistic Regression accuracy : {acc1:.4f}  ({acc1*100:.1f}%)\")\nprint(f\"Decision Tree accuracy        : {acc2:.4f}  ({acc2*100:.1f}%)\")\nprint()\nprint(\"👆 Logistic Regression looks clearly better — but let's dig deeper.\")","metadata":{"execution":{"iopub.status.busy":"2026-08-27T14:22:25.424193Z","iopub.execute_input":"2026-08-27T14:22:25.424507Z","iopub.status.idle":"2026-08-27T14:22:25.434929Z","shell.execute_reply.started":"2026-08-27T14:22:25.424457Z","shell.execute_reply":"2026-08-27T14:22:25.433528Z"},"papermill":{"duration":0.02454,"end_time":"2026-08-26T09:57:43.274601+00:00","exception":false,"start_time":"2026-08-26T09:57:43.250061+00:00","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"id":"0c599eb7","cell_type":"markdown","source":"<a id='confusion'></a>\n<div style=\"border-bottom: 2px solid #7c3aed; padding-bottom: 8px; margin: 32px 0 20px 0;\">\n  <span style=\"background: #7c3aed; color: #fff; font-size: 11px; font-weight: 700; letter-spacing: 1.5px; padding: 3px 10px; border-radius: 4px; text-transform: uppercase;\">Section 5</span>\n  <h2 style=\"color: #e2e0f0; font-size: 22px; font-weight: 700; margin: 10px 0 0 0;\">Confusion Matrix — Reading TP, FP, FN, TN</h2>\n</div>\n\nA confusion matrix shows the **full breakdown of every prediction** — not just whether the model was right or wrong, but which type of right and which type of wrong.\n\n<div style=\"background: #0d0d20; border: 1px solid #2d2060; border-radius: 12px; padding: 20px 28px; margin: 16px 0;\">\n  <div style=\"color: #a89dd0; font-size: 11px; letter-spacing: 1.5px; text-transform: uppercase; margin-bottom: 16px;\">Confusion Matrix — 2×2 Layout (Binary)</div>\n  <div style=\"display: grid; grid-template-columns: 1fr 1fr; gap: 12px; max-width: 440px;\">\n    <div style=\"background: rgba(46,204,113,0.15); border: 1px solid #2ecc71; border-radius: 8px; padding: 14px; text-align: center;\">\n      <div style=\"color: #2ecc71; font-weight: 800; font-size: 16px;\">TP</div>\n      <div style=\"color: #e2e0f0; font-size: 12px; margin-top: 4px;\">True Positive<br/>Predicted 1, Actually 1 ✅</div>\n    </div>\n    <div style=\"background: rgba(231,76,60,0.15); border: 1px solid #e74c3c; border-radius: 8px; padding: 14px; text-align: center;\">\n      <div style=\"color: #e74c3c; font-weight: 800; font-size: 16px;\">FP</div>\n      <div style=\"color: #e2e0f0; font-size: 12px; margin-top: 4px;\">False Positive<br/>Predicted 1, Actually 0 ❌<br/><em>Type I Error</em></div>\n    </div>\n    <div style=\"background: rgba(243,156,18,0.15); border: 1px solid #f39c12; border-radius: 8px; padding: 14px; text-align: center;\">\n      <div style=\"color: #f39c12; font-weight: 800; font-size: 16px;\">FN</div>\n      <div style=\"color: #e2e0f0; font-size: 12px; margin-top: 4px;\">False Negative<br/>Predicted 0, Actually 1 ❌<br/><em>Type II Error</em></div>\n    </div>\n    <div style=\"background: rgba(46,204,113,0.15); border: 1px solid #2ecc71; border-radius: 8px; padding: 14px; text-align: center;\">\n      <div style=\"color: #2ecc71; font-weight: 800; font-size: 16px;\">TN</div>\n      <div style=\"color: #e2e0f0; font-size: 12px; margin-top: 4px;\">True Negative<br/>Predicted 0, Actually 0 ✅</div>\n    </div>\n  </div>\n  <div style=\"color: #a89dd0; font-size: 12px; margin-top: 14px;\">Layout: rows = actual labels, columns = predicted labels</div>\n</div>","metadata":{"papermill":{"duration":0.008318,"end_time":"2026-08-26T09:57:43.29187+00:00","exception":false,"start_time":"2026-08-26T09:57:43.283552+00:00","status":"completed"},"tags":[]}},{"id":"5b77fc60","cell_type":"code","source":"fig, axes = plt.subplots(1, 2, figsize=(13, 5))\nfig.suptitle('Confusion Matrices — Logistic Regression vs Decision Tree',\n             fontsize=13, fontweight='bold')\n\nfor ax, y_pred, title in zip(\n    axes,\n    [y_pred1, y_pred2],\n    ['Logistic Regression', 'Decision Tree']\n):\n    cm = confusion_matrix(y_test, y_pred)\n    disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=['No Disease (0)', 'Disease (1)'])\n    disp.plot(ax=ax, colorbar=False, cmap='Purples')\n    ax.set_title(f'{title}\\nAccuracy: {accuracy_score(y_test, y_pred):.3f}',\n                 fontsize=11, fontweight='bold')\n    ax.set_xlabel('Predicted Label', fontsize=10)\n    ax.set_ylabel('True Label', fontsize=10)\n\nplt.tight_layout()\nplt.show()\n\n# Also print as DataFrame for reference\nprint(\"Logistic Regression Confusion Matrix:\")\nprint(pd.DataFrame(confusion_matrix(y_test, y_pred1),\n      index=['Actual 0', 'Actual 1'],\n      columns=['Predicted 0', 'Predicted 1']), \"\\n\")\n\nprint(\"Decision Tree Confusion Matrix:\")\nprint(pd.DataFrame(confusion_matrix(y_test, y_pred2),\n      index=['Actual 0', 'Actual 1'],\n      columns=['Predicted 0', 'Predicted 1']))","metadata":{"execution":{"iopub.status.busy":"2026-08-27T14:22:25.435833Z","iopub.execute_input":"2026-08-27T14:22:25.436132Z","iopub.status.idle":"2026-08-27T14:22:25.759262Z","shell.execute_reply.started":"2026-08-27T14:22:25.436102Z","shell.execute_reply":"2026-08-27T14:22:25.758280Z"},"papermill":{"duration":0.323858,"end_time":"2026-08-26T09:57:43.624351+00:00","exception":false,"start_time":"2026-08-26T09:57:43.300493+00:00","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"id":"6f9a6562","cell_type":"code","source":"# Side-by-side prediction sample\nresult = pd.DataFrame({\n    'Actual':               y_test.values,\n    'Logistic Regression':  y_pred1,\n    'Decision Tree':        y_pred2\n}, index=y_test.index)\n\nresult['LR Correct?']  = result['Actual'] == result['Logistic Regression']\nresult['DT Correct?']  = result['Actual'] == result['Decision Tree']\n\nresult.sample(10, random_state=1)","metadata":{"execution":{"iopub.status.busy":"2026-08-27T14:22:25.760452Z","iopub.execute_input":"2026-08-27T14:22:25.760799Z","iopub.status.idle":"2026-08-27T14:22:25.774932Z","shell.execute_reply.started":"2026-08-27T14:22:25.760772Z","shell.execute_reply":"2026-08-27T14:22:25.773875Z"},"papermill":{"duration":0.023882,"end_time":"2026-08-26T09:57:43.654559+00:00","exception":false,"start_time":"2026-08-26T09:57:43.630677+00:00","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"id":"c2006a5b","cell_type":"markdown","source":"<a id='errors'></a>\n<div style=\"border-bottom: 2px solid #7c3aed; padding-bottom: 8px; margin: 32px 0 20px 0;\">\n  <span style=\"background: #7c3aed; color: #fff; font-size: 11px; font-weight: 700; letter-spacing: 1.5px; padding: 3px 10px; border-radius: 4px; text-transform: uppercase;\">Section 6</span>\n  <h2 style=\"color: #e2e0f0; font-size: 22px; font-weight: 700; margin: 10px 0 0 0;\">Type I &amp; Type II Errors — Why Error Type Matters</h2>\n</div>\n\nNot all mistakes are equal. The confusion matrix reveals **which kind of errors** your model makes — and in medical, legal, or safety contexts, the two types have very different consequences.\n\n<div style=\"display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin: 20px 0;\">\n  <div style=\"background: #0d0d20; border: 1px solid #e74c3c; border-radius: 10px; padding: 20px;\">\n    <div style=\"color: #e74c3c; font-size: 14px; font-weight: 700; margin-bottom: 10px;\">🔴 Type I Error — False Positive (FP)</div>\n    <div style=\"color: #a89dd0; font-size: 13px; line-height: 1.7;\">\n      Model predicts <strong style='color:#e2e0f0;'>positive</strong> when the truth is <strong style='color:#e2e0f0;'>negative</strong>.<br/><br/>\n      <strong>Heart disease:</strong> Telling a healthy patient they have heart disease → unnecessary stress, tests, treatment<br/><br/>\n      <strong>Spam filter:</strong> Marking a legitimate email as spam → missing an important message<br/><br/>\n      <em>Metric that catches this: <strong style='color:#a78bfa;'>Precision</strong></em>\n    </div>\n  </div>\n  <div style=\"background: #0d0d20; border: 1px solid #f39c12; border-radius: 10px; padding: 20px;\">\n    <div style=\"color: #f39c12; font-size: 14px; font-weight: 700; margin-bottom: 10px;\">🟡 Type II Error — False Negative (FN)</div>\n    <div style=\"color: #a89dd0; font-size: 13px; line-height: 1.7;\">\n      Model predicts <strong style='color:#e2e0f0;'>negative</strong> when the truth is <strong style='color:#e2e0f0;'>positive</strong>.<br/><br/>\n      <strong>Heart disease:</strong> Missing a sick patient who actually has heart disease → delayed treatment, death risk<br/><br/>\n      <strong>Fraud detection:</strong> Flagging a real fraud as legitimate → financial loss<br/><br/>\n      <em>Metric that catches this: <strong style='color:#a78bfa;'>Recall</strong></em>\n    </div>\n  </div>\n</div>\n\n<div style=\"background: #13102a; border: 1px solid #2d2060; border-radius: 8px; padding: 14px 18px; margin: 14px 0; font-size: 13px; color: #a89dd0;\">\n  <strong style=\"color: #a78bfa;\">💡 In our heart disease problem:</strong> A False Negative (missing a sick patient) is far more dangerous than a False Positive (extra tests for a healthy patient). This means <strong style='color:#e2e0f0;'>Recall is more important than Precision</strong> here — and accuracy alone hides this entirely.\n</div>","metadata":{"papermill":{"duration":0.006125,"end_time":"2026-08-26T09:57:43.667159+00:00","exception":false,"start_time":"2026-08-26T09:57:43.661034+00:00","status":"completed"},"tags":[]}},{"id":"c63ce604","cell_type":"markdown","source":"<a id='metrics'></a>\n<div style=\"border-bottom: 2px solid #7c3aed; padding-bottom: 8px; margin: 32px 0 20px 0;\">\n  <span style=\"background: #7c3aed; color: #fff; font-size: 11px; font-weight: 700; letter-spacing: 1.5px; padding: 3px 10px; border-radius: 4px; text-transform: uppercase;\">Section 7</span>\n  <h2 style=\"color: #e2e0f0; font-size: 22px; font-weight: 700; margin: 10px 0 0 0;\">Precision, Recall &amp; F1 Score</h2>\n</div>\n\nEach metric answers a different question about your model's behaviour:\n\n<div style=\"background: #0d0d20; border: 1px solid #2d2060; border-radius: 12px; padding: 22px 28px; margin: 16px 0;\">\n  <div style=\"display: flex; flex-direction: column; gap: 16px;\">\n    <div style=\"display: flex; gap: 16px; align-items: center;\">\n      <div style=\"background: #1e1040; border: 1px solid #7c3aed; border-radius: 8px; padding: 10px 16px; min-width: 110px; text-align: center;\">\n        <div style=\"color: #a78bfa; font-weight: 800; font-size: 15px;\">Precision</div>\n      </div>\n      <div>\n        <div style=\"color: #e2e0f0; font-size: 15px; font-family: Georgia, serif;\">TP / (TP + FP)</div>\n        <div style=\"color: #a89dd0; font-size: 13px; margin-top: 4px;\">\"Of all the patients I predicted have disease, what fraction actually do?\" — measures <strong style='color:#e2e0f0;'>quality of positive predictions</strong></div>\n      </div>\n    </div>\n    <div style=\"display: flex; gap: 16px; align-items: center;\">\n      <div style=\"background: #1e1040; border: 1px solid #7c3aed; border-radius: 8px; padding: 10px 16px; min-width: 110px; text-align: center;\">\n        <div style=\"color: #a78bfa; font-weight: 800; font-size: 15px;\">Recall</div>\n      </div>\n      <div>\n        <div style=\"color: #e2e0f0; font-size: 15px; font-family: Georgia, serif;\">TP / (TP + FN)</div>\n        <div style=\"color: #a89dd0; font-size: 13px; margin-top: 4px;\">\"Of all patients who actually have disease, how many did I catch?\" — measures <strong style='color:#e2e0f0;'>coverage of actual positives</strong></div>\n      </div>\n    </div>\n    <div style=\"display: flex; gap: 16px; align-items: center;\">\n      <div style=\"background: #1e1040; border: 1px solid #7c3aed; border-radius: 8px; padding: 10px 16px; min-width: 110px; text-align: center;\">\n        <div style=\"color: #a78bfa; font-weight: 800; font-size: 15px;\">F1 Score</div>\n      </div>\n      <div>\n        <div style=\"color: #e2e0f0; font-size: 15px; font-family: Georgia, serif;\">2 · (Precision · Recall) / (Precision + Recall)</div>\n        <div style=\"color: #a89dd0; font-size: 13px; margin-top: 4px;\">Harmonic mean of Precision and Recall — balances both. Use when you care about <strong style='color:#e2e0f0;'>both false positives and false negatives</strong></div>\n      </div>\n    </div>\n  </div>\n</div>","metadata":{"papermill":{"duration":0.006341,"end_time":"2026-08-26T09:57:43.680837+00:00","exception":false,"start_time":"2026-08-26T09:57:43.674496+00:00","status":"completed"},"tags":[]}},{"id":"920e6c65","cell_type":"code","source":"# ── Logistic Regression metrics ────────────────────────────────────────────\nprint(\"=\" * 50)\nprint(\"  LOGISTIC REGRESSION\")\nprint(\"=\" * 50)\ncm1 = confusion_matrix(y_test, y_pred1)\ntn, fp, fn, tp = cm1.ravel()\nprint(f\"  TP={tp}  FP={fp}  FN={fn}  TN={tn}\")\nprint(f\"  Accuracy  : {accuracy_score(y_test, y_pred1):.4f}\")\nprint(f\"  Precision : {precision_score(y_test, y_pred1):.4f}\")\nprint(f\"  Recall    : {recall_score(y_test, y_pred1):.4f}\")\nprint(f\"  F1 Score  : {f1_score(y_test, y_pred1):.4f}\")\n\nprint()\n\n# ── Decision Tree metrics ──────────────────────────────────────────────────\nprint(\"=\" * 50)\nprint(\"  DECISION TREE\")\nprint(\"=\" * 50)\ncm2 = confusion_matrix(y_test, y_pred2)\ntn2, fp2, fn2, tp2 = cm2.ravel()\nprint(f\"  TP={tp2}  FP={fp2}  FN={fn2}  TN={tn2}\")\nprint(f\"  Accuracy  : {accuracy_score(y_test, y_pred2):.4f}\")\nprint(f\"  Precision : {precision_score(y_test, y_pred2):.4f}\")\nprint(f\"  Recall    : {recall_score(y_test, y_pred2):.4f}\")\nprint(f\"  F1 Score  : {f1_score(y_test, y_pred2):.4f}\")","metadata":{"execution":{"iopub.status.busy":"2026-08-27T14:22:25.776220Z","iopub.execute_input":"2026-08-27T14:22:25.776577Z","iopub.status.idle":"2026-08-27T14:22:25.815066Z","shell.execute_reply.started":"2026-08-27T14:22:25.776540Z","shell.execute_reply":"2026-08-27T14:22:25.814032Z"},"papermill":{"duration":0.042522,"end_time":"2026-08-26T09:57:43.729919+00:00","exception":false,"start_time":"2026-08-26T09:57:43.687397+00:00","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"id":"55683a92","cell_type":"code","source":"# Visual comparison — radar / bar chart of all metrics\nmetrics = ['Accuracy', 'Precision', 'Recall', 'F1 Score']\nlr_scores = [\n    accuracy_score(y_test, y_pred1),\n    precision_score(y_test, y_pred1),\n    recall_score(y_test, y_pred1),\n    f1_score(y_test, y_pred1)\n]\ndt_scores = [\n    accuracy_score(y_test, y_pred2),\n    precision_score(y_test, y_pred2),\n    recall_score(y_test, y_pred2),\n    f1_score(y_test, y_pred2)\n]\n\nx = np.arange(len(metrics))\nwidth = 0.35\n\nfig, ax = plt.subplots(figsize=(10, 5))\nbars1 = ax.bar(x - width/2, lr_scores, width, label='Logistic Regression',\n               color='#7c3aed', alpha=0.85)\nbars2 = ax.bar(x + width/2, dt_scores, width, label='Decision Tree',\n               color='#a78bfa', alpha=0.85)\n\nax.set_xticks(x)\nax.set_xticklabels(metrics, fontsize=11)\nax.set_ylabel('Score', fontsize=11)\nax.set_ylim(0, 1.1)\nax.set_title('All Metrics — Logistic Regression vs Decision Tree', fontsize=13, fontweight='bold')\nax.legend(fontsize=10)\nax.bar_label(bars1, fmt='%.3f', fontsize=9, padding=2)\nax.bar_label(bars2, fmt='%.3f', fontsize=9, padding=2)\nax.grid(axis='y', alpha=0.3)\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2026-08-27T14:22:25.816273Z","iopub.execute_input":"2026-08-27T14:22:25.816653Z","iopub.status.idle":"2026-08-27T14:22:26.059158Z","shell.execute_reply.started":"2026-08-27T14:22:25.816615Z","shell.execute_reply":"2026-08-27T14:22:26.058280Z"},"papermill":{"duration":0.261539,"end_time":"2026-08-26T09:57:43.998039+00:00","exception":false,"start_time":"2026-08-26T09:57:43.7365+00:00","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"id":"1d72033e","cell_type":"markdown","source":"<div style=\"background: #0d0d20; border-left: 4px solid #a78bfa; border-radius: 0 8px 8px 0; padding: 14px 18px; margin: 12px 0; font-size: 14px; color: #a89dd0;\">\n  <strong style=\"color: #e2e0f0;\">✅ Key takeaway:</strong> Logistic Regression wins on every metric — especially <strong>Recall (0.927)</strong>. This means it catches more actual heart disease cases (fewer dangerous misses). The Decision Tree's Recall is lower, meaning it misses more sick patients — much riskier in a medical context.\n</div>","metadata":{"papermill":{"duration":0.006934,"end_time":"2026-08-26T09:57:44.012449+00:00","exception":false,"start_time":"2026-08-26T09:57:44.005515+00:00","status":"completed"},"tags":[]}},{"id":"b51ce77b","cell_type":"markdown","source":"<a id='averaging'></a>\n<div style=\"border-bottom: 2px solid #7c3aed; padding-bottom: 8px; margin: 32px 0 20px 0;\">\n  <span style=\"background: #7c3aed; color: #fff; font-size: 11px; font-weight: 700; letter-spacing: 1.5px; padding: 3px 10px; border-radius: 4px; text-transform: uppercase;\">Section 8</span>\n  <h2 style=\"color: #e2e0f0; font-size: 22px; font-weight: 700; margin: 10px 0 0 0;\">Averaging Strategies — None, Macro &amp; Weighted</h2>\n</div>\n\nWhen there are multiple classes, sklearn needs to know how to combine per-class scores into a single number. There are three strategies:\n\n<div style=\"background: #0d0d20; border: 1px solid #2d2060; border-radius: 10px; overflow: hidden; margin: 16px 0;\">\n  <table style=\"width: 100%; border-collapse: collapse; font-size: 13px;\">\n    <thead>\n      <tr style=\"background: #1e1040;\">\n        <th style=\"padding: 12px 16px; color: #a78bfa; text-align: left;\">Strategy</th>\n        <th style=\"padding: 12px 16px; color: #a78bfa; text-align: left;\">What it does</th>\n        <th style=\"padding: 12px 16px; color: #a78bfa; text-align: left;\">Use when</th>\n      </tr>\n    </thead>\n    <tbody>\n      <tr style=\"border-bottom: 1px solid #2d2060;\">\n        <td style=\"padding: 11px 16px; font-weight: 600; color: #e2e0f0;\">None</td>\n        <td style=\"padding: 11px 16px; color: #a89dd0;\">Returns score for each class separately (array)</td>\n        <td style=\"padding: 11px 16px; color: #a89dd0;\">You need per-class breakdown</td>\n      </tr>\n      <tr style=\"border-bottom: 1px solid #2d2060; background: rgba(124,58,237,0.05);\">\n        <td style=\"padding: 11px 16px; font-weight: 600; color: #e2e0f0;\">macro</td>\n        <td style=\"padding: 11px 16px; color: #a89dd0;\">Simple average — treats all classes equally</td>\n        <td style=\"padding: 11px 16px; color: #a89dd0;\">Balanced classes, each class equally important</td>\n      </tr>\n      <tr style=\"background: rgba(124,58,237,0.05);\">\n        <td style=\"padding: 11px 16px; font-weight: 600; color: #e2e0f0;\">weighted</td>\n        <td style=\"padding: 11px 16px; color: #a89dd0;\">Average weighted by class support (sample count)</td>\n        <td style=\"padding: 11px 16px; color: #a89dd0;\">Imbalanced classes, larger classes matter more</td>\n      </tr>\n    </tbody>\n  </table>\n</div>","metadata":{"papermill":{"duration":0.006813,"end_time":"2026-08-26T09:57:44.026348+00:00","exception":false,"start_time":"2026-08-26T09:57:44.019535+00:00","status":"completed"},"tags":[]}},{"id":"567a81b6","cell_type":"code","source":"print(\"── Per-class Precision (average=None) ───────────────────────\")\nprint(f\"  Logistic Regression : {precision_score(y_test, y_pred1, average=None).round(4)}\")\nprint(f\"  Decision Tree       : {precision_score(y_test, y_pred2, average=None).round(4)}\")\n\nprint(\"\\n── Per-class Recall (average=None) ──────────────────────────\")\nprint(f\"  Logistic Regression : {recall_score(y_test, y_pred1, average=None).round(4)}\")\nprint(f\"  Decision Tree       : {recall_score(y_test, y_pred2, average=None).round(4)}\")\n\nprint(\"\\n── Macro Average (equal class weight) ───────────────────────\")\nprint(f\"  Precision LR  : {precision_score(y_test, y_pred1, average='macro'):.4f}\")\nprint(f\"  Precision DT  : {precision_score(y_test, y_pred2, average='macro'):.4f}\")\nprint(f\"  Recall    LR  : {recall_score(y_test, y_pred1, average='macro'):.4f}\")\nprint(f\"  Recall    DT  : {recall_score(y_test, y_pred2, average='macro'):.4f}\")\n\nprint(\"\\n── Weighted Average (weighted by class size) ─────────────────\")\nprint(f\"  Precision LR  : {precision_score(y_test, y_pred1, average='weighted'):.4f}\")\nprint(f\"  Precision DT  : {precision_score(y_test, y_pred2, average='weighted'):.4f}\")\nprint(f\"  Recall    LR  : {recall_score(y_test, y_pred1, average='weighted'):.4f}\")\nprint(f\"  Recall    DT  : {recall_score(y_test, y_pred2, average='weighted'):.4f}\")","metadata":{"execution":{"iopub.status.busy":"2026-08-27T14:22:26.061370Z","iopub.execute_input":"2026-08-27T14:22:26.061666Z","iopub.status.idle":"2026-08-27T14:22:26.106555Z","shell.execute_reply.started":"2026-08-27T14:22:26.061639Z","shell.execute_reply":"2026-08-27T14:22:26.105693Z"},"papermill":{"duration":0.054884,"end_time":"2026-08-26T09:57:44.088317+00:00","exception":false,"start_time":"2026-08-26T09:57:44.033433+00:00","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"id":"40bce5a4","cell_type":"markdown","source":"<a id='multiclass'></a>\n<div style=\"border-bottom: 2px solid #7c3aed; padding-bottom: 8px; margin: 32px 0 20px 0;\">\n  <span style=\"background: #7c3aed; color: #fff; font-size: 11px; font-weight: 700; letter-spacing: 1.5px; padding: 3px 10px; border-radius: 4px; text-transform: uppercase;\">Section 9</span>\n  <h2 style=\"color: #e2e0f0; font-size: 22px; font-weight: 700; margin: 10px 0 0 0;\">Multi-class Classification — MNIST Handwritten Digits</h2>\n</div>\n\nEverything we've discussed for binary classification extends naturally to **10 classes**. The confusion matrix grows to 10×10 — each row represents an actual digit, each column a predicted digit. Off-diagonal cells reveal which digits are most commonly confused with each other.\n\n<div style=\"background: #0d0d20; border: 1px solid #2d2060; border-radius: 10px; padding: 16px 22px; margin: 14px 0; font-size: 13px; color: #a89dd0;\">\n  <strong style=\"color: #a78bfa;\">⚠️ Convergence warning fix:</strong> The original code gets a <code>ConvergenceWarning</code> because LogisticRegression hits the default <code>max_iter=100</code> limit on 784-dimensional image data. We fix this with <code>max_iter=1000</code>.\n</div>","metadata":{"papermill":{"duration":0.007018,"end_time":"2026-08-26T09:57:44.102571+00:00","exception":false,"start_time":"2026-08-26T09:57:44.095553+00:00","status":"completed"},"tags":[]}},{"id":"b1bc465b","cell_type":"code","source":"df1 = pd.read_csv('/kaggle/input/competitions/digit-recognizer/train.csv')\n\nprint(f\"Shape  : {df1.shape}\")\nprint(f\"Labels : {sorted(df1['label'].unique())}\")\nprint(f\"\\nClass distribution:\")\nprint(df1['label'].value_counts().sort_index().to_string())\n\ndf1.head(3)","metadata":{"execution":{"iopub.status.busy":"2026-08-27T14:22:26.107612Z","iopub.execute_input":"2026-08-27T14:22:26.107935Z","iopub.status.idle":"2026-08-27T14:22:29.399311Z","shell.execute_reply.started":"2026-08-27T14:22:26.107908Z","shell.execute_reply":"2026-08-27T14:22:29.398531Z"},"papermill":{"duration":2.819688,"end_time":"2026-08-26T09:57:46.929346+00:00","exception":false,"start_time":"2026-08-26T09:57:44.109658+00:00","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"id":"10081615","cell_type":"code","source":"X1 = df1.drop(columns=['label'])\ny1 = df1['label']\n\nX_train1, X_test1, y_train1, y_test1 = train_test_split(\n    X1, y1, test_size=0.25, random_state=2\n)\n\nprint(f\"Train : {X_train1.shape}  |  Test : {X_test1.shape}\")","metadata":{"execution":{"iopub.status.busy":"2026-08-27T14:22:29.400355Z","iopub.execute_input":"2026-08-27T14:22:29.401082Z","iopub.status.idle":"2026-08-27T14:22:29.734269Z","shell.execute_reply.started":"2026-08-27T14:22:29.401050Z","shell.execute_reply":"2026-08-27T14:22:29.733491Z"},"papermill":{"duration":0.271245,"end_time":"2026-08-26T09:57:47.20843+00:00","exception":false,"start_time":"2026-08-26T09:57:46.937185+00:00","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"id":"d5a3527e","cell_type":"code","source":"# Fix: max_iter=1000 prevents ConvergenceWarning on high-dim pixel data\nclf3 = LogisticRegression(max_iter=1000, random_state=42)\nclf4 = DecisionTreeClassifier(random_state=42)\n\nprint(\"Training Logistic Regression on 784 pixel features...\")\nclf3.fit(X_train1, y_train1)\nprint(\"Training Decision Tree...\")\nclf4.fit(X_train1, y_train1)\n\ny_pred3 = clf3.predict(X_test1)\ny_pred4 = clf4.predict(X_test1)\n\nprint(f\"\\nLogistic Regression accuracy : {accuracy_score(y_test1, y_pred3):.4f}\")\nprint(f\"Decision Tree accuracy        : {accuracy_score(y_test1, y_pred4):.4f}\")","metadata":{"execution":{"iopub.status.busy":"2026-08-27T14:22:29.735321Z","iopub.execute_input":"2026-08-27T14:22:29.735653Z","iopub.status.idle":"2026-08-27T14:25:12.885482Z","shell.execute_reply.started":"2026-08-27T14:22:29.735623Z","shell.execute_reply":"2026-08-27T14:25:12.884500Z"},"papermill":{"duration":165.280929,"end_time":"2026-08-26T10:00:32.496846+00:00","exception":false,"start_time":"2026-08-26T09:57:47.215917+00:00","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"id":"64a63204","cell_type":"code","source":"# Heatmap confusion matrices for both models\nfig, axes = plt.subplots(1, 2, figsize=(16, 7))\nfig.suptitle('10×10 Confusion Matrices — MNIST Digits', fontsize=14, fontweight='bold')\n\nfor ax, y_pred, title, acc in zip(\n    axes,\n    [y_pred3, y_pred4],\n    ['Logistic Regression', 'Decision Tree'],\n    [accuracy_score(y_test1, y_pred3), accuracy_score(y_test1, y_pred4)]\n):\n    cm = confusion_matrix(y_test1, y_pred)\n    sns.heatmap(cm, annot=True, fmt='d', cmap='Purples', ax=ax,\n                xticklabels=range(10), yticklabels=range(10),\n                linewidths=0.5, linecolor='#1e1040')\n    ax.set_title(f'{title} — Accuracy: {acc:.3f}', fontsize=12, fontweight='bold')\n    ax.set_xlabel('Predicted Digit', fontsize=10)\n    ax.set_ylabel('True Digit', fontsize=10)\n\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2026-08-27T14:25:12.886659Z","iopub.execute_input":"2026-08-27T14:25:12.886994Z","iopub.status.idle":"2026-08-27T14:25:13.760267Z","shell.execute_reply.started":"2026-08-27T14:25:12.886953Z","shell.execute_reply":"2026-08-27T14:25:13.759391Z"},"papermill":{"duration":0.924739,"end_time":"2026-08-26T10:00:33.434219+00:00","exception":false,"start_time":"2026-08-26T10:00:32.50948+00:00","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"id":"c0c0c1a8","cell_type":"markdown","source":"<div style=\"background: #0d0d20; border-left: 4px solid #a78bfa; border-radius: 0 8px 8px 0; padding: 14px 18px; margin: 12px 0; font-size: 14px; color: #a89dd0;\">\n  <strong style=\"color: #e2e0f0;\">🔍 Reading the heatmap:</strong> Dark diagonal cells = correct predictions. Any bright off-diagonal cell is a common confusion. For example, <strong>8 vs 9</strong> and <strong>4 vs 9</strong> are typical digit pairs that get confused because they look similar visually.\n</div>","metadata":{"papermill":{"duration":0.010179,"end_time":"2026-08-26T10:00:33.455093+00:00","exception":false,"start_time":"2026-08-26T10:00:33.444914+00:00","status":"completed"},"tags":[]}},{"id":"693d35f5","cell_type":"markdown","source":"<a id='report'></a>\n<div style=\"border-bottom: 2px solid #7c3aed; padding-bottom: 8px; margin: 32px 0 20px 0;\">\n  <span style=\"background: #7c3aed; color: #fff; font-size: 11px; font-weight: 700; letter-spacing: 1.5px; padding: 3px 10px; border-radius: 4px; text-transform: uppercase;\">Section 10</span>\n  <h2 style=\"color: #e2e0f0; font-size: 22px; font-weight: 700; margin: 10px 0 0 0;\">Classification Report — All Metrics at Once</h2>\n</div>\n\n`classification_report` prints Precision, Recall, and F1 for every class simultaneously — the fastest way to get a complete picture of model performance.\n\n<div style=\"background: #0d0d20; border: 1px solid #2d2060; border-radius: 8px; padding: 12px 18px; margin: 14px 0; font-size: 13px; color: #a89dd0;\">\n  <strong style=\"color: #a78bfa;\">📌 Reading the report:</strong>\n  <ul style=\"margin: 6px 0 0 0; padding-left: 18px; line-height: 2;\">\n    <li><code>precision</code> — quality of positive predictions for that class</li>\n    <li><code>recall</code> — fraction of actual instances of that class caught</li>\n    <li><code>f1-score</code> — harmonic mean of the two</li>\n    <li><code>support</code> — number of actual samples in that class (test set)</li>\n    <li><code>macro avg</code> — simple average across all classes</li>\n    <li><code>weighted avg</code> — average weighted by support count</li>\n  </ul>\n</div>","metadata":{"papermill":{"duration":0.0105,"end_time":"2026-08-26T10:00:33.476029+00:00","exception":false,"start_time":"2026-08-26T10:00:33.465529+00:00","status":"completed"},"tags":[]}},{"id":"56b7b28f","cell_type":"code","source":"print(\"=\" * 60)\nprint(\"  LOGISTIC REGRESSION — Classification Report (MNIST)\")\nprint(\"=\" * 60)\nprint(classification_report(y_test1, y_pred3))\n\nprint(\"=\" * 60)\nprint(\"  DECISION TREE — Classification Report (MNIST)\")\nprint(\"=\" * 60)\nprint(classification_report(y_test1, y_pred4))","metadata":{"execution":{"iopub.status.busy":"2026-08-27T14:25:13.761428Z","iopub.execute_input":"2026-08-27T14:25:13.762189Z","iopub.status.idle":"2026-08-27T14:25:13.792123Z","shell.execute_reply.started":"2026-08-27T14:25:13.762155Z","shell.execute_reply":"2026-08-27T14:25:13.791164Z"},"papermill":{"duration":0.045992,"end_time":"2026-08-26T10:00:33.532621+00:00","exception":false,"start_time":"2026-08-26T10:00:33.486629+00:00","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"id":"d0bf6964","cell_type":"code","source":"# Per-digit F1 bar chart — which digits are hardest to classify?\nfrom sklearn.metrics import f1_score\n\nf1_lr = f1_score(y_test1, y_pred3, average=None)\nf1_dt = f1_score(y_test1, y_pred4, average=None)\n\nx = np.arange(10)\nwidth = 0.35\n\nfig, ax = plt.subplots(figsize=(12, 5))\nbars1 = ax.bar(x - width/2, f1_lr, width, label='Logistic Regression', color='#7c3aed', alpha=0.85)\nbars2 = ax.bar(x + width/2, f1_dt, width, label='Decision Tree',       color='#a78bfa', alpha=0.85)\n\nax.set_xticks(x)\nax.set_xticklabels([f'Digit {i}' for i in range(10)], fontsize=10)\nax.set_ylabel('F1 Score', fontsize=11)\nax.set_ylim(0.6, 1.05)\nax.set_title('Per-Digit F1 Score — Which Digits Are Hardest to Classify?',\n             fontsize=13, fontweight='bold')\nax.legend(fontsize=10)\nax.bar_label(bars1, fmt='%.2f', fontsize=8, padding=2)\nax.bar_label(bars2, fmt='%.2f', fontsize=8, padding=2)\nax.grid(axis='y', alpha=0.3)\nax.axhline(f1_lr.mean(), color='#7c3aed', linestyle='--', linewidth=1, alpha=0.5, label='LR mean')\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2026-08-27T14:25:13.793328Z","iopub.execute_input":"2026-08-27T14:25:13.793850Z","iopub.status.idle":"2026-08-27T14:25:14.125252Z","shell.execute_reply.started":"2026-08-27T14:25:13.793812Z","shell.execute_reply":"2026-08-27T14:25:14.124394Z"},"papermill":{"duration":0.35276,"end_time":"2026-08-26T10:00:33.896188+00:00","exception":false,"start_time":"2026-08-26T10:00:33.543428+00:00","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"id":"5bdef3c1","cell_type":"markdown","source":"<a id='summary'></a>\n<div style=\"background: linear-gradient(135deg, #0a0a1a 0%, #1a1035 100%); border: 1px solid #2d2060; border-radius: 14px; padding: 36px 40px; margin-top: 32px;\">\n  <h2 style=\"color: #ffffff; font-size: 20px; font-weight: 700; margin: 0 0 8px 0;\">📌 Summary — When to Use Each Metric</h2>\n  <p style=\"color: #a89dd0; font-size: 13px; margin: 0 0 20px 0;\">Choose your metric based on what kind of error matters most in your domain.</p>\n  <div style=\"display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-bottom: 20px;\">\n    <div style=\"background: rgba(124,58,237,0.08); border: 1px solid #7c3aed; border-radius: 10px; padding: 16px 18px;\">\n      <div style=\"color: #a78bfa; font-weight: 700; font-size: 13px; margin-bottom: 6px;\">📊 Accuracy</div>\n      <div style=\"color: #a89dd0; font-size: 12px; line-height: 1.7;\">Use only when classes are balanced and errors are equally costly. <strong style='color:#e2e0f0;'>Default metric but often misleading.</strong> Never use alone on imbalanced data.</div>\n    </div>\n    <div style=\"background: rgba(124,58,237,0.08); border: 1px solid #7c3aed; border-radius: 10px; padding: 16px 18px;\">\n      <div style=\"color: #a78bfa; font-weight: 700; font-size: 13px; margin-bottom: 6px;\">🎯 Precision</div>\n      <div style=\"color: #a89dd0; font-size: 12px; line-height: 1.7;\">Use when <strong style='color:#e2e0f0;'>False Positives are costly</strong>. Spam filter (don't block good emails), recommendation systems (don't recommend bad items).</div>\n    </div>\n    <div style=\"background: rgba(124,58,237,0.08); border: 1px solid #7c3aed; border-radius: 10px; padding: 16px 18px;\">\n      <div style=\"color: #a78bfa; font-weight: 700; font-size: 13px; margin-bottom: 6px;\">🔍 Recall</div>\n      <div style=\"color: #a89dd0; font-size: 12px; line-height: 1.7;\">Use when <strong style='color:#e2e0f0;'>False Negatives are costly</strong>. Disease detection (don't miss sick patients), fraud detection (don't miss fraudulent transactions).</div>\n    </div>\n    <div style=\"background: rgba(124,58,237,0.08); border: 1px solid #7c3aed; border-radius: 10px; padding: 16px 18px;\">\n      <div style=\"color: #a78bfa; font-weight: 700; font-size: 13px; margin-bottom: 6px;\">⚖️ F1 Score</div>\n      <div style=\"color: #a89dd0; font-size: 12px; line-height: 1.7;\">Use when you need to <strong style='color:#e2e0f0;'>balance both Precision and Recall</strong> — imbalanced datasets where both error types matter. Best single metric for most real-world tasks.</div>\n    </div>\n  </div>\n  <div style=\"background: rgba(255,255,255,0.03); border: 1px solid #2d2060; border-radius: 8px; padding: 14px 20px; margin-bottom: 16px; font-size: 13px; color: #a89dd0;\">\n    <strong style=\"color: #a78bfa;\">🏥 This episode's domain (Heart Disease):</strong> <span style=\"color: #e2e0f0;\">Recall is king</span> — missing a sick patient is far worse than a false alarm. Logistic Regression's Recall of 0.927 vs Decision Tree's 0.756 is the decisive difference — accuracy alone (89% vs 78%) understates how much better LR really is.\n  </div>\n  <div style=\"padding-top: 14px; border-top: 1px solid #2d2060; color: #a89dd0; font-size: 12px;\">\n    Next up → <a href='https://www.kaggle.com/code/ahmedfakhar123/ml-40-roc-curve-auc-threshold-tuning' style='text-decoration: none;'><strong style='color:#a78bfa;'>ML 40: ROC Curve, AUC &amp; Threshold Tuning</strong></a> — visualising the Precision-Recall tradeoff across all decision thresholds.\n  </div>\n</div>","metadata":{"papermill":{"duration":0.011495,"end_time":"2026-08-26T10:00:33.919182+00:00","exception":false,"start_time":"2026-08-26T10:00:33.907687+00:00","status":"completed"},"tags":[]}}]}