{
 "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;\">Unsupervised ML Modelle: Dimensionsreduzierung (Downprojection)</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": [
    "## Downprojection von Daten"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Die **Downprojection** (oder Dimensionalitätsreduktion) ist ein Verfahren, um hochdimensionale Daten in eine niedrigere Dimension zu verwandeln (zbsp durch eine Projektion), während wichtige Strukturen und Muster erhalten bleiben (sollen). Dies erleichtert Visualisierungen, reduziert Speicherbedarf und verbessert oft die Effizienz von Machine-Learning-Algorithmen."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![Dim_Reduction_Cubes](../resources/Dim_Reduction_Cubes.jpeg)\n",
    "\n",
    "(von https://www.sc-best-practices.org/preprocessing_visualization/dimensionality_reduction.html)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![Dim_Reduction_Points](../resources/Dim_Reduction_Points.png)\n",
    "\n",
    "(von https://blog.roboflow.com/what-is-dimensionality-reduction/)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Wir werden uns nun die beiden wichtigsten Methoden ansehen: **Principal Component Analysis (PCA)** und **t-Distributed Stochastic Neighbour Embedding (t-SNE)**. Neben diesen beiden gibt es noch weitere Methoden, welche auch ihre eigenen Vorteile/Nachteile und Anwendungsfälle besitzen. Darunter gehören zum Beispiel *UMAP (Uniform Manifold Approximation and Projection)*, *MDS (Multidmensional Scaling)* und *LLE (Locally Linear Embedding)*."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Principal Component Analysis (PCA)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Die **Principal Component Analysis (PCA)** ist ein mathematisches Verfahren, das es uns möglich macht, die Dimension von Daten zu reduzieren. Einfach gesagt sucht man in *PCA* mehr oder weniger eine $n$-dimensionale \"Ansicht\" der Daten, bei der man möglichst viel sieht ($n$ ist für Visualisierungszwecke gleich 2). Sprich wir schauen uns an, in welche Richtungen die Daten besonders ausgebreitet sind und machen dies zu unseren neuen Achsen. Diese neuen Achsen nennen wir **Principal Components (Hauptkomponenten)**."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Info:** Wenn wir für $d$-dimensionale Daten eine $d$-dimensionale \"Ansicht\" suchen, dann bekommen wir die exakt gleichen Daten wieder zurück, jedoch haben jetzt das Koordinatensystem geändert."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Wichtig:** Die Daten werden beim verwenden von PCA nicht verändert, es wird nur das Koordinatensystem gedreht."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Info:** Wenn wir für $d$-dimensionale Daten zum Beispiel die beste \"Ansicht\" mit Dimension $2$ finden wollen, dann passiert dies, indem wir zuerst PCA anwenden, um $d$ neue Achsen zu bekommen. Anschließend wählen wir die ersten beiden Achsen aus."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Info:** Die neuen Richtungen, in welche sich die Daten am meisten Ausbreiten sind orthogonal (=rechtwinklig) zueinander."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Wichtig:** Bei jeder Dimensionsreduzierung gehen auch Daten verloren. Also die von uns betrachteten Methoden sind (normalerweise) nicht **verlustfrei**, auch *lossless* genannt."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![PCA_2_Plots](../resources/PCA_2_Datasets.png)\n",
    "\n",
    "(von Unsupervised Techniques, Prof. Hochreiter; JKU)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Beschreibung des Algorithmus"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Der *PCA* Algorithmus arbeitet folgende Schritt ab."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. **Zentrieren der Daten:** Subtrahiere den Mittelwert jeder Dimension. Somit ist der Mittelwert des Datasets $0$ in jeder Dimension.\n",
    "2. **Bestimmen der Principal Components:** Bestimme die Richtungen/Achsen, in welche die Daten sich am meisten Ausbreiten und ordne diese absteigend.\n",
    "3. **Hauptkomponentenauswahl:** Wähle die wichtigsten $n$ Richtungen (somit die ersten $n$ Richtungen der Daten mit neuem Koordinatensystem) aus.\n",
    "4. **Transformation:** Projiziere die Daten auf diese Richtungen."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Infos:** Der Beitrag pro Richtung zu einem Sample nimmt mit jeder Richtung ab, sprich die letzten Richtungen tragen nur mehr ganz wenig zum Datenpunkt bei im Vergleich zu den anderen Datenpunkten (siehe Referat: Kompression von Daten)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Hyperparameter von PCA"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* **Anzahl der Hauptkomponenten:** Entscheidet, wie viele Dimensionen behalten werden. Kann wie vorher beschrieben auch gleich viele wie vorher sein, dies bedeutet, dass wir nur das Koordinatensystem ändern."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Vorteile und Nachteile von PCA"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Vorteile:**\n",
    "* Sehr schnell und effizient für große Datensätze\n",
    "* Kann auch zur Datenkompression verwendet werden (Beitrag der einzelnen zu einem Datenpunkt absteigend)\n",
    "* Kann auch verwendet werden, um die Anzahl der Features für ein Model zu verringern. Bsp: Statt 100 Features werden nur 10 Eingangsvariablen (*wichtig:* Hier sind mehrere Features \"vermischt\"!)\n",
    "\n",
    "**Nachteile:**\n",
    "* Nur für lineare Zusammenhänge geeignet\n",
    "* Die neuen Achsen können schwer interpretierbar sein\n",
    "* Variablen müssen standardisiert werden, da sonst Achsen mit großer Skalierung dominieren"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## PCA in Python"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "import pandas as pd\n",
    "import seaborn as sns\n",
    "from sklearn.decomposition import PCA\n",
    "from sklearn.datasets import load_wine, load_iris\n",
    "from sklearn.preprocessing import StandardScaler"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "data = load_iris()\n",
    "X = data.data\n",
    "y = data.target"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "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": 4,
   "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": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "X = StandardScaler().fit_transform(X)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 344548 characters]",
      "text/plain": [
       "<Figure size 1058.88x1000 with 20 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Pairplot\n",
    "\n",
    "df = pd.DataFrame(X, columns=data.feature_names)\n",
    "df['Target'] = data.target\n",
    "\n",
    "sns.pairplot(df, hue='Target')\n",
    "plt.suptitle('Pairplot')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Anwenden von PCA\n",
    "pca = PCA(n_components=2)\n",
    "X_pca = pca.fit_transform(X)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "df_pca = pd.DataFrame(X_pca, columns=['PC1', 'PC2'])\n",
    "df_pca['Target'] = y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 57576 characters]",
      "text/plain": [
       "<Figure size 800x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(8, 6))\n",
    "sns.scatterplot(x='PC1', y='PC2', hue=df_pca['Target'], palette='viridis', data=df_pca)\n",
    "plt.title(f'PCA Visualization of the Dataset')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Hinzufügen eines neuen Datenpunktes in PCA"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Hat man nun einen neuen Datenpunkt, so kann dieser auch ganz einfach downprojected werden.\n",
    "\n",
    "Dafür muss $\\ldots$\n",
    "* $\\ldots$ der Datenpunkt die die gleiche Anzahl der Features haben wie die Datenpunkte im Dataset\n",
    "* $\\ldots$ der Datenpunkt auf die gelernten *Principal Components* projeziert werden\n",
    "\n",
    "In Python funktioniert dies recht einfach"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "# hinzufügen von einem neuen Punkt in PCA\n",
    "new_point = [[-2, 0, 1.5, 0.5]]\t# 4 features (funktioniert also für Iris dataset)\n",
    "new_point_pca = pca.transform(new_point)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0.11091608, -0.68462682]])"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "new_point_pca"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## t-Distributed Stochastic Neighbour Embedding (t-SNE)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**t-SNE** ist ein Algorithmus zur Reduktion der Dimensionalität, ähnlich wie PCA, aber mit einem anderen Ansatz. Während PCA versucht, die gesamte Struktur der Daten zu erhalten, fokussiert sich t-SNE darauf, die lokalen Zusammenhänge zwischen Datenpunkten beizubehalten. Das bedeutet, dass Punkte, die in der hohen Dimension nah beieinander liegen, auch in der niedrigeren Dimension (z. B. 2d oder 3d) nah beieinander bleiben sollen. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![tSNE_Example](../resources/tSNE_Example.png)\n",
    "\n",
    "(von https://rpubs.com/marwahsi/tnse)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Beschreibung des Algorithmus"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**1. Ähnlichkeit in hoher Dimension berechnen**  \n",
    "t-SNE beginnt damit, Ähnlichkeiten zwischen allen Punkten im hochdimensionalen Raum zu berechnen. Es versucht herauszufinden, welche Punkte „Nachbarn“ sind, also welche Punkte in einem bestimmten Umkreis besonders nahe an einem anderen Punkt liegen.  \n",
    "\n",
    "**2. Punkte in niedriger Dimension platzieren**  \n",
    "Dann erzeugt t-SNE eine zufällige Anordnung der Punkte in einem niedrigdimensionalen Raum (zum Beispiel 2d). Anschließend beginnt der eigentliche Optimierungsprozess:  \n",
    "\n",
    "**3. Anordnung verbessern**  \n",
    "t-SNE vergleicht die Abstände der Punkte in der niedrigen Dimension mit denen in der hohen Dimension. Falls zwei Punkte in der niedrigen Dimension zu weit voneinander entfernt sind, obwohl sie eigentlich Nachbarn sein sollten, werden sie näher zusammengezogen. Falls zwei Punkte zu nah sind, obwohl sie keine echten Nachbarn waren, werden sie auseinander gedrückt. Das passiert iterativ, bis eine möglichst gute Darstellung entsteht. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Info:** Nachdem dieser Vorgang iterativ ist, bricht der Algorithmus nach den gegebenen Iterationen ab. Die Anzahl der Iterationen kann im Konstruktor mitgegeben werden."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Hyperparameter von t-SNE"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. **Perplexity:**\n",
    "    * Dieser Wert bestimmt, wie viele Nachbarn t-SNE für jeden Punkt betrachtet.  \n",
    "    * Eine niedrige Perplexity (z. B. 5) fokussiert stark auf lokale Strukturen. Eine hohe Perplexity (z. B. 50) betrachtet größere Zusammenhänge.  \n",
    "    * Es gibt leider keinen Wert, der immer funktioniert $\\rightarrow$ probieren!\n",
    "\n",
    "2. **Anzahl der Iterationen**\n",
    "    * Je länger man t-SNE laufen lässt, desto besser wird die Struktur.\n",
    "    * Mehr Iterationen benötigen aber auch mehr Rechenleistung und dauern dementsprechend auch länger "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Vorteile und Nachteile von t-SNE"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Vorteile:**\n",
    "* Besonders gut für Datenvisualisierung geeignet\n",
    "* Erhält lokale Strukturen sehr gut\n",
    "* Kann komplexe nicht-lineare Muster erkennen, zum Beispiel welche, die PCA nicht erkennen kann\n",
    "\n",
    "**Nachteile:**\n",
    "* Sehr rechenintensiv im Vergleich zu PCA\n",
    "* Keine eindeutige Rekonstruktion der Daten möglich\n",
    "* Sensitiv gegenüber der Wahl der Hyperparameter\n",
    "* Keine neuen Daten können hinzugefügt werden"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### t-SNE in Python"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "import pandas as pd\n",
    "import seaborn as sns\n",
    "from sklearn.manifold import TSNE\n",
    "from sklearn.datasets import load_wine, load_iris\n",
    "from sklearn.preprocessing import StandardScaler"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "data = load_iris()\n",
    "X = data.data\n",
    "y = data.target"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "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": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "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": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "X = StandardScaler().fit_transform(X)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 344548 characters]",
      "text/plain": [
       "<Figure size 1058.88x1000 with 20 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Pairplot\n",
    "\n",
    "df = pd.DataFrame(X, columns=data.feature_names)\n",
    "df['Target'] = data.target\n",
    "\n",
    "sns.pairplot(df, hue='Target')\n",
    "plt.suptitle('Pairplot')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Anwenden von t-SNE\n",
    "tsne = TSNE(n_components=2, random_state=42, perplexity=100) # Standard Wert für Perplexity ist 30\n",
    "X_tsne = tsne.fit_transform(X)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "df_tsne = pd.DataFrame(X_tsne, columns=['TSNE1', 'TSNE2'])\n",
    "df_tsne['Target'] = y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 59824 characters]",
      "text/plain": [
       "<Figure size 800x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(8, 6))\n",
    "sns.scatterplot(x='TSNE1', y='TSNE2', hue=df_tsne['Target'], palette='viridis', data=df_tsne)\n",
    "plt.title(f't-SNE Visualization of the Dataset')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Tipps und Tricks zur Dimensions-Reduzierung"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* **PCA vor t-SNE:** Eine Voranwendung von PCA kann Rauschen reduzieren und t-SNE effizienter machen.\n",
    "* **Hyperparameter optimieren:** Die richtige Wahl der Perplexity in t-SNE kann entscheidend sein.\n",
    "* **Normalisieren/Standardisieren**: Vor allem für PCA sollen die einzelnen Features in der gleichen Größenordnung sein. Ist dies nicht der Fall, kann standardisieren helfen."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Weitere Methoden (kurzer Überblick)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* **UMAP (Uniform Manifold Approximation and Projection):** Eine moderne Alternative zu t-SNE, die schneller ist und oft besser zwischen globalen und lokalen Strukturen balanciert.\n",
    "* **MDS (Multidimensional Scaling):** Eine Technik, die Distanzen zwischen Punkten in eine niedrigere Dimension überträgt.\n",
    "* **LLE (Locally Linear Embedding):** Eine Methode zur Erhaltung lokaler Beziehungen zwischen Datenpunkten."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Aufgabe 1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Versuche die Aufgabe von letzer Woche zu lösen bzw. die Lösung zu verbessern, indem du zum Beispiel $\\ldots$\n",
    "* $\\ldots$ zuerst eine Dimensionsreduzierung anwedest um die Anzahl der Features zu reduzieren\n",
    "* $\\ldots$ danach Dimensionsreduzierung verwendest um die Ergebnisse zu visualisieren\n",
    "* $\\ldots$ nur Dimensionsreduzierungstechniken (auch vielleicht in Kombination -> welche Kombinationen machen zbsp keinen Sinn?) anwendest und dir ansiehst, welche Datenunkte sich ähnlich sein dürften."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Bisherige Aufgabe:**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* Verwende nun die folgenden Datasets und versuche die Aufgabenstellungen zu beantworten.\n",
    "* Lade dazu das Dataset mit den bekannten Methoden (Laden mit Hilfe von `pd.read_csv`)\n",
    "* Verwende für jede Aufgabe eigene Code-Zellen und dokumentiere für die verschiedenen Durchläufe die Ergebnisse\n",
    "\n",
    "\n",
    "1) HELP International konnte rund 10 Millionen Dollar aufbringen. Nun muss der Geschäftsführer der NRO entscheiden, wie er dieses Geld strategisch und effektiv einsetzen will. Der CEO muss also entscheiden, welche Länder die Hilfe am dringendsten benötigen. Ihre Aufgabe als Datenwissenschaftler besteht also darin, die Länder anhand einiger sozioökonomischer und gesundheitlicher Faktoren zu kategorisieren, die die Gesamtentwicklung des Landes bestimmen. Sie müssen also Länder vorschlagen, auf die sich der CEO am meisten konzentrieren soll.\n",
    "\n",
    "    *Dataset:* Country `country.csv` (verwendet von https://www.kaggle.com/datasets/rohan0301/unsupervised-learning-on-country-data?select=Country-data.csv)\n",
    "\n",
    "2) Nach der HTL-Karriere beschließen Sie, für eine gewisse Zeit ins Ausland zu gehen. Dabei wollen Sie in ein Land ziehen, in welchem die Länder besonders glücklich sind. Versuchen Sie nun das nachfolgende Dataset zu gruppieren und herauszufinden, in welchen Ländern (Gruppen) die Menschen ähnlich glücklick zu sein scheinen.\n",
    "\n",
    "    *Dataset:* Happiness 2017 `happiness_2017.csv` (verwendet von https://www.kaggle.com/datasets/unsdsn/world-happiness?select=2017.csv)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Aufgabe 2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Verwende Methoden zur Dimensionsreduzierung um die Performance eines Supervised Machine Learning Modells (Lineare/Logistische Regression, kNN, (Kernel) SVM, Decision Tree bzw. Random Forest) zu verbessern. Verwende dazu ein beliebiges Dataset von den Aufgaben der Supervised-Notebooks (idealerweise eines, bei dem die Performance nicht besonders gut war bisher). "
   ]
  },
  {
   "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
}
