{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div style=\"\n",
    "    border: 2px solid #4CAF50; \n",
    "    padding: 15px; \n",
    "    background-color: #f4f4f4; \n",
    "    border-radius: 10px; \n",
    "    align-items: center;\">\n",
    "\n",
    "<h1 style=\"margin: 0; color: #4CAF50;\">ML Basics 2: Lernen von Daten</h1>\n",
    "<h2 style=\"margin: 5px 0; color: #555;\">DSAI</h2>\n",
    "<h3 style=\"margin: 5px 0; color: #555;\">Jakob Eggl</h3>\n",
    "\n",
    "<div style=\"flex-shrink: 0;\">\n",
    "    <img src=\"https://www.htl-grieskirchen.at/wp/wp-content/uploads/2022/11/logo_bildschirm-1024x503.png\" alt=\"Logo\" style=\"width: 250px; height: auto;\"/>\n",
    "</div>\n",
    "<p1> © 2024/25 Jakob Eggl. Nutzung oder Verbreitung nur mit ausdrücklicher Genehmigung des Autors.</p1>\n",
    "</div>\n",
    "<div style=\"flex: 1;\">\n",
    "</div>   "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Beurteilung des Gelernten Models"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Im letzten Notebook haben wir gelernt, wie das Training von Modellen in etwa funktioniert und abschließend auch intuitive Beurteilungen von der Qualität des Models gemacht.\n",
    "\n",
    "Insbesondere haben wir diese Theorie immer anhand vom linearen Regressionsmodell erörtert. Obwohl für die verschiedenen Modelltypen dies unterschiedlich aussehen kann, stellt uns dieses Modell die Theorie sehr deutlich dar. \n",
    "\n",
    "![Underfitting_Regression](../resources/2_Underfitting_Wiederholung_Regression.png) vs. ![Overfitting_Regression](../resources/2_Overfitting_Wiederholung_Regression.png)\n",
    "\n",
    "(von https://visualize-it.github.io/polynomial_regression/simulation.html)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Nun wollen wir das ganze formalisieren und im Detail besprechen.\n",
    "\n",
    "Dabei werden wir folgende Dinge besprechen (und mit Code durchführen):\n",
    "* **Overfitting und Underfitting**\n",
    "* **Train-Test Splits**\n",
    "* **Metriken zur Evaluierung (inkl. Confusion Matrix)**\n",
    "* **Tipps und Tricks**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Overfitting und Underfitting"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Die beiden obigen Bilder repräsentieren 2 wichtige Zustände, welche im Rahmen des Trainings eines Modells erreicht werden können: **Overfitting** und **Underfitting**.\n",
    "\n",
    "Beides sind **Zustände**, die wir **nicht erreichen wollen**!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Overfitting\n",
    "\n",
    "* Modell \"**lernt** die Trainingsdaten **auswendig**\"\n",
    "* Jeder Punkt wird genau getroffen\n",
    "* Für **neue Punkte** ist die Vorhersage **schlecht**\n",
    "* Beispiel: Stell dir vor, du lernst für eine Matheprüfung, indem du alle Aufgaben auswendig lernst, die im Buch stehen. Wenn in der Prüfung andere Aufgaben kommen, weißt du nicht, wie du sie lösen sollst."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Underfitting\n",
    "\n",
    "* Modell ist **zu einfach** um Muster aus den Daten zu erkennen\n",
    "* Fast kein Punkt wird genau getroffen\n",
    "* Kann **weder Trainingsdaten**, **noch** neue **Daten** gut **vorhersagen**\n",
    "* Beispiel: Stell dir vor, du lernst für eine Matheprüfung, indem du nur die Überschriften aus dem Mathe-Buch liest. Nun hast du zu wenig Wissen, die Aufgaben zu lösen."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Der gute Mittelweg (Right Fit)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Wir wollen ein Modell, welches:\n",
    "* die **Muster gut erkennt**\n",
    "* **kein** **\"auswendig lernen\"** der (Trainings)Daten\n",
    "* **Gute Vorhersagen** für **neue Daten** treffen kann"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![Right Fit vs Overfitting and Underfitting](../resources/2_Overfitting_vs_Underfitting_Regression_Classification.png)\n",
    "\n",
    "(von https://de.mathworks.com/discovery/overfitting.html)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![Polynomial Grad 3 Right Fit](../resources/2_Good_Tradeoff_Polynomial_Degree3.png)\n",
    "\n",
    "(von https://visualize-it.github.io/polynomial_regression/simulation.html)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Wie können wir nun so ein Modell erhalten, bzw. wie können wir entscheiden, ob ein Modell zu einfach oder zu kompliziert ist?\n",
    "\n",
    "Um dies zu beantworten, sehen wir uns nun eine Technik an, bei der wir die Daten in sogenannte **Trainingsdaten** und **Testdaten** unterteilen."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Train Test Split"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![Train_Test_Split](../resources/2_Train_Test_Split.jpg)\n",
    "\n",
    "(von https://builtin.com/data-science/train-test-split)\n",
    "\n",
    "**Wichtig:** Auch bei den Testdaten besitzen wir das echte Label, hier mit $y$ gekennzeichnet."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. Was ist der Train-Test-Split?\n",
    "    * Methode um Datenset in **2 Teile** aufzuteilen\n",
    "        * **Trainingsdaten**: Werden vom Modell benutzt, um die Muster zu lernen.\n",
    "        * **Testdaten**: Werden verwendet, um zu überprüfen, ob das Modell auch bei neuen Daten gut funktioniert\n",
    "1. Warum brauchen wir das?\n",
    "    * Wir wollen sichergehen, dass das Modell nicht nur auswendig lernt (Overfitting) sondern auch gut verallgemeinern kann\n",
    "1. Wie teilt man die Daten auf?\n",
    "    * Frei wählbar, üblich sind aber etwa **80% Trainingsdaten** und **20% Testdaten**\n",
    "1. Beispiel:\n",
    "    * Stell dir vor, du lernst für eine Mathematikprüfung:\n",
    "        * Die Trainingsdaten sind einige Übungsbeispiele, bei denen auch die Lösung gegeben ist.\n",
    "        * Du versuchst nun mit Hilfe von den Lösungen die Aufgaben zu verstehen und zu lernen, wie man solche Beispiele löst\n",
    "        * Bei der Prüfung selber hast du aber keinen Zugang zu den Lösungen, weswegen du dir sicher sein willst, dass du die Beispiele tatsächlich verstanden hast und nicht nur die Übungsaufgaben auswendig gelernt hast\n",
    "        * Dafür verwendest du jetzt weitere Beispiele, von denen du die Lösung weißt (=Testdaten). Diese musst du nun lösen, ohne auf die Lösung zu schauen. Dafür kannst du im Nachhinein mit der Musterlösung vergleichen.\n",
    "1. Was gibt es sonst noch zu beachten?\n",
    "    * Die Testdaten dürfen nie im Trainingsdataset vorkommen! (Ansonsten könnte das Modell einfach auch die Testdaten auswendig lernen)\n",
    "    * Die Testdaten sollen das ganze Dataset gut repräsentieren, genauso die Trainingsdaten (**i.i.d.-Annahme** - siehe nächster Absatz)\n",
    "    * Es ist vernünftig (nicht nur hier, sondern allgemein), einen **seed** zu vergeben, somit bleiben die Ergebnisse reproduzierbar."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Die i.i.d. Annahme"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Eine Voraussetzung, um ein gutes Modell zu bekommen ist es, dass die Daten, die wir verwenden die **i.i.d.**-Annahme (**independent and identically distribueted** - also unabhängig und identisch verteilt) erfüllen. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. Was bedeuten unabhängige (**independent**) Daten?\n",
    "    * Jeder Datenpnkt ist von den anderen Datenpunkten unabhängig.\n",
    "    * Das Ergebnis des einen Datenpunktes hängt nicht (mit dem Ergebnis) des nächsten Datenpunkts zusammen!\n",
    "    * Beispiel: Wenn du für die Matheprüfung lernst, dann soll jedes Beispiel eigenständig sein. Man will also nicht, dass du ein Beispiel nicht lernen kannst, weil du bereits ein anderes nicht gelernt hast und umgekehrt.\n",
    "1. Was bedeuten identisch verteilte (**identically distributed**) Daten?\n",
    "    * Alle Datenpunkte sind gleich wahrscheinlich\n",
    "    * Es soll damit garantiert werden, dass von jedem möglichen Bereich Daten vorhanden sind\n",
    "    * Beispiel: Wenn du für die Matheprüfung lernst, dann wäre es schlecht, wenn in den Übungsbeispielen ein Kapitel nicht vorhanden ist. Dieses würdest du dann nicht lernen können und wärst dann schlecht für den Test vorbereitet."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* Sollten die Daten (und von dem gehen wir normalerweise aus) die **i.i.d.** Annahme erfüllen, so darf zum Beispiel das Mischen der Datenpunkte (Reihenfolge in dem Dataset) keinen Unterschied machen!\n",
    "* **Achtung:** Bei Sequentiellen Daten (zum Beispiel Audio, Text oder Zeitreihen im Allgemeinen) muss man aufpassen, hier darf man die Daten natürlich nicht einfach auf dieser Ebene mischen? Erfüllen Sie trotzdem die **i.i.d.** Voraussetzung?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* **Wichtig** ist auch: In beiden Datasets (Train und Test) sollen in etwa die gleichen \"Arten von Daten\" vorkommen:\n",
    "    * Im vorigen Beispiel (Lernen für die Mathematik Prüfung) heißt das konkret: Es sollen in beiden Aufgabensets (Training und Test) alle Arten von Problemen auftauchen. Es macht wenig Sinn, wenn zum Beispiel in den Übungsaufgaben nur Aufgaben zum Thema Differenzieren und im Testbeispiel nur Beispiele zum Thema Integrieren vorkommen!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Train/Test Split in Python"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.datasets import load_iris, load_wine\n",
    "import seaborn as sns"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Zuerst Laden wir das Dataset. Bisher haben wir nur eine Variable bekommen, diesmal wollen wir direkt x und y!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'load_iris' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[1], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m X, y \u001b[38;5;241m=\u001b[39m \u001b[43mload_iris\u001b[49m(return_X_y\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m, as_frame\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m) \u001b[38;5;66;03m# Wir verwenden as_frame = False (=Default), damit wir nur die Daten bekommen (als Array)\u001b[39;00m\n",
      "\u001b[0;31mNameError\u001b[0m: name 'load_iris' is not defined"
     ]
    }
   ],
   "source": [
    "X, y = load_iris(return_X_y=True, as_frame=False) # Wir verwenden as_frame = False (=Default), damit wir nur die Daten bekommen (als Array)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[5.1, 3.5, 1.4, 0.2],\n",
       "       [4.9, 3. , 1.4, 0.2],\n",
       "       [4.7, 3.2, 1.3, 0.2],\n",
       "       [4.6, 3.1, 1.5, 0.2],\n",
       "       [5. , 3.6, 1.4, 0.2],\n",
       "       [5.4, 3.9, 1.7, 0.4],\n",
       "       [4.6, 3.4, 1.4, 0.3],\n",
       "       [5. , 3.4, 1.5, 0.2],\n",
       "       [4.4, 2.9, 1.4, 0.2],\n",
       "       [4.9, 3.1, 1.5, 0.1],\n",
       "       [5.4, 3.7, 1.5, 0.2],\n",
       "       [4.8, 3.4, 1.6, 0.2],\n",
       "       [4.8, 3. , 1.4, 0.1],\n",
       "       [4.3, 3. , 1.1, 0.1],\n",
       "       [5.8, 4. , 1.2, 0.2],\n",
       "       [5.7, 4.4, 1.5, 0.4],\n",
       "       [5.4, 3.9, 1.3, 0.4],\n",
       "       [5.1, 3.5, 1.4, 0.3],\n",
       "       [5.7, 3.8, 1.7, 0.3],\n",
       "       [5.1, 3.8, 1.5, 0.3],\n",
       "       [5.4, 3.4, 1.7, 0.2],\n",
       "       [5.1, 3.7, 1.5, 0.4],\n",
       "       [4.6, 3.6, 1. , 0.2],\n",
       "       [5.1, 3.3, 1.7, 0.5],\n",
       "       [4.8, 3.4, 1.9, 0.2],\n",
       "       [5. , 3. , 1.6, 0.2],\n",
       "       [5. , 3.4, 1.6, 0.4],\n",
       "       [5.2, 3.5, 1.5, 0.2],\n",
       "       [5.2, 3.4, 1.4, 0.2],\n",
       "       [4.7, 3.2, 1.6, 0.2],\n",
       "       [4.8, 3.1, 1.6, 0.2],\n",
       "       [5.4, 3.4, 1.5, 0.4],\n",
       "       [5.2, 4.1, 1.5, 0.1],\n",
       "       [5.5, 4.2, 1.4, 0.2],\n",
       "       [4.9, 3.1, 1.5, 0.2],\n",
       "       [5. , 3.2, 1.2, 0.2],\n",
       "       [5.5, 3.5, 1.3, 0.2],\n",
       "       [4.9, 3.6, 1.4, 0.1],\n",
       "       [4.4, 3. , 1.3, 0.2],\n",
       "       [5.1, 3.4, 1.5, 0.2],\n",
       "       [5. , 3.5, 1.3, 0.3],\n",
       "       [4.5, 2.3, 1.3, 0.3],\n",
       "       [4.4, 3.2, 1.3, 0.2],\n",
       "       [5. , 3.5, 1.6, 0.6],\n",
       "       [5.1, 3.8, 1.9, 0.4],\n",
       "       [4.8, 3. , 1.4, 0.3],\n",
       "       [5.1, 3.8, 1.6, 0.2],\n",
       "       [4.6, 3.2, 1.4, 0.2],\n",
       "       [5.3, 3.7, 1.5, 0.2],\n",
       "       [5. , 3.3, 1.4, 0.2],\n",
       "       [7. , 3.2, 4.7, 1.4],\n",
       "       [6.4, 3.2, 4.5, 1.5],\n",
       "       [6.9, 3.1, 4.9, 1.5],\n",
       "       [5.5, 2.3, 4. , 1.3],\n",
       "       [6.5, 2.8, 4.6, 1.5],\n",
       "       [5.7, 2.8, 4.5, 1.3],\n",
       "       [6.3, 3.3, 4.7, 1.6],\n",
       "       [4.9, 2.4, 3.3, 1. ],\n",
       "       [6.6, 2.9, 4.6, 1.3],\n",
       "       [5.2, 2.7, 3.9, 1.4],\n",
       "       [5. , 2. , 3.5, 1. ],\n",
       "       [5.9, 3. , 4.2, 1.5],\n",
       "       [6. , 2.2, 4. , 1. ],\n",
       "       [6.1, 2.9, 4.7, 1.4],\n",
       "       [5.6, 2.9, 3.6, 1.3],\n",
       "       [6.7, 3.1, 4.4, 1.4],\n",
       "       [5.6, 3. , 4.5, 1.5],\n",
       "       [5.8, 2.7, 4.1, 1. ],\n",
       "       [6.2, 2.2, 4.5, 1.5],\n",
       "       [5.6, 2.5, 3.9, 1.1],\n",
       "       [5.9, 3.2, 4.8, 1.8],\n",
       "       [6.1, 2.8, 4. , 1.3],\n",
       "       [6.3, 2.5, 4.9, 1.5],\n",
       "       [6.1, 2.8, 4.7, 1.2],\n",
       "       [6.4, 2.9, 4.3, 1.3],\n",
       "       [6.6, 3. , 4.4, 1.4],\n",
       "       [6.8, 2.8, 4.8, 1.4],\n",
       "       [6.7, 3. , 5. , 1.7],\n",
       "       [6. , 2.9, 4.5, 1.5],\n",
       "       [5.7, 2.6, 3.5, 1. ],\n",
       "       [5.5, 2.4, 3.8, 1.1],\n",
       "       [5.5, 2.4, 3.7, 1. ],\n",
       "       [5.8, 2.7, 3.9, 1.2],\n",
       "       [6. , 2.7, 5.1, 1.6],\n",
       "       [5.4, 3. , 4.5, 1.5],\n",
       "       [6. , 3.4, 4.5, 1.6],\n",
       "       [6.7, 3.1, 4.7, 1.5],\n",
       "       [6.3, 2.3, 4.4, 1.3],\n",
       "       [5.6, 3. , 4.1, 1.3],\n",
       "       [5.5, 2.5, 4. , 1.3],\n",
       "       [5.5, 2.6, 4.4, 1.2],\n",
       "       [6.1, 3. , 4.6, 1.4],\n",
       "       [5.8, 2.6, 4. , 1.2],\n",
       "       [5. , 2.3, 3.3, 1. ],\n",
       "       [5.6, 2.7, 4.2, 1.3],\n",
       "       [5.7, 3. , 4.2, 1.2],\n",
       "       [5.7, 2.9, 4.2, 1.3],\n",
       "       [6.2, 2.9, 4.3, 1.3],\n",
       "       [5.1, 2.5, 3. , 1.1],\n",
       "       [5.7, 2.8, 4.1, 1.3],\n",
       "       [6.3, 3.3, 6. , 2.5],\n",
       "       [5.8, 2.7, 5.1, 1.9],\n",
       "       [7.1, 3. , 5.9, 2.1],\n",
       "       [6.3, 2.9, 5.6, 1.8],\n",
       "       [6.5, 3. , 5.8, 2.2],\n",
       "       [7.6, 3. , 6.6, 2.1],\n",
       "       [4.9, 2.5, 4.5, 1.7],\n",
       "       [7.3, 2.9, 6.3, 1.8],\n",
       "       [6.7, 2.5, 5.8, 1.8],\n",
       "       [7.2, 3.6, 6.1, 2.5],\n",
       "       [6.5, 3.2, 5.1, 2. ],\n",
       "       [6.4, 2.7, 5.3, 1.9],\n",
       "       [6.8, 3. , 5.5, 2.1],\n",
       "       [5.7, 2.5, 5. , 2. ],\n",
       "       [5.8, 2.8, 5.1, 2.4],\n",
       "       [6.4, 3.2, 5.3, 2.3],\n",
       "       [6.5, 3. , 5.5, 1.8],\n",
       "       [7.7, 3.8, 6.7, 2.2],\n",
       "       [7.7, 2.6, 6.9, 2.3],\n",
       "       [6. , 2.2, 5. , 1.5],\n",
       "       [6.9, 3.2, 5.7, 2.3],\n",
       "       [5.6, 2.8, 4.9, 2. ],\n",
       "       [7.7, 2.8, 6.7, 2. ],\n",
       "       [6.3, 2.7, 4.9, 1.8],\n",
       "       [6.7, 3.3, 5.7, 2.1],\n",
       "       [7.2, 3.2, 6. , 1.8],\n",
       "       [6.2, 2.8, 4.8, 1.8],\n",
       "       [6.1, 3. , 4.9, 1.8],\n",
       "       [6.4, 2.8, 5.6, 2.1],\n",
       "       [7.2, 3. , 5.8, 1.6],\n",
       "       [7.4, 2.8, 6.1, 1.9],\n",
       "       [7.9, 3.8, 6.4, 2. ],\n",
       "       [6.4, 2.8, 5.6, 2.2],\n",
       "       [6.3, 2.8, 5.1, 1.5],\n",
       "       [6.1, 2.6, 5.6, 1.4],\n",
       "       [7.7, 3. , 6.1, 2.3],\n",
       "       [6.3, 3.4, 5.6, 2.4],\n",
       "       [6.4, 3.1, 5.5, 1.8],\n",
       "       [6. , 3. , 4.8, 1.8],\n",
       "       [6.9, 3.1, 5.4, 2.1],\n",
       "       [6.7, 3.1, 5.6, 2.4],\n",
       "       [6.9, 3.1, 5.1, 2.3],\n",
       "       [5.8, 2.7, 5.1, 1.9],\n",
       "       [6.8, 3.2, 5.9, 2.3],\n",
       "       [6.7, 3.3, 5.7, 2.5],\n",
       "       [6.7, 3. , 5.2, 2.3],\n",
       "       [6.3, 2.5, 5. , 1.9],\n",
       "       [6.5, 3. , 5.2, 2. ],\n",
       "       [6.2, 3.4, 5.4, 2.3],\n",
       "       [5.9, 3. , 5.1, 1.8]])"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(150, 4)"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
       "       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
       "       0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n",
       "       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n",
       "       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\n",
       "       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\n",
       "       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(150,)"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Wir splitten die Daten in Trainings- und Testdaten\n",
    "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # mischt das Dataset automatisch. Ansonsten hätten wir viel weniger mit Label 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[4.6, 3.6, 1. , 0.2],\n",
       "       [5.7, 4.4, 1.5, 0.4],\n",
       "       [6.7, 3.1, 4.4, 1.4],\n",
       "       [4.8, 3.4, 1.6, 0.2],\n",
       "       [4.4, 3.2, 1.3, 0.2],\n",
       "       [6.3, 2.5, 5. , 1.9],\n",
       "       [6.4, 3.2, 4.5, 1.5],\n",
       "       [5.2, 3.5, 1.5, 0.2],\n",
       "       [5. , 3.6, 1.4, 0.2],\n",
       "       [5.2, 4.1, 1.5, 0.1],\n",
       "       [5.8, 2.7, 5.1, 1.9],\n",
       "       [6. , 3.4, 4.5, 1.6],\n",
       "       [6.7, 3.1, 4.7, 1.5],\n",
       "       [5.4, 3.9, 1.3, 0.4],\n",
       "       [5.4, 3.7, 1.5, 0.2],\n",
       "       [5.5, 2.4, 3.7, 1. ],\n",
       "       [6.3, 2.8, 5.1, 1.5],\n",
       "       [6.4, 3.1, 5.5, 1.8],\n",
       "       [6.6, 3. , 4.4, 1.4],\n",
       "       [7.2, 3.6, 6.1, 2.5],\n",
       "       [5.7, 2.9, 4.2, 1.3],\n",
       "       [7.6, 3. , 6.6, 2.1],\n",
       "       [5.6, 3. , 4.5, 1.5],\n",
       "       [5.1, 3.5, 1.4, 0.2],\n",
       "       [7.7, 2.8, 6.7, 2. ],\n",
       "       [5.8, 2.7, 4.1, 1. ],\n",
       "       [5.2, 3.4, 1.4, 0.2],\n",
       "       [5. , 3.5, 1.3, 0.3],\n",
       "       [5.1, 3.8, 1.9, 0.4],\n",
       "       [5. , 2. , 3.5, 1. ],\n",
       "       [6.3, 2.7, 4.9, 1.8],\n",
       "       [4.8, 3.4, 1.9, 0.2],\n",
       "       [5. , 3. , 1.6, 0.2],\n",
       "       [5.1, 3.3, 1.7, 0.5],\n",
       "       [5.6, 2.7, 4.2, 1.3],\n",
       "       [5.1, 3.4, 1.5, 0.2],\n",
       "       [5.7, 3. , 4.2, 1.2],\n",
       "       [7.7, 3.8, 6.7, 2.2],\n",
       "       [4.6, 3.2, 1.4, 0.2],\n",
       "       [6.2, 2.9, 4.3, 1.3],\n",
       "       [5.7, 2.5, 5. , 2. ],\n",
       "       [5.5, 4.2, 1.4, 0.2],\n",
       "       [6. , 3. , 4.8, 1.8],\n",
       "       [5.8, 2.7, 5.1, 1.9],\n",
       "       [6. , 2.2, 4. , 1. ],\n",
       "       [5.4, 3. , 4.5, 1.5],\n",
       "       [6.2, 3.4, 5.4, 2.3],\n",
       "       [5.5, 2.3, 4. , 1.3],\n",
       "       [5.4, 3.9, 1.7, 0.4],\n",
       "       [5. , 2.3, 3.3, 1. ],\n",
       "       [6.4, 2.7, 5.3, 1.9],\n",
       "       [5. , 3.3, 1.4, 0.2],\n",
       "       [5. , 3.2, 1.2, 0.2],\n",
       "       [5.5, 2.4, 3.8, 1.1],\n",
       "       [6.7, 3. , 5. , 1.7],\n",
       "       [4.9, 3.1, 1.5, 0.2],\n",
       "       [5.8, 2.8, 5.1, 2.4],\n",
       "       [5. , 3.4, 1.5, 0.2],\n",
       "       [5. , 3.5, 1.6, 0.6],\n",
       "       [5.9, 3.2, 4.8, 1.8],\n",
       "       [5.1, 2.5, 3. , 1.1],\n",
       "       [6.9, 3.2, 5.7, 2.3],\n",
       "       [6. , 2.7, 5.1, 1.6],\n",
       "       [6.1, 2.6, 5.6, 1.4],\n",
       "       [7.7, 3. , 6.1, 2.3],\n",
       "       [5.5, 2.5, 4. , 1.3],\n",
       "       [4.4, 2.9, 1.4, 0.2],\n",
       "       [4.3, 3. , 1.1, 0.1],\n",
       "       [6. , 2.2, 5. , 1.5],\n",
       "       [7.2, 3.2, 6. , 1.8],\n",
       "       [4.6, 3.1, 1.5, 0.2],\n",
       "       [5.1, 3.5, 1.4, 0.3],\n",
       "       [4.4, 3. , 1.3, 0.2],\n",
       "       [6.3, 2.5, 4.9, 1.5],\n",
       "       [6.3, 3.4, 5.6, 2.4],\n",
       "       [4.6, 3.4, 1.4, 0.3],\n",
       "       [6.8, 3. , 5.5, 2.1],\n",
       "       [6.3, 3.3, 6. , 2.5],\n",
       "       [4.7, 3.2, 1.3, 0.2],\n",
       "       [6.1, 2.9, 4.7, 1.4],\n",
       "       [6.5, 2.8, 4.6, 1.5],\n",
       "       [6.2, 2.8, 4.8, 1.8],\n",
       "       [7. , 3.2, 4.7, 1.4],\n",
       "       [6.4, 3.2, 5.3, 2.3],\n",
       "       [5.1, 3.8, 1.6, 0.2],\n",
       "       [6.9, 3.1, 5.4, 2.1],\n",
       "       [5.9, 3. , 4.2, 1.5],\n",
       "       [6.5, 3. , 5.2, 2. ],\n",
       "       [5.7, 2.6, 3.5, 1. ],\n",
       "       [5.2, 2.7, 3.9, 1.4],\n",
       "       [6.1, 3. , 4.6, 1.4],\n",
       "       [4.5, 2.3, 1.3, 0.3],\n",
       "       [6.6, 2.9, 4.6, 1.3],\n",
       "       [5.5, 2.6, 4.4, 1.2],\n",
       "       [5.3, 3.7, 1.5, 0.2],\n",
       "       [5.6, 3. , 4.1, 1.3],\n",
       "       [7.3, 2.9, 6.3, 1.8],\n",
       "       [6.7, 3.3, 5.7, 2.1],\n",
       "       [5.1, 3.7, 1.5, 0.4],\n",
       "       [4.9, 2.4, 3.3, 1. ],\n",
       "       [6.7, 3.3, 5.7, 2.5],\n",
       "       [7.2, 3. , 5.8, 1.6],\n",
       "       [4.9, 3.6, 1.4, 0.1],\n",
       "       [6.7, 3.1, 5.6, 2.4],\n",
       "       [4.9, 3. , 1.4, 0.2],\n",
       "       [6.9, 3.1, 4.9, 1.5],\n",
       "       [7.4, 2.8, 6.1, 1.9],\n",
       "       [6.3, 2.9, 5.6, 1.8],\n",
       "       [5.7, 2.8, 4.1, 1.3],\n",
       "       [6.5, 3. , 5.5, 1.8],\n",
       "       [6.3, 2.3, 4.4, 1.3],\n",
       "       [6.4, 2.9, 4.3, 1.3],\n",
       "       [5.6, 2.8, 4.9, 2. ],\n",
       "       [5.9, 3. , 5.1, 1.8],\n",
       "       [5.4, 3.4, 1.7, 0.2],\n",
       "       [6.1, 2.8, 4. , 1.3],\n",
       "       [4.9, 2.5, 4.5, 1.7],\n",
       "       [5.8, 4. , 1.2, 0.2],\n",
       "       [5.8, 2.6, 4. , 1.2],\n",
       "       [7.1, 3. , 5.9, 2.1]])"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X_train"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(120, 4)"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X_train.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(30, 4)"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X_test.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(120,)"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y_train.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Nun stellt sich nach wie vor die Frage, wie wir nun bewerten können, ob unser Modell gut performt.\n",
    "\n",
    "Dies ist, wie bereits besprochen, für eine Regression ziemlich einfach. Für kompliziertere Modelle (und für eine objektive Beurteilung von einfachen Modellen) führen wir jetzt ein paar Metriken ein, welche diese Performance messen."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Metriken zur Evaluierung"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Nun besprechen wir verschiedene **Metriken**, welche verwendet werden können um die **Perfomance** von **Regressions- und Klassifikationsmodellen** zu **bewerten**."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Regressionsmetriken"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Die üblichste Möglichkeit, ein Regressionsmodell zu beurteilen ist es, den **Mean Squared Error** (*MSE*) zu berechnen."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![Evaluation_Regression](../resources/2_Regression_Evaluation.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Dazu nehmen wir das trainierte Modell (nur auf den Trainingsdaten trainiert) und berechnen für jeden Punkt in den Testdaten die quadratische Abweichung zum Wert, der vorhergesagt wurde. Abschließend berechnen wir noch den Mittelwert dieser Abweichung.\n",
    "\n",
    "Die Formel ist also\n",
    "\n",
    "\\begin{equation*}\n",
    "    \\text{MSE} = \\frac{1}{n}\\sum_{i=1}^{n}(y_{\\text{true}}-y_{\\text{predicted}})^2\n",
    "\\end{equation*}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Idealerweise ist dieser Fehler natürlich klein!\n",
    "\n",
    "**Wichtig:** Es darf kein Testpunkt in den Trainingsdaten sein und umgekehrt. Ansonsten ist der berechnete Wert ohne Aussagekraft!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Metriken für die Klassifizierung"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Im Fall von 2 Klassen erstellt unser Modell also für jeden Datenpunkt einen Output (Vorhersage) von entweder $0$ oder $1$. In unserem Testset haben wir das echte (true) Label, somit können wir einfach zählen, wie oft die Prediciton von unserem Modell mit jener vom echten Dataset zusammen stimmt. Dies ist eine Möglichkeit zur Evaluierung und nennt sich **Accuracy**."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\\begin{equation*}\n",
    "\\text{Accuracy} = \\frac{\\text{Anzahl der korrekten Vorhersagen}}{\\text{Anzahl der Datenpunkte im Testset}}.\n",
    "\\end{equation*} \n",
    "\n",
    "Ein perfekter Klassifizierer hat also eine Accuracy von $1$, also $100\\%$ richtige Vorhersagen."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Es gibt auch noch die **Balanced Accuracy**, welche die Klassenverteilung miteinbezieht, diese wird aber jetzt nicht mathematisch Beschrieben. Anwendbar ist sie in Python sowieso ziemlich einfach via `scikit-learn`!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Es gibt aber noch weitere Metriken, welche für Klassifizierung verwendet werden können.\n",
    "\n",
    "Ein Grund für die große Auswahl ist, weil man je nach **Anwendungsfall** auf **andere Eigenschaften** des Modells Wert legt!\n",
    "\n",
    "Dafür betrachten wir nun zuerst die sogenannte **Confusion Matrix**!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Confusion Matrix"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Eine **Confusion Matrix** zeigt die Performance eines Klassifikationsmodells, indem sie echte und vorhergesagte Klassen vergleicht.  \n",
    "Beispiel für eine 2-Klassen-Klassifikation:  \n",
    "\n",
    "|                  | **Positive Vorhersage** | **Negative Vorhersage** |\n",
    "|------------------|--------------------------|--------------------------|\n",
    "| **Positive Fälle** | **True Positive (TP)**  | **False Negative (FN)**  |\n",
    "| **Negative Fälle** | **False Positive (FP)** | **True Negative (TN)**   |\n",
    "\n",
    "- **True Positive (TP):** Modell sagt \"positiv\" und es ist korrekt.  \n",
    "- **False Positive (FP):** Modell sagt \"positiv\", aber es ist falsch.  \n",
    "- **True Negative (TN):** Modell sagt \"negativ\" und es ist korrekt.  \n",
    "- **False Negative (FN):** Modell sagt \"negativ\", aber es ist falsch."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In diesem Fall bedeuten positiv und negativ zum Beispiel Klasse $1$ und Klasse $0$."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Mit diesen können wir nun **weitere Metriken** zur Bewertung von Klassifikationsmodellen definieren!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\\begin{equation*}\n",
    "\\text{Precision} = \\frac{\\text{TP}}{\\text{TP} + \\text{FP}}.\n",
    "\\end{equation*} \n",
    "\n",
    "Die **Precision** gewichtet Falsch-Positive (FP) Fälle auch mit ein. Dieser Wert soll hoch sein, wenn wir Falsch-Positive Vorhersagen problematisch sind (zum Beispiel bei Krankheitstest (Corona))."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\\begin{equation*}\n",
    "\\text{Recall} = \\frac{\\text{TP}}{\\text{TP} + \\text{FN}}.\n",
    "\\end{equation*} "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Der **Recall** wird auch **True Positive Rate** (*TPR*) genannt. Dementsprechend gibt es auch eine **True Negative Rate** (*TNR*). "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\\begin{equation*}\n",
    "\\text{TNR} = \\frac{\\text{TN}}{\\text{TN} + \\text{FP}}.\n",
    "\\end{equation*} "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Eine weitere Metrik ist der sogenannte $F1$-Score:\n",
    "\\begin{equation*}\n",
    "\\text{F1-Score} = 2\\cdot \\frac{\\text{Precision}\\cdot \\text{Recall}}{\\text{Precision} + \\text{Recall}}.\n",
    "\\end{equation*} "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Wichtig:** Die vorigen Metriken funktionieren nur für die binäre Klassifikation (sprich $0$ oder $1$ Klassifizierung). Für Multiclass Klassifizierung verwendet man deswegen hauptsächlich die Accuracy oder ändert die genannten Metriken leicht ab!\n",
    "\n",
    "Dies gilt natürlich auch für die Confusion Matrix im Allgemeinen!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Confusion Matrix für Multiclass Klassifikation"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![Multiclass Confusion Matrix](../resources/2_Confusion_Matrix_Multiclass.png)\n",
    "\n",
    "(from AI Vis 2024WS Prof. Marc Streit)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Nun muss bei einer Falschklassifikation unterschieden werden, welche Klasse anstelle der richtigen Klasse vorhergesagt wurde!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Evaluierung in Python"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Insgesamt bietet auch hier `scikit-learn` viele praktische Funktionen, sodass sehr wenig ausprogrammiert werden muss."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.metrics import mean_squared_error, accuracy_score, precision_score, recall_score, f1_score, confusion_matrix"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Wir werden nun unser erstes Modell trainieren!🥳\n",
    "\n",
    "Wir betrachten jetzt nur Klassifikation. Außerdem geht es noch nicht um das Modell selber, sondern um die Evaluierung im Anschluss.\n",
    "\n",
    "Das Trainieren der Modelle passiert nächste Woche!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.neighbors import KNeighborsClassifier # Laden der Modellklasse"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Wir verenden das wine dataset\n",
    "X, y = load_wine(return_X_y=True, as_frame=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1.423e+01, 1.710e+00, 2.430e+00, ..., 1.040e+00, 3.920e+00,\n",
       "        1.065e+03],\n",
       "       [1.320e+01, 1.780e+00, 2.140e+00, ..., 1.050e+00, 3.400e+00,\n",
       "        1.050e+03],\n",
       "       [1.316e+01, 2.360e+00, 2.670e+00, ..., 1.030e+00, 3.170e+00,\n",
       "        1.185e+03],\n",
       "       ...,\n",
       "       [1.327e+01, 4.280e+00, 2.260e+00, ..., 5.900e-01, 1.560e+00,\n",
       "        8.350e+02],\n",
       "       [1.317e+01, 2.590e+00, 2.370e+00, ..., 6.000e-01, 1.620e+00,\n",
       "        8.400e+02],\n",
       "       [1.413e+01, 4.100e+00, 2.740e+00, ..., 6.100e-01, 1.600e+00,\n",
       "        5.600e+02]])"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(178, 13)"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
       "       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
       "       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1,\n",
       "       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n",
       "       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n",
       "       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,\n",
       "       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\n",
       "       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\n",
       "       2, 2])"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(178,)"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "number_of_neighbors = 7\n",
    "\n",
    "knn = KNeighborsClassifier(n_neighbors=number_of_neighbors) # Instanziieren des Modells\n",
    "trained_model = knn.fit(X_train, y_train) # Trainieren des Modells"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Model Evaluierung\n",
    "\n",
    "y_pred = trained_model.predict(X_test) # Vorhersage auf den Testdaten"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 0, 2, 0, 1, 0, 2, 0, 2, 0, 2, 2, 0, 1, 0, 1, 1, 2, 0, 1, 0, 1,\n",
       "       2, 1, 1, 1, 1, 2, 1, 0, 0, 1, 2, 0, 0, 0])"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y_pred"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 0, 2, 0, 1, 0, 1, 2, 1, 2, 0, 2, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1,\n",
       "       1, 2, 2, 2, 1, 1, 1, 0, 0, 1, 2, 0, 0, 0])"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y_test"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "accuracy = accuracy_score(y_test, y_pred)\n",
    "conf_matrix = confusion_matrix(y_test, y_pred)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Die Accuracy beträgt: 0.6944444444444444\n"
     ]
    }
   ],
   "source": [
    "print(f\"Die Accuracy beträgt: {accuracy}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Die Confusion Matrix lautet:\n",
      "[[13  0  1]\n",
      " [ 0  9  5]\n",
      " [ 2  3  3]]\n"
     ]
    }
   ],
   "source": [
    "print(f\"Die Confusion Matrix lautet:\\n{conf_matrix}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Wir können nun auch die Confusion Matrix mit einer Heatmap visualisieren!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Axes: >"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 11796 characters]",
      "text/plain": [
       "<Figure size 640x480 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "sns.heatmap(conf_matrix, annot=True, cmap='Blues')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Vielleicht schafft ein anderes Modell (oder andere Hyperparameter) eine bessere Performance?\n",
    "\n",
    "Wie sieht es mit den Iris Daten aus?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Tipps and Tricks"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Falls ein Modell schlecht performt, kann man sich folgende Dinge überlegen:\n",
    "* Daten normalisieren (Beispiel k-nearest-neighbor)\n",
    "* Mehr Daten beschaffen (eventuell Data Augmentation möglich)\n",
    "* **Model kleiner** machen, indem manche Features nicht verwendet werden (hilft auch oft gegen Overfitting), zum Beispiel mittels Korrelationsmatrix, um zu sehen, welche Features mehr oder weniger das gleiche Verhalten haben.\n",
    "\n",
    "Letzteren Punkt sehen wir uns jetzt nochmal mit Python an!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Axes: >"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 144140 characters]",
      "text/plain": [
       "<Figure size 640x480 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Correlation Matrix\n",
    "\n",
    "correlation_matrix = np.corrcoef(X_train, rowvar=False) # Berechnen den Korrelationskoeffizienten (wie in den Visualisierungsunterlagen besprochen)\n",
    "sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Hohe Werte können nun entfernt werden und das Model wird kleiner, somit auch schneller mit vergleichsweise wenig (oder keinem) Verlust in der Performance. Oft verbessert das die Perfomance am Testset sogar (Overfitting)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Aufgabe"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* Verwende das Dataset, welches für die bisherigen Gruppenarbeiten bereits verwendet wurde und schaue dir die Größe an\n",
    "* Versuche das Dataset mit Hilfe von `sklearn` in einen Train- und in einen Testteil zu unterteilen.\n",
    "* Funktioniert es auch mit Dataframes?\n",
    "* Wie kann ich aus einem bestehenden Dataframe das Label extrahieren?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "dsai",
   "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.9.18"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
