{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "8698744b",
   "metadata": {},
   "source": [
    "Bibliotheken importieren"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "a1be2d54",
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "from pathlib import Path\n",
    "\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.preprocessing import StandardScaler\n",
    "from sklearn.metrics import accuracy_score, f1_score, roc_auc_score, confusion_matrix, classification_report\n",
    "\n",
    "import tensorflow as tf\n",
    "from tensorflow.keras import Input, layers, models, regularizers\n",
    "\n",
    "import joblib \n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9a2832a7",
   "metadata": {},
   "source": [
    "Daten laden"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "f2a8a12d",
   "metadata": {},
   "outputs": [],
   "source": [
    "data_path = Path(r\"~/data-paulusjafahrsimulator-gpu/new_datasets/50s_25Hz_dataset.parquet\") \n",
    "\n",
    "df = pd.read_parquet(path=data_path)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5192248c",
   "metadata": {},
   "source": [
    "Labels erstellen"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "05b15322",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Label distribution:\n",
      "label\n",
      "1    4750\n",
      "0    3484\n",
      "Name: count, dtype: int64\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/tmp/ipykernel_2528/3529185502.py:9: SettingWithCopyWarning: \n",
      "A value is trying to be set on a copy of a slice from a DataFrame.\n",
      "Try using .loc[row_indexer,col_indexer] = value instead\n",
      "\n",
      "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
      "  low_all[\"label\"] = 0\n"
     ]
    }
   ],
   "source": [
    "low_all = df[((df[\"PHASE\"] == \"baseline\") | \n",
    "              ((df[\"STUDY\"] == \"n-back\") & (df[\"PHASE\"] != \"baseline\") & (df[\"LEVEL\"].isin([1,4]))))] \n",
    "\n",
    "high_all = pd.concat([ \n",
    "    df[(df[\"STUDY\"]==\"n-back\") & (df[\"LEVEL\"].isin([2,3,5,6])) & (df[\"PHASE\"].isin([\"train\",\"test\"]))], \n",
    "    df[(df[\"STUDY\"]==\"k-drive\") & (df[\"PHASE\"]!=\"baseline\")] \n",
    "]) \n",
    "\n",
    "low_all[\"label\"] = 0 \n",
    "high_all[\"label\"] = 1 \n",
    "data = pd.concat([low_all, high_all], ignore_index=True).drop_duplicates() \n",
    "\n",
    "print(\"Label distribution:\") \n",
    "print(data[\"label\"].value_counts())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9b44f8a4",
   "metadata": {},
   "source": [
    "Feature-Auswahl"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "5c11e2fd",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['subjectID', 'start_time', 'STUDY', 'LEVEL', 'PHASE', 'FACE_AU01_mean', 'FACE_AU02_mean', 'FACE_AU04_mean', 'FACE_AU05_mean', 'FACE_AU06_mean', 'FACE_AU07_mean', 'FACE_AU09_mean', 'FACE_AU10_mean', 'FACE_AU11_mean', 'FACE_AU12_mean', 'FACE_AU14_mean', 'FACE_AU15_mean', 'FACE_AU17_mean', 'FACE_AU20_mean', 'FACE_AU23_mean', 'FACE_AU24_mean', 'FACE_AU25_mean', 'FACE_AU26_mean', 'FACE_AU28_mean', 'FACE_AU43_mean', 'Fix_count_short_66_150', 'Fix_count_medium_300_500', 'Fix_count_long_gt_1000', 'Fix_count_100', 'Fix_mean_duration', 'Fix_median_duration', 'Sac_count', 'Sac_mean_amp', 'Sac_mean_dur', 'Sac_median_dur', 'Blink_count', 'Blink_mean_dur', 'Blink_median_dur', 'Pupil_mean', 'Pupil_IPA', 'label']\n",
      "Gefundene FACE_AU-Spalten: ['FACE_AU01_mean', 'FACE_AU02_mean', 'FACE_AU04_mean', 'FACE_AU05_mean', 'FACE_AU06_mean', 'FACE_AU07_mean', 'FACE_AU09_mean', 'FACE_AU10_mean', 'FACE_AU11_mean', 'FACE_AU12_mean', 'FACE_AU14_mean', 'FACE_AU15_mean', 'FACE_AU17_mean', 'FACE_AU20_mean', 'FACE_AU23_mean', 'FACE_AU24_mean', 'FACE_AU25_mean', 'FACE_AU26_mean', 'FACE_AU28_mean', 'FACE_AU43_mean']\n"
     ]
    }
   ],
   "source": [
    "au_columns = [col for col in data.columns if col.lower().startswith(\"face\")] \n",
    "print(data.columns.tolist())\n",
    "\n",
    "print(\"Gefundene FACE_AU-Spalten:\", au_columns)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "52aaa568",
   "metadata": {},
   "source": [
    "Train-/Val- und Test-Split nach Subjects"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "78023e16",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(4116, 41) (1235, 41) (2883, 41)\n"
     ]
    }
   ],
   "source": [
    "subjects = np.random.permutation(data[\"subjectID\"].unique()) \n",
    "n = len(subjects) \n",
    "n_train = int(n*0.66) \n",
    "\n",
    "train_subjects = subjects[:n_train] \n",
    "test_subjects = subjects[n_train:] \n",
    "train_subs, val_subs = train_test_split(train_subjects, test_size=0.2, random_state=42) \n",
    "\n",
    "train_df = data[data.subjectID.isin(train_subs)] \n",
    "val_df = data[data.subjectID.isin(val_subs)] \n",
    "test_df = data[data.subjectID.isin(test_subjects)] \n",
    "\n",
    "print(train_df.shape, val_df.shape, test_df.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4fbd22c4",
   "metadata": {},
   "source": [
    "Normalisierung - StandardScaler global"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "13a6ec83",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Vorher (erste 5 Werte):      FACE_AU01_mean  FACE_AU02_mean  FACE_AU04_mean\n",
      "697        0.792161        0.804894        0.310528\n",
      "698        0.793914        0.806557        0.312750\n",
      "699        0.795915        0.803190        0.293604\n",
      "700        0.790821        0.797190        0.299714\n",
      "701        0.790045        0.793320        0.292109\n",
      "Nachher (erste 5 Werte):      FACE_AU01_mean  FACE_AU02_mean  FACE_AU04_mean\n",
      "697        0.679178        1.116911        1.874625\n",
      "698        0.709019        1.138696        1.913728\n",
      "699        0.743082        1.094597        1.576792\n",
      "700        0.656358        1.016024        1.684310\n",
      "701        0.643142        0.965348        1.550483\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 24580 characters]",
      "text/plain": [
       "<Figure size 1000x400 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "scaler = StandardScaler() \n",
    "scaler.fit(train_df[au_columns]) \n",
    "\n",
    "train_scaled = train_df.copy() \n",
    "val_scaled = val_df.copy() \n",
    "test_scaled = test_df.copy() \n",
    "\n",
    "train_scaled[au_columns] = scaler.transform(train_df[au_columns]) \n",
    "val_scaled[au_columns] = scaler.transform(val_df[au_columns]) \n",
    "test_scaled[au_columns] = scaler.transform(test_df[au_columns])\n",
    "\n",
    "#Normalisierung - Vorher-Nachher Vergleich\n",
    "print(\"Vorher (erste 5 Werte):\", train_df[au_columns].iloc[:5, :3])\n",
    "print(\"Nachher (erste 5 Werte):\", train_scaled[au_columns].iloc[:5, :3])\n",
    "\n",
    "#Histogramme - vor und nach Normalisierung\n",
    "col = au_columns[0]  # erste AU-Spalte\n",
    "plt.figure(figsize=(10,4))\n",
    "plt.subplot(1,2,1)\n",
    "train_df[col].hist(bins=30)\n",
    "plt.title(f\"Vorher: {col}\")\n",
    "\n",
    "plt.subplot(1,2,2)\n",
    "train_scaled[col].hist(bins=30)\n",
    "plt.title(f\"Nachher: {col}\")\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "367533dc",
   "metadata": {},
   "source": [
    "Datenvorbereitung für CNN "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e5c1c8ae",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "X_train Shape: (4116, 20, 1)\n",
      "X_val Shape: (1235, 20, 1)\n",
      "X_test Shape: (2883, 20, 1)\n",
      "Train Labels: [1741 2375]\n",
      "Val Labels: [524 711]\n",
      "Test Labels: [1219 1664]\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 20020 characters]",
      "text/plain": [
       "<Figure size 1000x400 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "X_train = train_scaled[au_columns].values[..., np.newaxis] \n",
    "y_train = train_scaled[\"label\"].values \n",
    "\n",
    "X_val = val_scaled[au_columns].values[..., np.newaxis] \n",
    "y_val = val_scaled[\"label\"].values \n",
    "\n",
    "X_test = test_scaled[au_columns].values[..., np.newaxis] \n",
    "y_test = test_scaled[\"label\"].values\n",
    "\n",
    "#Shape-Kontrolle\n",
    "print(\"X_train Shape:\", X_train.shape)\n",
    "print(\"X_val Shape:\", X_val.shape)\n",
    "print(\"X_test Shape:\", X_test.shape)\n",
    "\n",
    "#Label-Verteilung\n",
    "print(\"Train Labels:\", np.bincount(y_train))\n",
    "print(\"Val Labels:\", np.bincount(y_val))\n",
    "print(\"Test Labels:\", np.bincount(y_test))\n",
    "\n",
    "#Histogramm nach Datenvorbereitung\n",
    "col_idx = 0  #nur erste AU-Spalte\n",
    "plt.figure(figsize=(10,4))\n",
    "plt.hist(X_train[:, col_idx, 0], bins=30)\n",
    "plt.title(f\"Verteilung nach CNN-Form: Feature {au_columns[col_idx]}\")\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2dddde72",
   "metadata": {},
   "source": [
    "CNN Architektur - mit Keras"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "4501c65a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\">Model: \"sequential_2\"</span>\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[1mModel: \"sequential_2\"\u001b[0m\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n",
       "┃<span style=\"font-weight: bold\"> Layer (type)                    </span>┃<span style=\"font-weight: bold\"> Output Shape           </span>┃<span style=\"font-weight: bold\">       Param # </span>┃\n",
       "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n",
       "│ conv1d_6 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Conv1D</span>)               │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">18</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">32</span>)         │           <span style=\"color: #00af00; text-decoration-color: #00af00\">128</span> │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ batch_normalization_2           │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">18</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">32</span>)         │           <span style=\"color: #00af00; text-decoration-color: #00af00\">128</span> │\n",
       "│ (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">BatchNormalization</span>)            │                        │               │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ max_pooling1d_3 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">MaxPooling1D</span>)  │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">9</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">32</span>)          │             <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ conv1d_7 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Conv1D</span>)               │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">7</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">64</span>)          │         <span style=\"color: #00af00; text-decoration-color: #00af00\">6,208</span> │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ batch_normalization_3           │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">7</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">64</span>)          │           <span style=\"color: #00af00; text-decoration-color: #00af00\">256</span> │\n",
       "│ (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">BatchNormalization</span>)            │                        │               │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ global_average_pooling1d_3      │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">64</span>)             │             <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │\n",
       "│ (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">GlobalAveragePooling1D</span>)        │                        │               │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ dense_4 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Dense</span>)                 │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">64</span>)             │         <span style=\"color: #00af00; text-decoration-color: #00af00\">4,160</span> │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ dropout_2 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Dropout</span>)             │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">64</span>)             │             <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ dense_5 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Dense</span>)                 │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">1</span>)              │            <span style=\"color: #00af00; text-decoration-color: #00af00\">65</span> │\n",
       "└─────────────────────────────────┴────────────────────────┴───────────────┘\n",
       "</pre>\n"
      ],
      "text/plain": [
       "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n",
       "┃\u001b[1m \u001b[0m\u001b[1mLayer (type)                   \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mOutput Shape          \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1m      Param #\u001b[0m\u001b[1m \u001b[0m┃\n",
       "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n",
       "│ conv1d_6 (\u001b[38;5;33mConv1D\u001b[0m)               │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m18\u001b[0m, \u001b[38;5;34m32\u001b[0m)         │           \u001b[38;5;34m128\u001b[0m │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ batch_normalization_2           │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m18\u001b[0m, \u001b[38;5;34m32\u001b[0m)         │           \u001b[38;5;34m128\u001b[0m │\n",
       "│ (\u001b[38;5;33mBatchNormalization\u001b[0m)            │                        │               │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ max_pooling1d_3 (\u001b[38;5;33mMaxPooling1D\u001b[0m)  │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m9\u001b[0m, \u001b[38;5;34m32\u001b[0m)          │             \u001b[38;5;34m0\u001b[0m │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ conv1d_7 (\u001b[38;5;33mConv1D\u001b[0m)               │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m7\u001b[0m, \u001b[38;5;34m64\u001b[0m)          │         \u001b[38;5;34m6,208\u001b[0m │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ batch_normalization_3           │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m7\u001b[0m, \u001b[38;5;34m64\u001b[0m)          │           \u001b[38;5;34m256\u001b[0m │\n",
       "│ (\u001b[38;5;33mBatchNormalization\u001b[0m)            │                        │               │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ global_average_pooling1d_3      │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m64\u001b[0m)             │             \u001b[38;5;34m0\u001b[0m │\n",
       "│ (\u001b[38;5;33mGlobalAveragePooling1D\u001b[0m)        │                        │               │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ dense_4 (\u001b[38;5;33mDense\u001b[0m)                 │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m64\u001b[0m)             │         \u001b[38;5;34m4,160\u001b[0m │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ dropout_2 (\u001b[38;5;33mDropout\u001b[0m)             │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m64\u001b[0m)             │             \u001b[38;5;34m0\u001b[0m │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ dense_5 (\u001b[38;5;33mDense\u001b[0m)                 │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m1\u001b[0m)              │            \u001b[38;5;34m65\u001b[0m │\n",
       "└─────────────────────────────────┴────────────────────────┴───────────────┘\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\"> Total params: </span><span style=\"color: #00af00; text-decoration-color: #00af00\">10,945</span> (42.75 KB)\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[1m Total params: \u001b[0m\u001b[38;5;34m10,945\u001b[0m (42.75 KB)\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\"> Trainable params: </span><span style=\"color: #00af00; text-decoration-color: #00af00\">10,753</span> (42.00 KB)\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m10,753\u001b[0m (42.00 KB)\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\"> Non-trainable params: </span><span style=\"color: #00af00; text-decoration-color: #00af00\">192</span> (768.00 B)\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m192\u001b[0m (768.00 B)\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "model = models.Sequential([\n",
    "    Input(shape=(len(au_columns),1)),\n",
    "    layers.Conv1D(32, kernel_size=3, activation=\"relu\"), \n",
    "    layers.BatchNormalization(), \n",
    "    layers.MaxPooling1D(pool_size=2), \n",
    "    \n",
    "    layers.Conv1D(64, kernel_size=3, activation=\"relu\"), \n",
    "    layers.BatchNormalization(), \n",
    "    layers.GlobalAveragePooling1D(), \n",
    "    \n",
    "    layers.Dense(64, activation=\"relu\", kernel_regularizer=regularizers.l2(0.001)), \n",
    "    layers.Dropout(0.6), # etwas stärkeres Dropout \n",
    "    layers.Dense(1, activation=\"sigmoid\")\n",
    "])\n",
    "\n",
    "model.compile(\n",
    "    optimizer=tf.keras.optimizers.Adam(learning_rate=0.001),\n",
    "    loss=\"binary_crossentropy\",\n",
    "    metrics=[\"accuracy\", tf.keras.metrics.AUC(name=\"auc\")]\n",
    ")\n",
    "\n",
    "model.summary()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bc203cec",
   "metadata": {},
   "source": [
    "Training - mit Callbacks"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "be371dbb",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/100\n",
      "\u001b[1m129/129\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 4ms/step - accuracy: 0.9429 - auc: 0.9839 - loss: 0.1901 - val_accuracy: 0.9206 - val_auc: 0.9442 - val_loss: 0.3106 - learning_rate: 2.5000e-04\n",
      "Epoch 2/100\n",
      "\u001b[1m129/129\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 3ms/step - accuracy: 0.9420 - auc: 0.9863 - loss: 0.1799 - val_accuracy: 0.9271 - val_auc: 0.9437 - val_loss: 0.2897 - learning_rate: 2.5000e-04\n",
      "Epoch 3/100\n",
      "\u001b[1m129/129\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 3ms/step - accuracy: 0.9508 - auc: 0.9869 - loss: 0.1764 - val_accuracy: 0.9247 - val_auc: 0.9421 - val_loss: 0.3190 - learning_rate: 2.5000e-04\n",
      "Epoch 4/100\n",
      "\u001b[1m129/129\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 3ms/step - accuracy: 0.9443 - auc: 0.9855 - loss: 0.1819 - val_accuracy: 0.9255 - val_auc: 0.9454 - val_loss: 0.3098 - learning_rate: 2.5000e-04\n",
      "Epoch 5/100\n",
      "\u001b[1m129/129\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 3ms/step - accuracy: 0.9431 - auc: 0.9866 - loss: 0.1755 - val_accuracy: 0.9279 - val_auc: 0.9432 - val_loss: 0.3023 - learning_rate: 2.5000e-04\n",
      "Epoch 6/100\n",
      "\u001b[1m129/129\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 3ms/step - accuracy: 0.9476 - auc: 0.9865 - loss: 0.1704 - val_accuracy: 0.9247 - val_auc: 0.9445 - val_loss: 0.3061 - learning_rate: 2.5000e-04\n",
      "Epoch 7/100\n",
      "\u001b[1m129/129\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 2ms/step - accuracy: 0.9485 - auc: 0.9865 - loss: 0.1682 - val_accuracy: 0.9279 - val_auc: 0.9423 - val_loss: 0.3132 - learning_rate: 2.5000e-04\n",
      "Epoch 8/100\n",
      "\u001b[1m129/129\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 3ms/step - accuracy: 0.9484 - auc: 0.9884 - loss: 0.1624 - val_accuracy: 0.9287 - val_auc: 0.9423 - val_loss: 0.3191 - learning_rate: 1.2500e-04\n",
      "Epoch 9/100\n",
      "\u001b[1m129/129\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 2ms/step - accuracy: 0.9496 - auc: 0.9885 - loss: 0.1611 - val_accuracy: 0.9320 - val_auc: 0.9409 - val_loss: 0.3137 - learning_rate: 1.2500e-04\n",
      "Epoch 10/100\n",
      "\u001b[1m129/129\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 2ms/step - accuracy: 0.9436 - auc: 0.9880 - loss: 0.1662 - val_accuracy: 0.9279 - val_auc: 0.9424 - val_loss: 0.3159 - learning_rate: 1.2500e-04\n",
      "Epoch 11/100\n",
      "\u001b[1m129/129\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 3ms/step - accuracy: 0.9427 - auc: 0.9876 - loss: 0.1657 - val_accuracy: 0.9312 - val_auc: 0.9415 - val_loss: 0.3128 - learning_rate: 1.2500e-04\n",
      "Epoch 12/100\n",
      "\u001b[1m129/129\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 2ms/step - accuracy: 0.9523 - auc: 0.9898 - loss: 0.1504 - val_accuracy: 0.9255 - val_auc: 0.9421 - val_loss: 0.3188 - learning_rate: 1.2500e-04\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 45684 characters]",
      "text/plain": [
       "<Figure size 800x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 52480 characters]",
      "text/plain": [
       "<Figure size 800x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 37684 characters]",
      "text/plain": [
       "<Figure size 800x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "callbacks = [ \n",
    "    tf.keras.callbacks.EarlyStopping( monitor=\"val_loss\", patience=10, restore_best_weights=True ), \n",
    "    tf.keras.callbacks.ReduceLROnPlateau( monitor=\"val_loss\", factor=0.5, patience=5, min_lr=1e-6 ), \n",
    "    tf.keras.callbacks.ModelCheckpoint( \"cnn_best_model.keras\", save_best_only=True, monitor=\"val_loss\" ) \n",
    "]\n",
    "\n",
    "history = model.fit(\n",
    "     X_train, y_train, \n",
    "     validation_data=(X_val, y_val), \n",
    "     epochs=100, \n",
    "     batch_size=32, \n",
    "     callbacks=callbacks \n",
    ")\n",
    "\n",
    "# Trainingsverlauf plotten\n",
    "def plot_history(history, metric): \n",
    "    plt.figure(figsize=(8,6)) \n",
    "    plt.plot(history.history[metric], label=f\"Train {metric}\") \n",
    "    plt.plot(history.history[f\"val_{metric}\"], label=f\"Val {metric}\") \n",
    "    plt.xlabel(\"Epochs\") \n",
    "    plt.ylabel(metric.capitalize()) \n",
    "    plt.title(f\"Training vs Validation {metric.capitalize()}\")\n",
    "    plt.legend()\n",
    "    plt.grid(True)\n",
    "    plt.show()\n",
    "\n",
    "# Funktionsaufrufe NACH der Definition\n",
    "plot_history(history, \"loss\")\n",
    "plot_history(history, \"accuracy\")\n",
    "plot_history(history, \"auc\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ff5c5462",
   "metadata": {},
   "source": [
    "Evaluation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "fd803602",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[1m91/91\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 4ms/step\n",
      "Test Accuracy: 0.9448491155046826\n",
      "Test F1: 0.9538193435957014\n",
      "Test AUC: 0.937195821764372\n",
      "Confusion Matrix:\n",
      " [[1082  137]\n",
      " [  22 1642]]\n",
      "              precision    recall  f1-score   support\n",
      "\n",
      "           0       0.98      0.89      0.93      1219\n",
      "           1       0.92      0.99      0.95      1664\n",
      "\n",
      "    accuracy                           0.94      2883\n",
      "   macro avg       0.95      0.94      0.94      2883\n",
      "weighted avg       0.95      0.94      0.94      2883\n",
      "\n"
     ]
    }
   ],
   "source": [
    "y_test_pred_proba = model.predict(X_test).ravel() \n",
    "y_test_pred = (y_test_pred_proba > 0.5).astype(int) \n",
    "\n",
    "print(\"Test Accuracy:\", accuracy_score(y_test, y_test_pred)) \n",
    "print(\"Test F1:\", f1_score(y_test, y_test_pred)) \n",
    "print(\"Test AUC:\", roc_auc_score(y_test, y_test_pred)) \n",
    "print(\"Confusion Matrix:\\n\", confusion_matrix(y_test, y_test_pred)) \n",
    "print(classification_report(y_test, y_test_pred)) "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4edb792b",
   "metadata": {},
   "source": [
    "Model speichern "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "1a805bf6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['scaler_cnn_v2.joblib']"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model.save(\"cnn_model_full_v2.keras\") \n",
    "\n",
    "# Scaler speichern \n",
    "joblib.dump(scaler, \"scaler_cnn_v2.joblib\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
