{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "080fa477",
   "metadata": {},
   "source": [
    "# Εργαστήριο – Ταξινόμηση Ι\n",
    "### Μηχανική Μάθηση και Εξόρυξη Γνώσης · ΗΜΜΥ ΕΛΜΕΠΑ · 9ο εξάμηνο\n",
    "\n",
    "Στόχος του εργαστηρίου είναι να γράψετε μόνοι σας τις βασικές εντολές για:\n",
    "\n",
    "- train / test split\n",
    "- δυαδική ταξινόμηση\n",
    "- cross-validation\n",
    "- confusion matrix\n",
    "- precision, recall και F1\n",
    "- threshold\n",
    "- ROC / AUC\n",
    "- multiclass classification\n",
    "- kNN\n",
    "- Naive Bayes\n",
    "- σύγκριση ταξινομητών\n",
    "\n",
    "Οι βιβλιοθήκες και τα δεδομένα δίνονται έτοιμα.  \n",
    "Στα σημεία **Άσκηση** γράφετε εσείς τον κώδικα.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9cf5f81d",
   "metadata": {},
   "source": [
    "## 0. Βιβλιοθήκες\n",
    "\n",
    "Τρέξτε το κελί χωρίς αλλαγές.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b97f09c5",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "from sklearn.datasets import load_digits\n",
    "from sklearn.model_selection import train_test_split, cross_val_score, cross_val_predict\n",
    "from sklearn.linear_model import SGDClassifier, LogisticRegression\n",
    "from sklearn.dummy import DummyClassifier\n",
    "from sklearn.metrics import (\n",
    "    confusion_matrix,\n",
    "    precision_score,\n",
    "    recall_score,\n",
    "    f1_score,\n",
    "    precision_recall_curve,\n",
    "    roc_curve,\n",
    "    roc_auc_score\n",
    ")\n",
    "from sklearn.preprocessing import StandardScaler\n",
    "from sklearn.pipeline import make_pipeline\n",
    "from sklearn.neighbors import KNeighborsClassifier\n",
    "from sklearn.naive_bayes import GaussianNB\n",
    "\n",
    "np.random.seed(42)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f1d0cb97",
   "metadata": {},
   "source": [
    "# Μέρος Α – Τα δεδομένα\n",
    "\n",
    "Χρησιμοποιούμε το `digits` του scikit-learn.\n",
    "\n",
    "Κάθε δείγμα είναι μία εικόνα 8×8 pixels και η ετικέτα είναι ένα ψηφίο από 0 έως 9.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f43991ee",
   "metadata": {},
   "outputs": [],
   "source": [
    "digits = load_digits()\n",
    "\n",
    "X = digits.data\n",
    "y = digits.target\n",
    "\n",
    "print(\"X:\", X.shape)\n",
    "print(\"y:\", y.shape)\n",
    "\n",
    "fig, axs = plt.subplots(1, 10, figsize=(12, 1.6))\n",
    "\n",
    "for ax, img, label in zip(axs, digits.images, y):\n",
    "    ax.imshow(img, cmap=\"gray_r\")\n",
    "    ax.set_title(label)\n",
    "    ax.axis(\"off\")\n",
    "\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eb04f31f",
   "metadata": {},
   "source": [
    "## Άσκηση Α1 – Train / test split\n",
    "\n",
    "Χωρίστε τα δεδομένα σε:\n",
    "\n",
    "- 80% training\n",
    "- 20% test\n",
    "- `random_state=42`\n",
    "- stratified split με βάση το `y`\n",
    "\n",
    "Χρησιμοποιήστε τη συνάρτηση `train_test_split`.\n",
    "\n",
    "**Έλεγχος:** πρέπει να προκύψουν 1437 training samples και 360 test samples.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "701e04e3",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "1320cc46",
   "metadata": {},
   "source": [
    "## Άσκηση Α2 – Δυαδικό πρόβλημα «είναι 5;»\n",
    "\n",
    "Δημιουργήστε δύο νέες μεταβλητές:\n",
    "\n",
    "- `y_train_5`\n",
    "- `y_test_5`\n",
    "\n",
    "Κάθε τιμή πρέπει να είναι `True` όταν το αντίστοιχο ψηφίο είναι 5 και `False` διαφορετικά.\n",
    "\n",
    "Στη συνέχεια εμφανίστε το ποσοστό των `5` στο training set.\n",
    "\n",
    "**Αναμενόμενο:** περίπου 10%.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "510d5a44",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "226a612d",
   "metadata": {},
   "source": [
    "# Μέρος Β – Accuracy και Cross-Validation\n",
    "\n",
    "Θα συγκρίνουμε:\n",
    "\n",
    "1. έναν `SGDClassifier`\n",
    "2. έναν `DummyClassifier` που προβλέπει πάντα την πιο συχνή κλάση\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f16523e1",
   "metadata": {},
   "source": [
    "## Άσκηση Β1 – Δημιουργία classifiers\n",
    "\n",
    "Δημιουργήστε:\n",
    "\n",
    "- `sgd_clf` με `random_state=42`\n",
    "- `dummy` με `strategy=\"most_frequent\"`\n",
    "\n",
    "Μην κάνετε ακόμη `fit`.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d6b484dc",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "5b880e94",
   "metadata": {},
   "source": [
    "## Άσκηση Β2 – 3-fold Cross-Validation\n",
    "\n",
    "Υπολογίστε την accuracy με `cross_val_score` για τους δύο classifiers.\n",
    "\n",
    "Χρησιμοποιήστε:\n",
    "\n",
    "- training data\n",
    "- το δυαδικό target `y_train_5`\n",
    "- `cv=3`\n",
    "- `scoring=\"accuracy\"`\n",
    "\n",
    "Εμφανίστε τα τρία scores για κάθε classifier.\n",
    "\n",
    "**Ερώτηση:** γιατί ο Dummy classifier μπορεί να έχει accuracy κοντά στο 90%;\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "54bff77b",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "9634db5e",
   "metadata": {},
   "source": [
    "# Μέρος Γ – Confusion Matrix, Precision, Recall, F1\n",
    "\n",
    "Δεν θα χρησιμοποιήσουμε ακόμη το test set.\n",
    "\n",
    "Θα πάρουμε out-of-fold predictions από το training set.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "17b41ca8",
   "metadata": {},
   "source": [
    "## Άσκηση Γ1 – Προβλέψεις με Cross-Validation\n",
    "\n",
    "Χρησιμοποιήστε `cross_val_predict` με:\n",
    "\n",
    "- `sgd_clf`\n",
    "- `X_train`\n",
    "- `y_train_5`\n",
    "- `cv=3`\n",
    "\n",
    "Αποθηκεύστε το αποτέλεσμα στη μεταβλητή:\n",
    "\n",
    "`y_train_pred`\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a93f180b",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "e06faea7",
   "metadata": {},
   "source": [
    "## Άσκηση Γ2 – Confusion Matrix\n",
    "\n",
    "Υπολογίστε τον πίνακα σύγχυσης με `confusion_matrix`.\n",
    "\n",
    "Αποθηκεύστε τον στη μεταβλητή `cm` και εμφανίστε τον.\n",
    "\n",
    "Στη συνέχεια εκτελέστε:\n",
    "\n",
    "```python\n",
    "TN, FP, FN, TP = cm.ravel()\n",
    "print(\"TN:\", TN, \"FP:\", FP, \"FN:\", FN, \"TP:\", TP)\n",
    "```\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "eebf8927",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "d5d79c5e",
   "metadata": {},
   "source": [
    "## Άσκηση Γ3 – Precision, Recall και F1\n",
    "\n",
    "Υπολογίστε για το `y_train_pred`:\n",
    "\n",
    "- precision\n",
    "- recall\n",
    "- F1\n",
    "\n",
    "Χρησιμοποιήστε τις συναρτήσεις:\n",
    "\n",
    "- `precision_score`\n",
    "- `recall_score`\n",
    "- `f1_score`\n",
    "\n",
    "Εμφανίστε τα τρία αποτελέσματα.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7d879f6f",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "0fcdb99b",
   "metadata": {},
   "source": [
    "# Μέρος Δ – Decision score και κατώφλι\n",
    "\n",
    "Ο classifier δεν παράγει μόνο `True/False`.  \n",
    "Μπορούμε να πάρουμε ένα **score απόφασης** και να επιλέξουμε διαφορετικό threshold.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "afe6821e",
   "metadata": {},
   "source": [
    "## Άσκηση Δ1 – Decision scores\n",
    "\n",
    "Χρησιμοποιήστε `cross_val_predict` ξανά, αλλά αυτή τη φορά προσθέστε:\n",
    "\n",
    "`method=\"decision_function\"`\n",
    "\n",
    "Αποθηκεύστε τα scores στο:\n",
    "\n",
    "`y_scores`\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "45375cbc",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "71ad8fad",
   "metadata": {},
   "source": [
    "## Άσκηση Δ2 – Precision–Recall curve\n",
    "\n",
    "Χρησιμοποιήστε:\n",
    "\n",
    "`precision_recall_curve`\n",
    "\n",
    "για να πάρετε:\n",
    "\n",
    "- `precisions`\n",
    "- `recalls`\n",
    "- `thresholds`\n",
    "\n",
    "Στη συνέχεια εκτελέστε το παρακάτω κελί για το διάγραμμα.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8a2f97c4",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ea7987be",
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.plot(thresholds, precisions[:-1], label=\"Precision\")\n",
    "plt.plot(thresholds, recalls[:-1], label=\"Recall\")\n",
    "\n",
    "plt.xlabel(\"Threshold\")\n",
    "plt.legend()\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cc8b5c01",
   "metadata": {},
   "source": [
    "## Άσκηση Δ3 – Threshold για precision ≥ 90%\n",
    "\n",
    "Βρείτε το **πρώτο** σημείο στο οποίο:\n",
    "\n",
    "`precision >= 0.90`\n",
    "\n",
    "και βρείτε το αντίστοιχο threshold.\n",
    "\n",
    "Στη συνέχεια δημιουργήστε νέες προβλέψεις με:\n",
    "\n",
    "`y_scores >= threshold`\n",
    "\n",
    "και υπολογίστε ξανά precision και recall.\n",
    "\n",
    "**Ερώτηση:** τι συνέβη στο recall;\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d96313df",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "298a760a",
   "metadata": {},
   "source": [
    "# Μέρος Ε – ROC και AUC\n",
    "\n",
    "Χρησιμοποιούμε τα ίδια `y_scores`.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1b24485f",
   "metadata": {},
   "source": [
    "## Άσκηση Ε1 – ROC curve\n",
    "\n",
    "Χρησιμοποιήστε `roc_curve` για να πάρετε:\n",
    "\n",
    "- `fpr`\n",
    "- `tpr`\n",
    "- `thresholds_roc`\n",
    "\n",
    "Στη συνέχεια υπολογίστε το AUC με `roc_auc_score`.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "53eaa3fd",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "879642f2",
   "metadata": {},
   "source": [
    "## Άσκηση Ε2 – Διάγραμμα ROC\n",
    "\n",
    "Χρησιμοποιήστε τα `fpr` και `tpr` που υπολογίσατε.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bceec230",
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.plot(fpr, tpr)\n",
    "plt.plot([0, 1], [0, 1], \"--\")\n",
    "\n",
    "plt.xlabel(\"False Positive Rate\")\n",
    "plt.ylabel(\"True Positive Rate\")\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fb0dfccd",
   "metadata": {},
   "source": [
    "# Μέρος ΣΤ – Multiclass Classification\n",
    "\n",
    "Επιστρέφουμε τώρα στο αρχικό πρόβλημα των 10 ψηφίων.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7f964578",
   "metadata": {},
   "source": [
    "## Άσκηση ΣΤ1 – Multiclass SGD\n",
    "\n",
    "Δημιουργήστε έναν νέο:\n",
    "\n",
    "`SGDClassifier(random_state=42)`\n",
    "\n",
    "και εκπαιδεύστε τον με:\n",
    "\n",
    "- `X_train`\n",
    "- `y_train`\n",
    "\n",
    "Στη συνέχεια προβλέψτε την κλάση του `X_test[0]`.\n",
    "\n",
    "Εμφανίστε:\n",
    "\n",
    "- την πραγματική κλάση\n",
    "- την πρόβλεψη\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c5d90b1b",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "354016b3",
   "metadata": {},
   "source": [
    "## Άσκηση ΣΤ2 – Multiclass Cross-Validation\n",
    "\n",
    "Υπολογίστε την accuracy του multiclass SGD με 5-fold cross-validation.\n",
    "\n",
    "Χρησιμοποιήστε `cross_val_score`.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "82504656",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "86d15c5d",
   "metadata": {},
   "source": [
    "# Μέρος Ζ – k-Nearest Neighbors\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "42f0c5a2",
   "metadata": {},
   "source": [
    "## Άσκηση Ζ1 – kNN\n",
    "\n",
    "Δημιουργήστε έναν `KNeighborsClassifier` με:\n",
    "\n",
    "`n_neighbors=3`\n",
    "\n",
    "Κάντε 5-fold cross-validation στο `X_train`, `y_train`.\n",
    "\n",
    "Εμφανίστε:\n",
    "\n",
    "- τα 5 scores\n",
    "- τον μέσο όρο\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "947fcc5d",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "16021507",
   "metadata": {},
   "source": [
    "## Άσκηση Ζ2 – Δοκιμή διαφορετικών k\n",
    "\n",
    "Για κάθε τιμή:\n",
    "\n",
    "`k = 1, 3, 5, 7, 9`\n",
    "\n",
    "υπολογίστε τη μέση 5-fold CV accuracy.\n",
    "\n",
    "Μπορείτε να χρησιμοποιήσετε ένα απλό `for`.\n",
    "\n",
    "Ποιο `k` δίνει την καλύτερη μέση accuracy;\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "29493325",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "9f74477b",
   "metadata": {},
   "source": [
    "# Μέρος Η – Naive Bayes\n",
    "\n",
    "Θα χρησιμοποιήσουμε `GaussianNB`, επειδή τα χαρακτηριστικά των εικόνων είναι αριθμητικά.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e936806c",
   "metadata": {},
   "source": [
    "## Άσκηση Η1 – Gaussian Naive Bayes\n",
    "\n",
    "Δημιουργήστε έναν `GaussianNB`.\n",
    "\n",
    "Υπολογίστε τη μέση 5-fold CV accuracy στο `X_train`, `y_train`.\n",
    "\n",
    "Συγκρίνετέ την με τον kNN.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8b21d53c",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "e16137e3",
   "metadata": {},
   "source": [
    "# Μέρος Θ – Σύγκριση τριών classifiers\n",
    "\n",
    "Θα συγκρίνουμε:\n",
    "\n",
    "- Logistic Regression\n",
    "- kNN\n",
    "- Gaussian Naive Bayes\n",
    "\n",
    "Το παρακάτω λεξικό είναι έτοιμο.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d6cf01fb",
   "metadata": {},
   "outputs": [],
   "source": [
    "models = {\n",
    "    \"Logistic Regression\": make_pipeline(\n",
    "        StandardScaler(),\n",
    "        LogisticRegression(max_iter=2000)\n",
    "    ),\n",
    "    \"kNN\": make_pipeline(\n",
    "        StandardScaler(),\n",
    "        KNeighborsClassifier(n_neighbors=3)\n",
    "    ),\n",
    "    \"Gaussian NB\": GaussianNB()\n",
    "}\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e7d202c9",
   "metadata": {},
   "source": [
    "## Άσκηση Θ1 – 5-fold Cross-Validation για όλα τα μοντέλα\n",
    "\n",
    "Για κάθε `(name, model)` του λεξικού `models`:\n",
    "\n",
    "1. υπολογίστε 5-fold CV accuracy\n",
    "2. υπολογίστε τον μέσο όρο\n",
    "3. εμφανίστε το όνομα και τη μέση accuracy\n",
    "\n",
    "Χρησιμοποιήστε ένα `for`.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "152e7238",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "00997b4d",
   "metadata": {},
   "source": [
    "# Μέρος Ι – Τελική αξιολόγηση στο test set\n",
    "\n",
    "Μέχρι τώρα χρησιμοποιούσαμε κυρίως cross-validation στο training set.\n",
    "\n",
    "Τώρα επιλέξτε **ένα** από τα μοντέλα του προηγούμενου μέρους.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6e7803a7",
   "metadata": {},
   "source": [
    "## Άσκηση Ι1 – Fit και test accuracy\n",
    "\n",
    "1. Επιλέξτε το μοντέλο που είχε την καλύτερη CV accuracy.\n",
    "2. Κάντε `fit` σε **όλο το `X_train`, `y_train`**.\n",
    "3. Υπολογίστε την accuracy στο `X_test`, `y_test` με τη μέθοδο `score`.\n",
    "\n",
    "Αυτή είναι η πρώτη και μοναδική χρήση του test set για τελική αξιολόγηση.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "eb909576",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "cec637e4",
   "metadata": {},
   "source": [
    "# Προαιρετικές ασκήσεις\n",
    "\n",
    "Αν υπάρχει χρόνος:\n",
    "\n",
    "### 1. Ανιχνευτής «8»\n",
    "Επαναλάβετε το δυαδικό πρόβλημα για το ψηφίο 8 αντί για το 5.\n",
    "\n",
    "### 2. Threshold για recall ≥ 95%\n",
    "Βρείτε threshold που δίνει recall τουλάχιστον 95%.  \n",
    "Υπολογίστε το precision σε αυτό το threshold.\n",
    "\n",
    "### 3. kNN\n",
    "Δοκιμάστε `weights=\"distance\"` και συγκρίνετε με την προεπιλογή.\n",
    "\n",
    "### 4. Τελική ερώτηση\n",
    "Ποιο από τα accuracy, precision, recall και F1 θα χρησιμοποιούσατε για ανίχνευση μιας πολύ σπάνιας νόσου και γιατί;\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
