From 0f7d5f708edfb4587658c1684c0ed0590fd44cc1 Mon Sep 17 00:00:00 2001 From: Janik02 <65945123+Janik02@users.noreply.github.com> Date: Tue, 25 Jan 2022 12:06:38 +0100 Subject: [PATCH 1/2] Add files via upload --- mainv2.2.ipynb | 719 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 719 insertions(+) create mode 100644 mainv2.2.ipynb diff --git a/mainv2.2.ipynb b/mainv2.2.ipynb new file mode 100644 index 0000000..c3d97af --- /dev/null +++ b/mainv2.2.ipynb @@ -0,0 +1,719 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "71fc1147-b775-4b7b-b705-4465369d983d", + "metadata": {}, + "source": [ + "# Import Libraries" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "c9638cdf", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The autoreload extension is already loaded. To reload it, use:\n", + " %reload_ext autoreload\n" + ] + } + ], + "source": [ + "import numpy as np\n", + "import pandas as pd\n", + "%load_ext autoreload\n", + "%autoreload 2\n", + "import custom_functions as cf\n", + "import tensorflow as tf\n", + "from tensorflow.keras import layers\n", + "from sklearn import metrics\n", + "import math\n", + "import scipy.stats as stats\n", + "import matplotlib.pyplot as plt\n", + "import seaborn as sn" + ] + }, + { + "cell_type": "markdown", + "id": "591713c5-410e-4826-aeb7-0bc8fcaf092d", + "metadata": {}, + "source": [ + "## Define functions " + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "68b640f9-4ddf-47fc-9261-e4635da0c94b", + "metadata": {}, + "outputs": [], + "source": [ + "#-------------------------------------------Data Preparation -------------------------------------------------------------------------#\n", + "def Remove_Outlier_Indices(df):\n", + " Q1 = df.quantile(0.25)\n", + " Q3 = df.quantile(0.75)\n", + " IQR = Q3 - Q1\n", + " trueList = ~((df < (Q1 - 1.5 * IQR)) |(df > (Q3 + 1.5 * IQR)))\n", + " return trueList\n", + "#-------------------------------------------Visualization-----------------------------------------------------------------------------#\n", + "\n", + "def plot_confu_matrix(cm, datatype=None, dataset=None, path = 'confusion_matrix.png'):\n", + " \"\"\"\n", + " Returns a matplotlib figure containing the plotted confusion matrix.\n", + "\n", + " Args:\n", + " cm (array, shape = [n, n]): a confusion matrix of integer classes\n", + " class_names (array, shape = [n]): String names of the integer classes\n", + " \"\"\"\n", + " fig = plt.figure(figsize=(8, 6)) # size in inches\n", + " # use plot(), etc. to create your plot.\n", + " df_cm = pd.DataFrame(cm, ('0','1'), ('0','1'))\n", + " sn.set(font_scale=1.4) # for label size\n", + " sn.heatmap(df_cm, annot=True, annot_kws={\"size\": 16},fmt=\"d\") # font size and decimal appearance\n", + " plt.xlabel('predicted')\n", + " plt.ylabel('true label')\n", + " if dataset is not None:\n", + " plt.title('conf_matrix based on {} data of {} dataset'.format(datatype,dataset))\n", + " #plt.show()\n", + " plt.savefig(path)\n", + " #return fig\n", + "#------------------------------------ Network Models ---------------------------------------------------------------------------------# \n", + "def denseModel():\n", + " input_shape = (cols-1)\n", + " dropout = 0.2\n", + " \n", + " inputs = tf.keras.Input(shape = input_shape) \n", + " x = layers.Flatten()(inputs)\n", + " x = layers.Dense(128)(x)\n", + " x = layers.Activation('relu')(x)\n", + " if dropout is not None:\n", + " x = layers.Dropout(rate = dropout)(x)\n", + "\n", + " x = layers.Dense(32)(x)\n", + " x = layers.Activation('relu')(x) \n", + " if dropout is not None:\n", + " x = layers.Dropout(rate = dropout)(x)\n", + "\n", + " x = layers.Dense(2)(x)\n", + "\n", + " outputs = layers.Activation('softmax')(x)\n", + " model = tf.keras.models.Model(inputs=inputs, outputs=outputs) \n", + " model.summary()\n", + " return model" + ] + }, + { + "cell_type": "markdown", + "id": "cdabfe56-4e2a-4481-aed9-3482dc4d2827", + "metadata": {}, + "source": [ + "# Main Code" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "80b94ebf", + "metadata": {}, + "outputs": [], + "source": [ + "#['A1','B1','C1','C3','D1','E1','F','G','H','I','D2','E2','A2','B2','C2','Target']\n", + "\n", + "# ----- IMPORT DATA --------\n", + "data_set = pd.read_csv('train.csv', header=0)\n" + ] + }, + { + "cell_type": "markdown", + "id": "4b975cf7-99ad-4d20-9b5a-31567ee5bc82", + "metadata": {}, + "source": [ + "Ziel:\n", + "Binäre Klassifikation von Daten, Zielvariable: Spalte \"Target\"\n", + "\n", + "A1, B1, C1, C3, D1, E1:\n", + "Anzahl der Treffer einer Datenbanksuche\n", + "\n", + "F, I:\n", + "Absolute Werte\n", + "\n", + "G:\n", + "Differenz vom Median von F (gruppiert nach einem fehlenden Wert)\n", + "\n", + "H:\n", + "Outlier von F (gruppiert nach einem fehlenden Wert)\n", + "\n", + "A2, B2, C2, D2, E2:\n", + "Ist der Quotient von A1, B1, C1, D1, E2 mit I\n", + "\n", + "--> Nutze: A2, B2, C2, D2, E2 und G/F und H? C3?\n" + ] + }, + { + "cell_type": "markdown", + "id": "149b0d93-35b8-439d-9da8-eacbf3bb8fb8", + "metadata": {}, + "source": [ + "## Data Preparation and visualization" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "b790f18a-5486-469e-a23e-84d1d26c0a1c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
A2B2C2C3D2E2FHTarget
count41131.00000041131.00000041131.00000041131.00000041131.00000041131.00000041131.00000041131.00000041131.000000
mean7.0491931.70822315.3163660.1593930.3875650.10668741.8768030.2409620.003185
std5.90701933.857118148.4654031.7982697.6838182.5323209.5197520.4276720.056346
min0.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.000000
25%2.4700000.0000000.0000000.0000000.0000000.00000036.1700000.0000000.000000
50%6.1100000.0000000.0000000.0000000.0000000.00000040.9400000.0000000.000000
75%9.7250000.0000000.0000000.0000000.0000000.00000047.3400000.0000000.000000
max54.2000002491.4600004206.460000203.000000287.360000294.46000099.8800001.0000001.000000
\n", + "
" + ], + "text/plain": [ + " A2 B2 C2 C3 D2 \\\n", + "count 41131.000000 41131.000000 41131.000000 41131.000000 41131.000000 \n", + "mean 7.049193 1.708223 15.316366 0.159393 0.387565 \n", + "std 5.907019 33.857118 148.465403 1.798269 7.683818 \n", + "min 0.000000 0.000000 0.000000 0.000000 0.000000 \n", + "25% 2.470000 0.000000 0.000000 0.000000 0.000000 \n", + "50% 6.110000 0.000000 0.000000 0.000000 0.000000 \n", + "75% 9.725000 0.000000 0.000000 0.000000 0.000000 \n", + "max 54.200000 2491.460000 4206.460000 203.000000 287.360000 \n", + "\n", + " E2 F H Target \n", + "count 41131.000000 41131.000000 41131.000000 41131.000000 \n", + "mean 0.106687 41.876803 0.240962 0.003185 \n", + "std 2.532320 9.519752 0.427672 0.056346 \n", + "min 0.000000 0.000000 0.000000 0.000000 \n", + "25% 0.000000 36.170000 0.000000 0.000000 \n", + "50% 0.000000 40.940000 0.000000 0.000000 \n", + "75% 0.000000 47.340000 0.000000 0.000000 \n", + "max 294.460000 99.880000 1.000000 1.000000 " + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# ---------- DELETE REDUNDANT FEATURES ---------------------------\n", + "data = data_set[['A2', 'B2', 'C2','C3', 'D2','E2', 'F', 'H', 'Target']] \n", + "data.describe()" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "6db71475-6585-4caf-9cd3-88ec78f975df", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "118 out of 131 Samples with label \"1\" have been kept\n" + ] + } + ], + "source": [ + "# ----------------- REMOVE OUTLIER ---------------------------\n", + "''' Remove only Outlier for Features A2 and F because otherwise all or near to all samples with Label(Target) == 1 get removed! '''\n", + "cleaned = data\n", + "for colName in ['A2','F']:\n", + " # Index List of Non-Outliers\n", + " nonOutlierList = Remove_Outlier_Indices(cleaned[colName])\n", + " # Non-Outlier Subset of the Given Dataset\n", + " cleaned = cleaned[nonOutlierList]\n", + "\n", + "#--------- VISUALIZE CLEANED DATA ------------------- \n", + "c= 0\n", + "for i in cleaned.Target.iteritems():\n", + "\n", + " if i[1] == 1:\n", + " c+=1\n", + "\n", + "print(c, ' out of 131 Samples with label \"1\" have been kept')\n", + "# cleaned.describe()" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "15348f4d-e561-41c0-a044-54a15fa8a309", + "metadata": {}, + "outputs": [], + "source": [ + "# ------------- MIN MAX NORMALIZATION --------------------------\n", + "# copy the data\n", + "scaled = cleaned.copy()\n", + "\n", + "# apply normalization techniques\n", + "for column in scaled.columns:\n", + " scaled[column] = (scaled[column] - scaled[column].abs().min()) / (scaled[column].abs().max() - scaled[column].abs().min())\n", + "\n", + "# view normalized data\n", + "#scaled.describe()\n" + ] + }, + { + "cell_type": "markdown", + "id": "a4ce8a39-37c6-403c-afdd-f509dfae3893", + "metadata": {}, + "source": [ + "### Upsampling for neural network " + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "3d544edd-2013-4594-9baa-5a01bdfd083a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "number of features: 8\n", + "Percentage of samples class 1: 0.44894467655957354\n" + ] + } + ], + "source": [ + "'''As the data set consists of less than 1 percent samples with label == 1, we simply extend the training set with multiple copies of those samples such that its percentage is ~ 50 % '''\n", + "\n", + "df = scaled\n", + "#shuffle data rows\n", + "df = df.sample(frac=1)\n", + "\n", + "#train test split\n", + "n = int(0.8 * len(df))\n", + "cols = len(df.columns)\n", + "print('number of features: ', cols-1)\n", + "train = df.iloc[0:n, :]\n", + "test = df.iloc[n: , :]\n", + "\n", + "#make copy of x_train for upsampling, this way we can use the original set for validation/analysis purposes later on\n", + "df_train = train.copy()\n", + "\n", + "# get row indices of samples with label '1'\n", + "c = 0\n", + "indices = []\n", + "for index, series in df_train.iterrows(): #Iterate over DataFrame rows as (index, Series) pairs.\n", + " if series.Target == 1:\n", + " c += 1\n", + " indices.append(index)\n", + " \n", + "samples =[]\n", + "for i in indices:\n", + " samples.append(df_train.loc[i])\n", + "samples = pd.DataFrame(samples)\n", + "\n", + "\n", + "Nupsample = 8\n", + "for n in range(Nupsample):\n", + " samples = samples.append(samples)\n", + "#append samples to original set\n", + "df_train = df_train.append(samples)\n", + "\n", + "print('Percentage of samples class 1: ',sum(df_train.Target)/len(df_train.Target))" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "fdb8c63c-085f-436b-9122-6d4a201e92d9", + "metadata": {}, + "outputs": [], + "source": [ + "#df_train" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "be2079bf", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "number of samples class 1: 25974.0\n" + ] + } + ], + "source": [ + "# ------------ SOME LAST PREPARATION BEFORE TRAINIGN ---------------------------\n", + "\n", + "#split features and labels\n", + "x_train = df_train.iloc[ : , : cols-1]\n", + "y_train = df_train.iloc[ : , cols-1]\n", + "x_test = test.iloc[ : , : cols-1]\n", + "y_test = test.iloc[ : , cols-1]\n", + "\n", + "# ------------ ONE HOT ENCODE LABELS ------------------------------------------\n", + "Y_train = tf.keras.utils.to_categorical(y_train, 2)\n", + "Y_test = tf.keras.utils.to_categorical(y_test, 2)\n", + "print('number of samples class 1: ',sum(y_train)+sum(y_test))" + ] + }, + { + "cell_type": "markdown", + "id": "478ba50d-b225-489c-ada8-3b60b2ffa9d9", + "metadata": {}, + "source": [ + "## Build Network Model" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "76d4e2c1", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Model: \"functional_5\"\n", + "_________________________________________________________________\n", + "Layer (type) Output Shape Param # \n", + "=================================================================\n", + "input_3 (InputLayer) [(None, 8)] 0 \n", + "_________________________________________________________________\n", + "flatten_2 (Flatten) (None, 8) 0 \n", + "_________________________________________________________________\n", + "dense_6 (Dense) (None, 128) 1152 \n", + "_________________________________________________________________\n", + "activation_6 (Activation) (None, 128) 0 \n", + "_________________________________________________________________\n", + "dropout_4 (Dropout) (None, 128) 0 \n", + "_________________________________________________________________\n", + "dense_7 (Dense) (None, 32) 4128 \n", + "_________________________________________________________________\n", + "activation_7 (Activation) (None, 32) 0 \n", + "_________________________________________________________________\n", + "dropout_5 (Dropout) (None, 32) 0 \n", + "_________________________________________________________________\n", + "dense_8 (Dense) (None, 2) 66 \n", + "_________________________________________________________________\n", + "activation_8 (Activation) (None, 2) 0 \n", + "=================================================================\n", + "Total params: 5,346\n", + "Trainable params: 5,346\n", + "Non-trainable params: 0\n", + "_________________________________________________________________\n" + ] + } + ], + "source": [ + "model = denseModel()\n", + "lr = 0.0001\n", + "optimizer = tf.keras.optimizers.Adam(lr=lr) \n", + " #beta_1 = config.beta_1, \n", + " #beta_2 = config.beta_2,\n", + " #epsilon = config.epsilon) \n", + "lossfct = tf.keras.losses.BinaryCrossentropy(from_logits = True)\n", + "model.compile(optimizer = optimizer, loss = lossfct)" + ] + }, + { + "cell_type": "markdown", + "id": "01ed1fe9-fd61-4c8b-b85e-6eaa7830601e", + "metadata": {}, + "source": [ + "## Train Model" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "6ff3634f-6f71-4ab6-9d72-e895be0127bd", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 1/15\n", + "1768/1768 [==============================] - 2s 1ms/step - loss: 0.6266 - val_loss: 0.5676\n", + "Epoch 2/15\n", + "1768/1768 [==============================] - 2s 1ms/step - loss: 0.5557 - val_loss: 0.5279\n", + "Epoch 3/15\n", + "1768/1768 [==============================] - 2s 1ms/step - loss: 0.5248 - val_loss: 0.5132\n", + "Epoch 4/15\n", + "1768/1768 [==============================] - 2s 1ms/step - loss: 0.5152 - val_loss: 0.5085\n", + "Epoch 5/15\n", + "1768/1768 [==============================] - 2s 1ms/step - loss: 0.5123 - val_loss: 0.5078\n", + "Epoch 6/15\n", + "1768/1768 [==============================] - 2s 1ms/step - loss: 0.5109 - val_loss: 0.5084\n", + "Epoch 7/15\n", + "1768/1768 [==============================] - 2s 1ms/step - loss: 0.5102 - val_loss: 0.5077\n", + "Epoch 8/15\n", + "1768/1768 [==============================] - 2s 1ms/step - loss: 0.5096 - val_loss: 0.5075\n", + "Epoch 9/15\n", + "1768/1768 [==============================] - 2s 1ms/step - loss: 0.5092 - val_loss: 0.5077\n", + "Epoch 10/15\n", + "1768/1768 [==============================] - 2s 1ms/step - loss: 0.5090 - val_loss: 0.5073\n", + "Epoch 11/15\n", + "1768/1768 [==============================] - 2s 1ms/step - loss: 0.5087 - val_loss: 0.5077\n", + "Epoch 12/15\n", + "1768/1768 [==============================] - 2s 1ms/step - loss: 0.5085 - val_loss: 0.5075\n", + "Epoch 13/15\n", + "1768/1768 [==============================] - 2s 1ms/step - loss: 0.5083 - val_loss: 0.5078\n", + "Epoch 14/15\n", + "1768/1768 [==============================] - 2s 1ms/step - loss: 0.5081 - val_loss: 0.5072\n", + "Epoch 15/15\n", + "1768/1768 [==============================] - 2s 1ms/step - loss: 0.5080 - val_loss: 0.5072\n", + "saved training log\n" + ] + }, + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# -------------- TRAIN MODEL ---------------------------------------------------\n", + "history = model.fit(x_train , Y_train , epochs = 15 , validation_data = ( x_test , Y_test), batch_size = 32)\n", + "model.save(\"model.h5\")\n", + "log = pd.DataFrame(history.history)\n", + "log.to_csv(\"train_log.csv\",index=False)\n", + "print(\"saved training log\")\n", + "\n", + "# --------------- VISUALIZE TRAINING PROCESS ------------\n", + "plt.plot(history.history['loss'])\n", + "plt.plot(history.history['val_loss'])" + ] + }, + { + "cell_type": "markdown", + "id": "9521ecc0-7c24-4987-90e5-a6554a7360bf", + "metadata": {}, + "source": [ + "## Validation and Performance Analysis" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "1fb2a96b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Accuracy on test data: 0.9917915309446254\n", + "Accuracy on train data: 0.9913000424388174\n" + ] + } + ], + "source": [ + "# ------ LOAD MODEL ---------\n", + "lmodel = tf.keras.models.load_model('model.h5')\n", + "\n", + "# ------- ACCURACIES ------------------------------\n", + "y_pred = np.argmax(lmodel.predict(x_test), axis=1)\n", + "y_pred_train = np.argmax(lmodel.predict(x_train), axis=1)\n", + "print('Accuracy on test data: ',metrics.accuracy_score(y_test,y_pred))\n", + "print('Accuracy on train data: ',metrics.accuracy_score(y_train,y_pred_train))" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "a6383610-865c-4e62-acbc-3beee06d8a7a", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAfAAAAF/CAYAAAC2SpvrAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8QVMy6AAAACXBIWXMAAAsTAAALEwEAmpwYAAA6nElEQVR4nO3de1wVdf7H8RcKiHCkvCBYmhc0yTS8gKhpmCW7+8tKtOzijSTTTdBMrLRSt9TNW5RhhYlpZiZmWa3rrllZa4UGWZliphapIWReiOXIETi/P4w5nkXg0OHi2PvZYx6PzndmvnwgHr35fuc7Mx52u92OiIiImEq9ui5AREREqk4BLiIiYkIKcBERERNSgIuIiJiQAlxERMSEFOAiIiIm5FnXBVSXM8cO1nUJIm7zu/y6ui5BpFrYCg/XSL/u/r/eq1m7aqqk7mkELiIiYkIXzQhcRET+AEqK67qCC4YCXEREzMNeUtcVXDAU4CIiYh4lCvBSugYuIiJiQhqBi4iIadg1hW5QgIuIiHloCt2gABcREfPQCNygABcREfPQbWQGLWITERExIY3ARUTEPDSFblCAi4iIeWgRm0EBLiIipqHbyBx0DVxERMSENAIXERHz0BS6QQEuIiLmoSl0gwJcRETMQ/eBGxTgIiJiHhqBG7SITURExIQU4CIiYh4lJe5tVbB9+3Y6dux43u2GG24AIDMzk5EjR9K1a1f69+9PSkrK/5RbwuLFi+nXrx+hoaGMGTOGrKwsp2Mq66M8CnARETEPe4l7WxV069aNbdu2OW3Lly/H09OTcePGcfz4cWJiYmjdujXr169n0qRJLF68mNTUVKOPJUuWsGbNGmbPns3atWupX78+sbGxFBYWArjUR3l0DVxERMyjFm8j8/b2JiAgwPh85swZ5s6dy8CBAxk2bBgvvvgiXl5ezJo1C09PT4KDg8nKymLp0qUMGzYMm83G8uXLSUhIIDIyEoDExET69u3Lpk2bGDx4MKmpqRX2URGNwEVExDTs9mK3NnesWrWK7Oxspk2bBkB6ejphYWF4ejrGwhERERw6dIicnBwyMzMpKCigV69exn6LxUKnTp1IT093qY+KKMBFREQqYbVaSU5OZtSoUQQGBgKQk5NDUFCQ03HNmzcHIDs72wjg0uPPPSY7O9ulPiqiKXQRETEPN28jy8vLIy8vr0y7v78//v7+5Z739ttvU1hYyKhRo4y206dP4+3t7XRc6efCwkKsVqtT27nH2Gw2l/qoiAJcRETMw81r4CtXriQpKalMe1xcHPHx8eWe9/bbbzNw4ECaNGlitPn4+BhBXKr0s6+vLz4+PkbbuSFts9nw9fV1qY+KKMBFRMQ83ByBjx49mujo6DLtFY2+jx8/zpdffsn48eOd2oOCgsjNzXVqK/0cFBSE3W432iwWi9Mx7du3d6mPiijARUTkD6OyqfLz+eKLL/Dw8CA8PNypPTw8nNWrV1NUVGQsQktLS6NNmzYEBARwySWXYLFY2LFjB+3atQMgPz+fPXv2cPfdd7vUR0W0iE1ERMyjpNi97XfYs2cPrVq1KjOlPXToUKxWK9OnT2f//v1s2LCBFStWMG7cOODstewRI0aQmJjIli1b2Lt3L5MnTyYwMJCoqCiX+qiIRuAiImIedfAs9J9//plLLrmkTHvTpk1JSUlhzpw5REdHExAQwJQpUxgyZIhxzMSJEykuLmbGjBlYrVZ69OjBsmXLjGvirvRRHg976SS9yZ05drCuSxBxm9/l19V1CSLVwlZ4uEb6PZ221q3zfXrdUU2V1D2NwEVExDz0NjKDroGLiIiYkEbgIiJiHrX4LPQLnQJcRETMQwFuUICLiIhpuPtCkouJroGLiIiYkEbgIiJiHppCNyjARUTEPHQbmUEBLiIi5qERuEEBLiIi5qERuEGL2ERERExII3ARETEPTaEbFOAiImIemkI3KMBFRMQ8NAI3KMBFRMQ8FOAGLWITERExIY3ARUTEPHQN3KAAFxER89AUukEBLiIi5qERuEHXwEVERExII3ARETEPTaEbFOAiImIemkI3KMBFRMQ8NAI3KMBFRMQ8FOAGLWITERExIY3ARUTEPOz2uq7ggqEAFxER89AUukEBLiIi5qEANyjARUTEPHQbmUGL2ERERExII3ARETEPTaEbNAIXERHzsNvd236HDRs28H//93906dKFm266iU2bNhn7MjMzGTlyJF27dqV///6kpKQ4nVtSUsLixYvp168foaGhjBkzhqysLKdjKuujPApwERExj5IS97Yqevvtt5k+fTp33HEH//jHPxg0aBAPPvggGRkZHD9+nJiYGFq3bs369euZNGkSixcvJjU11Th/yZIlrFmzhtmzZ7N27Vrq169PbGwshYWFAC71UR5NoYuIiJyH3W7n2WefZcSIEYwePRqAv/71r6Snp5OWlsbnn3+Ol5cXs2bNwtPTk+DgYLKysli6dCnDhg3DZrOxfPlyEhISiIyMBCAxMZG+ffuyadMmBg8eTGpqaoV9VEQjcBERMY9aHIEfPHiQI0eOMGjQIKf2lJQUJkyYQHp6OmFhYXh6OsbCERERHDp0iJycHDIzMykoKKBXr17GfovFQqdOnUhPTweotI+KKMBFRMQ87CXubVXwww8/AGCz2bjvvvvo3bs3t99+Ox988AEAOTk5BAUFOZ3TvHlzALKzs40ADgwMLHNMdna2S31URFPoIiJiGvYS9x6lmpeXR15eXpl2f39//P39ndry8/MBeOihh5gwYQKTJ09m8+bN3H///aSkpHD69Gm8vb2dzin9XFhYiNVqdWo79xibzQZQaR8VUYCLiIh5uHkb2cqVK0lKSirTHhcXR3x8vFObl5cXAPfccw9Dhw4F4KqrruKbb75h+fLl+Pj4GEFcqvSzr68vPj4+Rtu5IW2z2fD19QWotI+KKMBFROQPY/To0URHR5dp/9/RN2BMbV955ZVO7R06dOD999/niiuuIDc312lf6eegoCDsv922lpubi8VicTqmffv2xnEV9VERXQMXERHzcPMauL+/Py1btiyznS/AO3XqhJ+fH7t27XJq37dvH1dccQXh4eFkZGRQVFRk7EtLS6NNmzYEBAQQEhKCxWJhx44dxv78/Hz27NlDz549ASrtoyIKcBERMY8Su3tbFfj4+HDvvffy/PPP88477/Djjz/ywgsvsG3bNsaMGcPQoUOxWq1Mnz6d/fv3s2HDBlasWMG4ceOAs9eyR4wYQWJiIlu2bGHv3r1MnjyZwMBAoqKiACrtoyIedvvF8XLVM8cO1nUJIm7zu/y6ui5BpFrYCg/XSL8Fz93v1vm+8c9X+ZwVK1bw6quvcvToUdq1a0d8fDwDBw4EYNeuXcyZM4fdu3cTEBBATEwMo0aNMs4tLi4mMTGRN998E6vVSo8ePZg5cyatWrUyjqmsj/IowP8gdnzxNWPiHy53/+b1Kzh+4hR33jupzL7Rdw1hatxYAH48/BMLnnuJ7Rlf0aCBF/379mLK/bFceolj+qmoqJgXV7zGhn++x8mTebRv15oHxsfQK6xb9X9jFxkFePW5/vprefKJR+jS5Spyc4+xatU6Zs9JpKSkBB8fH6ZPm8htt99CUGAA+/d/z4IFS1j3xrt1XfZFo8YC/Nnxbp3vO+nFaqqk7mkR2x9Ep47BrE5+2qmt0HaGBx+bw1VXBhPUPIC09C9p2NCHZc/MdTquebOmAJw8lcfo+6fSoIE3M6bGYfHzJXnl69wT/zCpKYuNFZt/f+YF3v3XBzw4YQytLmvB2g0bmTB1FutWJNGudStEalrv3mG8+84qXn99A489/ne6d7+GWTMTKCkpYfacRJKem8stt/yJmbMW8O23+xk0KIrVq1/Abrfzxvp/1HX5Ii5RgP9BWPz8CO18lVPbU8+8iIcHzJv5EPXq1WPf/u/p0LZ1meNKbfjnexw7foINr75IcJsrAAjtfBV/uu0e1r/7b+4cMoisQ0dI3fBPFj05jajr+wHQs/s1DBk9ge3pXyrApVbMmT2N97Z8zL1jHwRg69ZPadqkMZGRfXgxeSWjRg3jvnEJrFjxOgAffLCNdu1aM3nyeAX4he7imDSuFgrwP6gD32ex5s13efTBCTRpfCkA+w78wJXt25Z7TtahI7QIDDDCG6DxpZfQtnVLtqWlc+eQQXzwn8+4xL8RA/v3NY7x8vLi3deW1tj3InKuZs2a0KdPOLfdHuvU/uhjfwegbdsrSF76Clu2fOS0f9++A4SHda2tMuX30utEDbUa4DabjX/961+kp6eTnZ1NYWEhvr6+BAUF0bNnT6KiopyeBys159mlK2nd6nJuu+XPRtt3B7/H29uLoaMncOCHH2kRGMD4mLu49f/OLtYIah7AiVN5nC4sxKdBA+Ds9e6jucewnTkDnP0joG3rlry3dRvPvbSKHw8foX3bNjzywDjCu11T+9+o/OF07hxCvXr1+O9/C3jrzZe54YZ+5OXlk5z8CrPnJPL99z8SHz/d6Zx69erx5z9dz7ff7q+jqsVlbj6J7WJSa7eR/fjjj9x0003MnDmTAwcOYLFYaNGiBQ0bNuS7777j0Ucf5eabb+bw4ZpZ+CAOh386ytZt2xl951Dq1Tv7K5D78y+cOJlH1qEj3Df6Tl5Y+ARh3brw6JyneXvTFgCiru9HcXEx055YwE9Hczj2y3FmL0ri1/x8rNbTAJw4eYqsQz8x79lk7h05jOcXPEHjSy/hr1NmcCS74gfzi1SHgN/WbCxPeZa93x7g5ltGkZz8CtOmTWTKg3897zkzZ0whJKQDi55+oTZLFXFLrQ13//a3v9G2bVveeustpyfSlMrPz2fy5Mk8+eSTJCcn11ZZf0hvvPMv/BtZuPlP1xttjRr5kfz0bK4MbktAsyYA9A7vxs/HjvPC8tXc+pcbadu6JfNnPczf5i8mamgM9erV45Y/38D1fXtx8IdDABQVFXH8xElWLJlPWNcuAHS75mr+MmwMy1ev4/GEuNr/huUPpXQx5XvvbWXatNkAfPTRpzRt1oRp0ybydOKLlJwzDZsw5X6mTZvE04kvsnHjljqpWaqgii8kuZjVWoBnZGSQmpp63vCGs69YmzJlCnfffXdtlfSH9cF/PmVAv95Oz+Zt6OPDtRE9yhx7bUQPtqWlU1Bgxde3ITdGXsv1fXtx6Eg2/o0sNGl8KffEPcwl/mf/u/o2bEhDnwb0CO1s9OHb0IfQziF8d+CHGv/eRPL/+18ANm/e6tT+/vsfc/9fY2jTphUHD2YBMH/+DB6YdB8vvLiCRx6ZXdulyu+hKXRDrU2h+/v7V/pu0yNHjlT68HZxT/bRXA7+cIgbI/s4tf/w42HWvrWxzEP1Cwtt+DRoQMOGPvx0NIc3//Fv6tevT5srWtKk8aWUlJSw//sf6NghGIBWLVtQXFJCcbHzX8lFRcV4eHjU7DcnAhzY/wNQ9g1QXp5nR+Z2ux0PDw9eXv4sD0y6j6eeWsykSY/VdpnyO9lLStzaLia1FuC33XYbjzzyCK+//joHDx6koKCAoqIiCgoK+OGHH0hNTeXRRx9lyJAhtVXSH9KuzG8BuObqEKf23J9/4cmFSXz82edGm91uZ8tHn9A99Go8PDzI+fkXZvz9Gfacs9DnXx98zImTefS/NgKAPuHdsdnOsPWTNOOYvF/z+XLXHrp2Of/taSLVaU/mPg4fzmbo0Juc2v/ylwEcOXKUH344xPz5Mxg+fChTH/obM2bOr6NK5XepxUepXuhqbQo9Pj4eDw8P5s+fb7wj9Vx+fn4MHz6cSZPKPglMqs93B7NofKm/05PTAHp07Uz3a67miQVJ5P2aT0DTJqx7exP7DnzPK88vBOCaTh256spgZvw9kUnjYsg9dpynnn2Rfr3C6B1+9ilrfXp2p1dYV2b8/RlOnvqV5s2asGxVKgAjbh9cq9+r/DHZ7XZmzHiK5cuf5bnn5vLmmxu5YUA/Ro68nbj4aYSGXk18XCzvbfmIzz7LoGfP7sa5xcXFZGR8VYfVi7iu1h+larPZ2Lt3Lzk5OVitVnx8fAgKCiIkJKTMlFdV6FGqrnlyYRKffb6Tf65NKbPvVN6vPPPiCj7+dDsnT/3KVR3bM3n8PfTo6rienX00l7mJL/D5zq/xbdiQP99wHfH3jaLhb++9BSgosPLMiy/zrw/+g9VqJbTzVTw8aRwd2rWpjW/R1PQo1epzx7BbefjheNq3b8Ohw9k8/fSLpKSs5vHHHuTxxx887zn5+f+lSdOOtVzpxammHqX639kj3Drf77FXq6mSuqdnoYtcQBTgcrGosQB/Yrhb5/vNWF1NldQ9PTVFRETM4yJbiOYOBbiIiJjHRbYQzR21tgpdREREqo9G4CIiYh56EptBAS4iIuahKXSDAlxEREzjYnuamjt0DVxERMSENAIXERHz0BS6QQEuIiLmoQA3KMBFRMQ8tArdoAAXERHz0AjcoEVsIiIiJqQRuIiImIZdI3CDAlxERMxDAW5QgIuIiHnoQS4GBbiIiJiHRuAGLWITERExIY3ARUTEPDQCNyjARUTENOx2BXgpTaGLiIh5lNjd26ro4MGDdOzYscy2bt06ADIzMxk5ciRdu3alf//+pKSkOJdbUsLixYvp168foaGhjBkzhqysLKdjKuujPBqBi4iIlOPbb7/FYrHwr3/9y6m9UaNGHD9+nJiYGAYOHMisWbP4+uuvmTVrFo0aNWLYsGEALFmyhDVr1vDUU08RGBjIokWLiI2NZePGjTRo0MClPsqjABcREfOo5Wvg+/btIzg4mICAgDL7VqxYgZeXF7NmzcLT05Pg4GCysrJYunQpw4YNw2azsXz5chISEoiMjAQgMTGRvn37smnTJgYPHkxqamqFfVREU+giImIa9hK7W1tVffvttwQHB593X3p6OmFhYXh6OsbCERERHDp0iJycHDIzMykoKKBXr17GfovFQqdOnUhPT3epj4oowEVExDxq+Rr4vn37yM3N5c4776RPnz7cfffdbNu2DYCcnByCgoKcjm/evDkA2dnZRgAHBgaWOSY7O9ulPiqiKXQRETEPNx/ElpeXR15eXpl2f39//P39ndoKCgo4fPgwTZo0YcqUKfj5+fHOO+9w7733snz5ck6fPo23t7fTOaWfCwsLsVqtTm3nHmOz2QAq7aMiCnAREfnDWLlyJUlJSWXa4+LiiI+Pd2rz9fUlIyMDLy8vI1Q7d+7MgQMHWLZsGT4+PkYQlyr97Ovri4+Pj9F2bkjbbDZ8fX0BKu2jIgpwERExDXffRjZ69Giio6PLtP/v6LuUn59fmbYrr7ySDz/8kFatWpGbm+u0r/RzUFCQcc96bm4uFovF6Zj27dsbx1XUR0V0DVxERMzDzWvg/v7+tGzZssx2vgDfuXMn3bp14+uvv3Zq/+abb+jQoQPh4eFkZGRQVFRk7EtLS6NNmzYEBAQQEhKCxWJhx44dxv78/Hz27NlDz549ASrtoyIKcBERMY8SN7cq6Ny5My1btuTxxx8nIyODAwcOMHv2bHbu3Mlf//pXhg4ditVqZfr06ezfv58NGzawYsUKxo0bB5y9lj1ixAgSExPZsmULe/fuZfLkyQQGBhIVFQVQaR8V8bBfJM+lO3PsYF2XIOI2v8uvq+sSRKqFrfBwjfR74vb+bp3feN3WKh2fk5PDokWL+OSTT8jLy+Pqq6/mwQcfNEbQu3btYs6cOezevZuAgABiYmIYNWqUcX5xcTGJiYm8+eabWK1WevTowcyZM2nVqpVxTGV9lEcBLnIBUYDLxeJiCfALmRaxiYiIebh5G9nFRAEuIiKm4e4q9IuJAlxERMxDI3CDVqGLiIiYkEbgIiJiGnaNwA0KcBERMQ8FuEEBLiIipqERuIMCXEREzEMBbtAiNhERERPSCFxERExDU+gOCnARETENBbiDAlxERExDAe5QboC/8cYbVerotttuc7sYERERcU25Af7YY4+53ImHh4cCXEREap7do64ruGCUG+Dvv/9+bdYhIiJSKU2hO5Qb4Jdffnlt1iEiIlIpe4lG4KVcXsSWk5PD888/zyeffEJubi5r1qzhH//4B1dffTWDBg2qyRpFREQAjcDP5dKDXL7//ntuvfVWNm/eTGhoKGfOnAHgl19+YerUqWzevLlGixQRERFnLo3A582bR4sWLVi1ahU+Pj5s3LgRgPnz53P69GmWLVtGVFRUjRYqIiJi1yI2g0sj8O3btzN27FgsFgseHs4/vNtuu439+/fXSHEiIiLnspe4t11MXBqB16tXr0xwl7JardSrp0eqi4hIzdMiNgeXkjc8PJzk5GR+/fVXo83Dw4Pi4mJWr15NWFhYjRUoIiJSym53b7uYuDQCnzp1KnfeeSdRUVH07NkTDw8PXnrpJfbv38+RI0d47bXXarpOEREROYdLI/Dg4GDWr1/PtddeS0ZGBvXr1yctLY127dqxdu1aQkJCarpOERER7CUebm0XE5fvA7/iiitYuHBhTdYiIiJSoYsthN1RpbeRffzxx3z22WecOnWKZs2aERERwbXXXltTtYmIiDi52K5ju8OlAP/ll1+YMGECX375JZ6enlx66aWcPHmSl156id69e7NkyRIaNmxY07WKiIjIb1y6Bj5v3jy+//57kpKS2LVrF9u2beOrr75i4cKFfPXVVyxYsKCm6xQREdE18HO4FOAffvghU6ZM4cYbbzTuB69fvz433XQTDzzwAP/85z9rtEgRERE4+yQ2d7aLicsPcmnSpMl597Vu3dp4NrqIiEhNutiepuYOl0bg0dHRLF26lIKCAqf2M2fOsGrVKm655ZYaKU5ERORcJXYPt7aLSbkj8Iceesj49+LiYvbs2cMNN9xA//79adasGadOnWLbtm2cOHGC9u3b10qxIiIideH7779nyJAhTJ8+ndtvvx2AzMxM5s6dy65du7j00ksZOXIksbGxxjklJSUkJSWxbt068vLy6NGjBzNnzqR169bGMZX1UZFyR+Dp6enGtnPnTpo3b07Dhg3Zvn07GzduZNu2bQA0btxYrxMVEZFaURfXwM+cOUNCQoLTLPTx48eJiYmhdevWrF+/nkmTJrF48WJSU1ONY5YsWcKaNWuYPXs2a9eupX79+sTGxlJYWOhyHxUpdwT+wQcf/K5vVEREpKbUxUry5557Dj8/P6e21NRUvLy8mDVrFp6engQHB5OVlcXSpUsZNmwYNpuN5cuXk5CQQGRkJACJiYn07duXTZs2MXjw4Er7qEy1vEbs1KlT1dGNiIhIhWr7ZSaff/45a9euZd68eU7t6enphIWF4enpGAdHRERw6NAhcnJyyMzMpKCggF69ehn7LRYLnTp1Ij093aU+KuPSKvTCwkJefvllduzYgc1mw/7bT6GkpASr1cqBAwfYtWuXK12JiIj8bu6OwPPy8sjLyyvT7u/vj7+/f5ljH3roIR577DFatGjhtC8nJ6fM+q/mzZsDkJ2dTW5uLgCBgYFljsnOznapj/8993+5FOALFizg1VdfpUOHDpw4cYIGDRrQpEkT9u3bx5kzZ5g4caIr3YiIiNSplStXkpSUVKY9Li6O+Ph4p7ZZs2bRtWtXbr755jLHnz59Gm9vb6e20s+FhYVYrVantnOPsdlsLvVRGZcCfPPmzYwaNYrp06eTnJxMZmYmzzzzDEePHmX48OEUFRW50o2IiIhb3L0VbPTo0URHR5dp/9/R94YNG0hPT+fdd989bz8+Pj5GEJcq/ezr64uPj4/Rdm5I22w2fH19XeqjMi4F+PHjx42L8CEhIaxduxaAoKAgxo4dyyuvvEJcXJwrXYmIiPxu7j5N7XxT5eezfv16fvnlF/r37+/U/sQTT7BixQouu+wyY5q8VOnnoKAg41Jzbm4uFovF6ZjSafOgoKAK+6iMSwHeqFEjTp8+DZx98lp2djb5+flYLBbjs4iISE2rrbeRLVy40Mi9UlFRUcTFxTFo0CA2btzI6tWrKSoqMhahpaWl0aZNGwICArjkkkuwWCzs2LGDdu3aAZCfn8+ePXu4++67AQgPD6+wj8q4tAo9LCyMVatWkZ+fzxVXXIGfnx/vv/8+AF9++aXTXxciIiJmFxgYSOvWrZ02gCZNmnD55ZczdOhQrFYr06dPZ//+/WzYsIEVK1Ywbtw44Oy17BEjRpCYmMiWLVvYu3cvkydPJjAwkKioKIBK+6iMSyPwuLg4hg8fztixY1mzZg3Dhw/n0UcfJSUlhf379xt/TYiIiNSkC+VxqE2bNiUlJYU5c+YQHR1NQEAAU6ZMYciQIcYxEydOpLi4mBkzZmC1WunRowfLli0zrom70kdFPOx21yYkfv75Z7799lv69u2L3W4nOTmZL774gmuuuYb77ruvzEq62nbm2ME6/foi1cHv8uvqugSRamErPFwj/e684la3zu/249vVVEndc2kEDhAQEGDMyXt4eDB+/PgaK0pEROR8ausauBmUG+BvvPFGlTq67bbb3C5GRESkIhfKFPqFoNwp9JCQENc78fAgMzOz2or6PTy9L6/Try8iIg5FtiM10m96y8FunR92eEO11HEhKHcEXrrKXERE5ELh7n3gF5NyA/zyyzWiFRGRC4um0B1cXsQmIiJS17SGzUEBLiIipqERuEO1vA9cREREapdG4CIiYhpaxOZQpQC32Wx8/fXX5OTk0LdvX6xWq0tvTBEREakOJXVdwAXE5QBfs2YNzzzzDKdOncLDw4M33niDp59+GoCkpCQaNmxYY0WKiIgA2NEIvJRL18A3bNjA3/72N/70pz+RnJxsvOc0OjqaL774gqSkpBotUkRERJy5NAJftmwZd911FzNnzqS4uNhoHzRoEEePHmXNmjVMnTq1xooUEREBKNF9ZAaXRuBZWVlcf/3159139dVX8/PPP1drUSIiIudTgodb28XEpQBv1qwZ33777Xn3fffddzRr1qxaixIRETkfOx5ubRcTl6bQb7rpJp5//nkCAwMZMGAAcPYFJl9++SXJyckMHjy4JmsUEREBtAr9XOW+jexcNpuN+Ph4PvroIzw8PLDb7TRs2JDTp08THh7OSy+9RIMGDWqj3nLpbWQiIheOmnob2XuBd7h1/sCctdVUSd1zaQTu7e1NcnIyn376KZ999hknT56kUaNGREREcN111+HhcXFNS4iIyIXpYpsGd0eVHuTSp08f+vTpU1O1iIiIVEhT6A4uBbgr93nHxcW5XYyIiEhFFOAObge4n58fzZo1U4CLiEiN0xS6g0sBvnv37jJt+fn5bN++nTlz5jBnzpxqL0xERETK51KA169fv0zbJZdcQlRUFMeOHWPevHmsW7eu2osTERE5V4kG4Aa3Xyfapk0b9u3bVx21iIiIVOhie5qaO9wK8MLCQl5//XUCAgKqqx4REZFy6VHoDi4FeGRkZJl7vYuLizl58iRnzpzh0UcfrZHiRERE5PxcCvDy7v22WCwMGDCA3r17V2tRIiIi56PbyBxcCvAbbriB8PBwLrnkkpquR0REpFwlevKnwaW3kT388MNs3bq1hksRERGpmN3N7WLi0gi8SZMm572VTEREpDZpCt3BpQAfN24cTz75JPv27aNDhw7nff+3roOLiIjUHpdeJxoSEnL+k397taiHhweZmZnVXlxV6HWiIiIXjpp6neiay4a7df5dP62u0vE5OTnMmzePTz75BJvNRnh4OFOnTqVDhw4AZGZmMnfuXHbt2sWll17KyJEjiY2NNc4vKSkhKSmJdevWkZeXR48ePZg5cyatW7c2jqmsj/K4NAJ/5ZVXqvQNi4iI1ITafJCL3W5n7NixWCwWUlJSaNiwIc8++ywxMTFs3ryZwsJCYmJiGDhwILNmzeLrr79m1qxZNGrUiGHDhgGwZMkS1qxZw1NPPUVgYCCLFi0iNjaWjRs30qBBA44fP15pH+VxKcA9PDy46qqrsFgsZfadOHGCTz/99Hf8aERERKqmNheiHTt2jODgYCZOnEjbtm0BuP/++7n11lvZt28f27dvx8vLi1mzZuHp6UlwcDBZWVksXbqUYcOGYbPZWL58OQkJCURGRgKQmJhI37592bRpE4MHDyY1NbXCPiri0ir0UaNG8d13351331dffcX06dOr8jMRERH5XUo83NuqIiAggMTERCO8jx07RkpKCs2bN+fKK68kPT2dsLAwPD0dY+GIiAgOHTpETk4OmZmZFBQU0KtXL2O/xWKhU6dOpKenA1TaR0XKHYHHxsZy4MAB4Ow0QlxcHF5eXmWOO3HiBJdddpkrPwsREZE6lZeXR15eXpl2f39//P39yz3vkUce4a233sLb25sXXngBPz8/cnJyaN++vdNxzZs3ByA7O5vc3FwAAgMDyxyTnZ0NUGkf/3vuucoN8AkTJhhvGHvrrbe4+uqradq0qdMx9erVw9/fnzvuuKPcLyAiIlJd3L2NbOXKlSQlJZVpj4uLIz4+vtzzYmNjGT58OK+99hoTJkxg9erVnD59Gm9vb6fjSj8XFhZitVqd2s49xmazAVTaR0XKDfDu3bvTvXt3AA4fPuy06k5ERKQuuHsNfPTo0URHR5dpr2j0DRj5N2fOHL766itWrVqFj4+PEcSlSj/7+vri4+NjtJ0b0jabDV9fX4BK+6iIS4vYVq1a5cphIiIiNcrd94FXNlV+rtzcXLZv386gQYOMF3rVq1eP9u3bk5OTQ1BQkDFNfu45AEFBQZTepZ2bm+u0CDw3N9eYNq+sj4q4tIhNRETkjyY7O5uEhAQyMjKMtjNnzrBnzx6Cg4MJDw8nIyODoqIiY39aWhpt2rQhICCAkJAQLBYLO3bsMPbn5+ezZ88eevbsCVBpHxVRgIuIiGmUuLlVRZcuXYiIiGDGjBmkp6ezb98+Hn74YU6ePElMTAxDhw7FarUyffp09u/fz4YNG1ixYgXjxo0Dzl7LHjFiBImJiWzZsoW9e/cyefJkAgMDiYqKAqi0j4q49CQ2M9CT2ERELhw19SS25JYj3Dp/3OFXq3T8qVOnWLhwIR9++CG//vorYWFhPPTQQ3Ts2BGAXbt2MWfOHHbv3k1AQAAxMTGMGjXKOL+4uJjExETefPNNrFar8SS2Vq1aGcdU1kd5FOAiIlLtairAX2zlXoCPP1S1AL+QubSITURE5EKgt5E56Bq4iIiICWkELiIipqERuIMCXERETOOiWLRVTRTgIiJiGu4+yOViomvgIiIiJqQRuIiImIaugTsowEVExDQU4A4KcBERMQ0tYnNQgIuIiGloEZuDFrGJiIiYkEbgIiJiGroG7qAAFxER09A1cAcFuIiImEaJItygABcREdPQFLqDFrGJiIiYkEbgIiJiGppAd1CAi4iIaWgK3UEBLiIipqEHuTjoGriIiIgJaQQuIiKmodvIHBTgIiJiGopvBwW4iIiYhhaxOSjARUTENDSF7qBFbCIiIiakEbiIiJiGxt8OCnARETENXQN3UICLiIhp6Bq4gwJcRERMQ/HtoEVsIiIiJqQRuIiImIaugTtoBC4iIqZhd/OfqsjPz2fu3LkMGDCAbt26MWTIEN5//31jf2ZmJiNHjqRr167079+flJQUp/NLSkpYvHgx/fr1IzQ0lDFjxpCVleV0TGV9VEQBLiIiplHi5lYV06ZNY+vWrcyePZsNGzYQFRVFXFwcn332GcePHycmJobWrVuzfv16Jk2axOLFi0lNTTXOX7JkCWvWrGH27NmsXbuW+vXrExsbS2FhIYBLfVREAS4uGzRoICd++bauyxCpkvJ+b4cNu4WdX2whP+8Ambu3MeH+e+qgOrlQ/fzzz2zevJnp06fTp08fWrduzfjx4+nZsydvvPEGqampeHl5MWvWLIKDg4mOjuaee+5h6dKlANhsNpYvX05cXByRkZGEhISQmJjIsWPH2LRpE0ClfVRGAS4u6d0rjFdWPIeHh17GK+ZR3u/t7bffwquvLGHzv7dy8y2jeGP9uzz7zGxGjry9jioVV5Vgd2tzVcOGDXnppZcICwtzavfw8ODUqVOkp6cTFhaGp6djKVlERASHDh0iJyeHzMxMCgoK6NWrl7HfYrHQqVMn0tPTASrtozIKcKmQt7c3CVP+ypb3UikqKqrrckRcUtnv7VNzH+WFF1fy8LTZfLj1Ex6fMY/X1rzJjTf0q4NqpSrsbm55eXkcPny4zJaXl+f0dSwWC9dddx0Wi8Vo+/LLL0lLS6N///7k5OQQFBTkdE7z5s0ByM7ONgI4MDCwzDHZ2dkAlfZRGa1Clwr9+c/X8/BDcTz8yGyaNm3M5AfG1XVJIpWq6Pe2R/draN26JctSVjudM2p0fG2XKb+Duw9yWblyJUlJSWXa4+LiiI8v/3fgwIEDxMXFERoayh133MHKlSvx9vZ2Oqb0c2FhIVar1ant3GNsNhsAp0+frrCPyijApULp6V/R/srenDqVx4zHH6zrckRcUtHvbZcuVwHgWb8+H2x5g169epCTc4x585N4MXllXZQrVeDubWSjR48mOjq6TLu/v3+553z++efExcVx2WWXkZycjJeXFz4+PkYQlyr97Ovri4+Pj9F2bkjbbDZ8fX0BKu2jMgpwqdBPPx2t6xJEqqyi39uAgKYUFRXx1psreDF5JU/OTuTWW/9M0nNz+eX4Cdate6cWK5Xa5u/vX2FY/6933nmH6dOn07NnTxYvXmxMqQcFBZGbm+t0bOnnoKAg7Ha70XbuNHxubi7t27d3qY/K6Bq4iPyheHl54enpybKUV3lq3nN8uPUTHpj8OBs3buHxxybXdXlSidq8D/zdd9/loYce4i9/+QvJyclOQRweHk5GRobTGou0tDTatGlDQEAAISEhWCwWduzYYezPz89nz5499OzZ06U+KlOrI/C7777b5VXMq1evrvwgEZEqys//LwD//vdWp/Yt73/Mgj/NwMvLizNnztRBZeKK2noS29GjR3n88ceJiIhg6tSpnDx50tjn5eXF0KFDWbZsGdOnT+e+++7jm2++YcWKFcycORM4ey17xIgRJCYm0qxZM1q2bMmiRYsIDAwkKioKoNI+KlOrAR4ZGckzzzxDu3btuOaaa2rzS4uIAHDgwA8AeHt7ObV7eXni4eFBSYke1nkhq+oo+vfavHkzVquVtLQ0+vVzvjuhe/furFmzhpSUFObMmUN0dDQBAQFMmTKFIUOGGMdNnDiR4uJiZsyYgdVqpUePHixbtsy4Jt60adNK+6hIrQb4uHHjsFgsLFq0iOTkZFq2bFmbX15EhI//k4bVamXo0EF88unnRvv//eVG0tO/ori4uA6rk8rU1p9Xo0aNYtSoURUe06VLF15//fVy99evX5+EhAQSEhJ+dx8VqfVFbMOHD+c///kPzzzzDAsXLqztLy8if3C//prPU/OSmPH4g/z6az4ff5zG7bffzHXX9eLmW0bWdXkiLquTVehPPPEEu3fvrosvLSLCnLnPcOpUHhPuH8OUB8ez77uD3H7HWP69eWtdlyaVKLHrjeClPOz2i+On4el9eV2XICIivymyHamRfke0du36cHlezXqzmiqpe7oPXERETMPdJ7FdTHQfuIiIiAlpBC4iIqZRW7eRmYECXERETEN36TsowEVExDR0DdxBAS4iIqahKXQHLWIT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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# ---------- CONFUSION MATRIX -----------------\n", + "y_pred = np.argmax(lmodel.predict(x_test), axis=1)\n", + "\n", + "cm = metrics.confusion_matrix(y_true = y_test,y_pred = y_pred)\n", + "plot_confu_matrix(cm)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.8" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From a47e7a3f5aece0822af563435616c681e29a5d08 Mon Sep 17 00:00:00 2001 From: Janik02 <65945123+Janik02@users.noreply.github.com> Date: Tue, 25 Jan 2022 12:07:47 +0100 Subject: [PATCH 2/2] Delete mainv2.2.ipynb --- mainv2.2.ipynb | 719 ------------------------------------------------- 1 file changed, 719 deletions(-) delete mode 100644 mainv2.2.ipynb diff --git a/mainv2.2.ipynb b/mainv2.2.ipynb deleted file mode 100644 index c3d97af..0000000 --- a/mainv2.2.ipynb +++ /dev/null @@ -1,719 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "71fc1147-b775-4b7b-b705-4465369d983d", - "metadata": {}, - "source": [ - "# Import Libraries" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "c9638cdf", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The autoreload extension is already loaded. To reload it, use:\n", - " %reload_ext autoreload\n" - ] - } - ], - "source": [ - "import numpy as np\n", - "import pandas as pd\n", - "%load_ext autoreload\n", - "%autoreload 2\n", - "import custom_functions as cf\n", - "import tensorflow as tf\n", - "from tensorflow.keras import layers\n", - "from sklearn import metrics\n", - "import math\n", - "import scipy.stats as stats\n", - "import matplotlib.pyplot as plt\n", - "import seaborn as sn" - ] - }, - { - "cell_type": "markdown", - "id": "591713c5-410e-4826-aeb7-0bc8fcaf092d", - "metadata": {}, - "source": [ - "## Define functions " - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "68b640f9-4ddf-47fc-9261-e4635da0c94b", - "metadata": {}, - "outputs": [], - "source": [ - "#-------------------------------------------Data Preparation -------------------------------------------------------------------------#\n", - "def Remove_Outlier_Indices(df):\n", - " Q1 = df.quantile(0.25)\n", - " Q3 = df.quantile(0.75)\n", - " IQR = Q3 - Q1\n", - " trueList = ~((df < (Q1 - 1.5 * IQR)) |(df > (Q3 + 1.5 * IQR)))\n", - " return trueList\n", - "#-------------------------------------------Visualization-----------------------------------------------------------------------------#\n", - "\n", - "def plot_confu_matrix(cm, datatype=None, dataset=None, path = 'confusion_matrix.png'):\n", - " \"\"\"\n", - " Returns a matplotlib figure containing the plotted confusion matrix.\n", - "\n", - " Args:\n", - " cm (array, shape = [n, n]): a confusion matrix of integer classes\n", - " class_names (array, shape = [n]): String names of the integer classes\n", - " \"\"\"\n", - " fig = plt.figure(figsize=(8, 6)) # size in inches\n", - " # use plot(), etc. to create your plot.\n", - " df_cm = pd.DataFrame(cm, ('0','1'), ('0','1'))\n", - " sn.set(font_scale=1.4) # for label size\n", - " sn.heatmap(df_cm, annot=True, annot_kws={\"size\": 16},fmt=\"d\") # font size and decimal appearance\n", - " plt.xlabel('predicted')\n", - " plt.ylabel('true label')\n", - " if dataset is not None:\n", - " plt.title('conf_matrix based on {} data of {} dataset'.format(datatype,dataset))\n", - " #plt.show()\n", - " plt.savefig(path)\n", - " #return fig\n", - "#------------------------------------ Network Models ---------------------------------------------------------------------------------# \n", - "def denseModel():\n", - " input_shape = (cols-1)\n", - " dropout = 0.2\n", - " \n", - " inputs = tf.keras.Input(shape = input_shape) \n", - " x = layers.Flatten()(inputs)\n", - " x = layers.Dense(128)(x)\n", - " x = layers.Activation('relu')(x)\n", - " if dropout is not None:\n", - " x = layers.Dropout(rate = dropout)(x)\n", - "\n", - " x = layers.Dense(32)(x)\n", - " x = layers.Activation('relu')(x) \n", - " if dropout is not None:\n", - " x = layers.Dropout(rate = dropout)(x)\n", - "\n", - " x = layers.Dense(2)(x)\n", - "\n", - " outputs = layers.Activation('softmax')(x)\n", - " model = tf.keras.models.Model(inputs=inputs, outputs=outputs) \n", - " model.summary()\n", - " return model" - ] - }, - { - "cell_type": "markdown", - "id": "cdabfe56-4e2a-4481-aed9-3482dc4d2827", - "metadata": {}, - "source": [ - "# Main Code" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "80b94ebf", - "metadata": {}, - "outputs": [], - "source": [ - "#['A1','B1','C1','C3','D1','E1','F','G','H','I','D2','E2','A2','B2','C2','Target']\n", - "\n", - "# ----- IMPORT DATA --------\n", - "data_set = pd.read_csv('train.csv', header=0)\n" - ] - }, - { - "cell_type": "markdown", - "id": "4b975cf7-99ad-4d20-9b5a-31567ee5bc82", - "metadata": {}, - "source": [ - "Ziel:\n", - "Binäre Klassifikation von Daten, Zielvariable: Spalte \"Target\"\n", - "\n", - "A1, B1, C1, C3, D1, E1:\n", - "Anzahl der Treffer einer Datenbanksuche\n", - "\n", - "F, I:\n", - "Absolute Werte\n", - "\n", - "G:\n", - "Differenz vom Median von F (gruppiert nach einem fehlenden Wert)\n", - "\n", - "H:\n", - "Outlier von F (gruppiert nach einem fehlenden Wert)\n", - "\n", - "A2, B2, C2, D2, E2:\n", - "Ist der Quotient von A1, B1, C1, D1, E2 mit I\n", - "\n", - "--> Nutze: A2, B2, C2, D2, E2 und G/F und H? C3?\n" - ] - }, - { - "cell_type": "markdown", - "id": "149b0d93-35b8-439d-9da8-eacbf3bb8fb8", - "metadata": {}, - "source": [ - "## Data Preparation and visualization" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "id": "b790f18a-5486-469e-a23e-84d1d26c0a1c", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
A2B2C2C3D2E2FHTarget
count41131.00000041131.00000041131.00000041131.00000041131.00000041131.00000041131.00000041131.00000041131.000000
mean7.0491931.70822315.3163660.1593930.3875650.10668741.8768030.2409620.003185
std5.90701933.857118148.4654031.7982697.6838182.5323209.5197520.4276720.056346
min0.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.000000
25%2.4700000.0000000.0000000.0000000.0000000.00000036.1700000.0000000.000000
50%6.1100000.0000000.0000000.0000000.0000000.00000040.9400000.0000000.000000
75%9.7250000.0000000.0000000.0000000.0000000.00000047.3400000.0000000.000000
max54.2000002491.4600004206.460000203.000000287.360000294.46000099.8800001.0000001.000000
\n", - "
" - ], - "text/plain": [ - " A2 B2 C2 C3 D2 \\\n", - "count 41131.000000 41131.000000 41131.000000 41131.000000 41131.000000 \n", - "mean 7.049193 1.708223 15.316366 0.159393 0.387565 \n", - "std 5.907019 33.857118 148.465403 1.798269 7.683818 \n", - "min 0.000000 0.000000 0.000000 0.000000 0.000000 \n", - "25% 2.470000 0.000000 0.000000 0.000000 0.000000 \n", - "50% 6.110000 0.000000 0.000000 0.000000 0.000000 \n", - "75% 9.725000 0.000000 0.000000 0.000000 0.000000 \n", - "max 54.200000 2491.460000 4206.460000 203.000000 287.360000 \n", - "\n", - " E2 F H Target \n", - "count 41131.000000 41131.000000 41131.000000 41131.000000 \n", - "mean 0.106687 41.876803 0.240962 0.003185 \n", - "std 2.532320 9.519752 0.427672 0.056346 \n", - "min 0.000000 0.000000 0.000000 0.000000 \n", - "25% 0.000000 36.170000 0.000000 0.000000 \n", - "50% 0.000000 40.940000 0.000000 0.000000 \n", - "75% 0.000000 47.340000 0.000000 0.000000 \n", - "max 294.460000 99.880000 1.000000 1.000000 " - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# ---------- DELETE REDUNDANT FEATURES ---------------------------\n", - "data = data_set[['A2', 'B2', 'C2','C3', 'D2','E2', 'F', 'H', 'Target']] \n", - "data.describe()" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "id": "6db71475-6585-4caf-9cd3-88ec78f975df", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "118 out of 131 Samples with label \"1\" have been kept\n" - ] - } - ], - "source": [ - "# ----------------- REMOVE OUTLIER ---------------------------\n", - "''' Remove only Outlier for Features A2 and F because otherwise all or near to all samples with Label(Target) == 1 get removed! '''\n", - "cleaned = data\n", - "for colName in ['A2','F']:\n", - " # Index List of Non-Outliers\n", - " nonOutlierList = Remove_Outlier_Indices(cleaned[colName])\n", - " # Non-Outlier Subset of the Given Dataset\n", - " cleaned = cleaned[nonOutlierList]\n", - "\n", - "#--------- VISUALIZE CLEANED DATA ------------------- \n", - "c= 0\n", - "for i in cleaned.Target.iteritems():\n", - "\n", - " if i[1] == 1:\n", - " c+=1\n", - "\n", - "print(c, ' out of 131 Samples with label \"1\" have been kept')\n", - "# cleaned.describe()" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "id": "15348f4d-e561-41c0-a044-54a15fa8a309", - "metadata": {}, - "outputs": [], - "source": [ - "# ------------- MIN MAX NORMALIZATION --------------------------\n", - "# copy the data\n", - "scaled = cleaned.copy()\n", - "\n", - "# apply normalization techniques\n", - "for column in scaled.columns:\n", - " scaled[column] = (scaled[column] - scaled[column].abs().min()) / (scaled[column].abs().max() - scaled[column].abs().min())\n", - "\n", - "# view normalized data\n", - "#scaled.describe()\n" - ] - }, - { - "cell_type": "markdown", - "id": "a4ce8a39-37c6-403c-afdd-f509dfae3893", - "metadata": {}, - "source": [ - "### Upsampling for neural network " - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "id": "3d544edd-2013-4594-9baa-5a01bdfd083a", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "number of features: 8\n", - "Percentage of samples class 1: 0.44894467655957354\n" - ] - } - ], - "source": [ - "'''As the data set consists of less than 1 percent samples with label == 1, we simply extend the training set with multiple copies of those samples such that its percentage is ~ 50 % '''\n", - "\n", - "df = scaled\n", - "#shuffle data rows\n", - "df = df.sample(frac=1)\n", - "\n", - "#train test split\n", - "n = int(0.8 * len(df))\n", - "cols = len(df.columns)\n", - "print('number of features: ', cols-1)\n", - "train = df.iloc[0:n, :]\n", - "test = df.iloc[n: , :]\n", - "\n", - "#make copy of x_train for upsampling, this way we can use the original set for validation/analysis purposes later on\n", - "df_train = train.copy()\n", - "\n", - "# get row indices of samples with label '1'\n", - "c = 0\n", - "indices = []\n", - "for index, series in df_train.iterrows(): #Iterate over DataFrame rows as (index, Series) pairs.\n", - " if series.Target == 1:\n", - " c += 1\n", - " indices.append(index)\n", - " \n", - "samples =[]\n", - "for i in indices:\n", - " samples.append(df_train.loc[i])\n", - "samples = pd.DataFrame(samples)\n", - "\n", - "\n", - "Nupsample = 8\n", - "for n in range(Nupsample):\n", - " samples = samples.append(samples)\n", - "#append samples to original set\n", - "df_train = df_train.append(samples)\n", - "\n", - "print('Percentage of samples class 1: ',sum(df_train.Target)/len(df_train.Target))" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "id": "fdb8c63c-085f-436b-9122-6d4a201e92d9", - "metadata": {}, - "outputs": [], - "source": [ - "#df_train" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "be2079bf", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "number of samples class 1: 25974.0\n" - ] - } - ], - "source": [ - "# ------------ SOME LAST PREPARATION BEFORE TRAINIGN ---------------------------\n", - "\n", - "#split features and labels\n", - "x_train = df_train.iloc[ : , : cols-1]\n", - "y_train = df_train.iloc[ : , cols-1]\n", - "x_test = test.iloc[ : , : cols-1]\n", - "y_test = test.iloc[ : , cols-1]\n", - "\n", - "# ------------ ONE HOT ENCODE LABELS ------------------------------------------\n", - "Y_train = tf.keras.utils.to_categorical(y_train, 2)\n", - "Y_test = tf.keras.utils.to_categorical(y_test, 2)\n", - "print('number of samples class 1: ',sum(y_train)+sum(y_test))" - ] - }, - { - "cell_type": "markdown", - "id": "478ba50d-b225-489c-ada8-3b60b2ffa9d9", - "metadata": {}, - "source": [ - "## Build Network Model" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "id": "76d4e2c1", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Model: \"functional_5\"\n", - "_________________________________________________________________\n", - "Layer (type) Output Shape Param # \n", - "=================================================================\n", - "input_3 (InputLayer) [(None, 8)] 0 \n", - "_________________________________________________________________\n", - "flatten_2 (Flatten) (None, 8) 0 \n", - "_________________________________________________________________\n", - "dense_6 (Dense) (None, 128) 1152 \n", - "_________________________________________________________________\n", - "activation_6 (Activation) (None, 128) 0 \n", - "_________________________________________________________________\n", - "dropout_4 (Dropout) (None, 128) 0 \n", - "_________________________________________________________________\n", - "dense_7 (Dense) (None, 32) 4128 \n", - "_________________________________________________________________\n", - "activation_7 (Activation) (None, 32) 0 \n", - "_________________________________________________________________\n", - "dropout_5 (Dropout) (None, 32) 0 \n", - "_________________________________________________________________\n", - "dense_8 (Dense) (None, 2) 66 \n", - "_________________________________________________________________\n", - "activation_8 (Activation) (None, 2) 0 \n", - "=================================================================\n", - "Total params: 5,346\n", - "Trainable params: 5,346\n", - "Non-trainable params: 0\n", - "_________________________________________________________________\n" - ] - } - ], - "source": [ - "model = denseModel()\n", - "lr = 0.0001\n", - "optimizer = tf.keras.optimizers.Adam(lr=lr) \n", - " #beta_1 = config.beta_1, \n", - " #beta_2 = config.beta_2,\n", - " #epsilon = config.epsilon) \n", - "lossfct = tf.keras.losses.BinaryCrossentropy(from_logits = True)\n", - "model.compile(optimizer = optimizer, loss = lossfct)" - ] - }, - { - "cell_type": "markdown", - "id": "01ed1fe9-fd61-4c8b-b85e-6eaa7830601e", - "metadata": {}, - "source": [ - "## Train Model" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "id": "6ff3634f-6f71-4ab6-9d72-e895be0127bd", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Epoch 1/15\n", - "1768/1768 [==============================] - 2s 1ms/step - loss: 0.6266 - val_loss: 0.5676\n", - "Epoch 2/15\n", - "1768/1768 [==============================] - 2s 1ms/step - loss: 0.5557 - val_loss: 0.5279\n", - "Epoch 3/15\n", - "1768/1768 [==============================] - 2s 1ms/step - loss: 0.5248 - val_loss: 0.5132\n", - "Epoch 4/15\n", - "1768/1768 [==============================] - 2s 1ms/step - loss: 0.5152 - val_loss: 0.5085\n", - "Epoch 5/15\n", - "1768/1768 [==============================] - 2s 1ms/step - loss: 0.5123 - val_loss: 0.5078\n", - "Epoch 6/15\n", - "1768/1768 [==============================] - 2s 1ms/step - loss: 0.5109 - val_loss: 0.5084\n", - "Epoch 7/15\n", - "1768/1768 [==============================] - 2s 1ms/step - loss: 0.5102 - val_loss: 0.5077\n", - "Epoch 8/15\n", - "1768/1768 [==============================] - 2s 1ms/step - loss: 0.5096 - val_loss: 0.5075\n", - "Epoch 9/15\n", - "1768/1768 [==============================] - 2s 1ms/step - loss: 0.5092 - val_loss: 0.5077\n", - "Epoch 10/15\n", - "1768/1768 [==============================] - 2s 1ms/step - loss: 0.5090 - val_loss: 0.5073\n", - "Epoch 11/15\n", - "1768/1768 [==============================] - 2s 1ms/step - loss: 0.5087 - val_loss: 0.5077\n", - "Epoch 12/15\n", - "1768/1768 [==============================] - 2s 1ms/step - loss: 0.5085 - val_loss: 0.5075\n", - "Epoch 13/15\n", - "1768/1768 [==============================] - 2s 1ms/step - loss: 0.5083 - val_loss: 0.5078\n", - "Epoch 14/15\n", - "1768/1768 [==============================] - 2s 1ms/step - loss: 0.5081 - val_loss: 0.5072\n", - "Epoch 15/15\n", - "1768/1768 [==============================] - 2s 1ms/step - loss: 0.5080 - val_loss: 0.5072\n", - "saved training log\n" - ] - }, - { - "data": { - "text/plain": [ - "[]" - ] - }, - "execution_count": 35, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# -------------- TRAIN MODEL ---------------------------------------------------\n", - "history = model.fit(x_train , Y_train , epochs = 15 , validation_data = ( x_test , Y_test), batch_size = 32)\n", - "model.save(\"model.h5\")\n", - "log = pd.DataFrame(history.history)\n", - "log.to_csv(\"train_log.csv\",index=False)\n", - "print(\"saved training log\")\n", - "\n", - "# --------------- VISUALIZE TRAINING PROCESS ------------\n", - "plt.plot(history.history['loss'])\n", - "plt.plot(history.history['val_loss'])" - ] - }, - { - "cell_type": "markdown", - "id": "9521ecc0-7c24-4987-90e5-a6554a7360bf", - "metadata": {}, - "source": [ - "## Validation and Performance Analysis" - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "id": "1fb2a96b", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Accuracy on test data: 0.9917915309446254\n", - "Accuracy on train data: 0.9913000424388174\n" - ] - } - ], - "source": [ - "# ------ LOAD MODEL ---------\n", - "lmodel = tf.keras.models.load_model('model.h5')\n", - "\n", - "# ------- ACCURACIES ------------------------------\n", - "y_pred = np.argmax(lmodel.predict(x_test), axis=1)\n", - "y_pred_train = np.argmax(lmodel.predict(x_train), axis=1)\n", - "print('Accuracy on test data: ',metrics.accuracy_score(y_test,y_pred))\n", - "print('Accuracy on train data: ',metrics.accuracy_score(y_train,y_pred_train))" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "id": "a6383610-865c-4e62-acbc-3beee06d8a7a", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAfAAAAF/CAYAAAC2SpvrAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8QVMy6AAAACXBIWXMAAAsTAAALEwEAmpwYAAA6nElEQVR4nO3de1wVdf7H8RcKiHCkvCBYmhc0yTS8gKhpmCW7+8tKtOzijSTTTdBMrLRSt9TNW5RhhYlpZiZmWa3rrllZa4UGWZliphapIWReiOXIETi/P4w5nkXg0OHi2PvZYx6PzndmvnwgHr35fuc7Mx52u92OiIiImEq9ui5AREREqk4BLiIiYkIKcBERERNSgIuIiJiQAlxERMSEFOAiIiIm5FnXBVSXM8cO1nUJIm7zu/y6ui5BpFrYCg/XSL/u/r/eq1m7aqqk7mkELiIiYkIXzQhcRET+AEqK67qCC4YCXEREzMNeUtcVXDAU4CIiYh4lCvBSugYuIiJiQhqBi4iIadg1hW5QgIuIiHloCt2gABcREfPQCNygABcREfPQbWQGLWITERExIY3ARUTEPDSFblCAi4iIeWgRm0EBLiIipqHbyBx0DVxERMSENAIXERHz0BS6QQEuIiLmoSl0gwJcRETMQ/eBGxTgIiJiHhqBG7SITURExIQU4CIiYh4lJe5tVbB9+3Y6dux43u2GG24AIDMzk5EjR9K1a1f69+9PSkrK/5RbwuLFi+nXrx+hoaGMGTOGrKwsp2Mq66M8CnARETEPe4l7WxV069aNbdu2OW3Lly/H09OTcePGcfz4cWJiYmjdujXr169n0qRJLF68mNTUVKOPJUuWsGbNGmbPns3atWupX78+sbGxFBYWArjUR3l0DVxERMyjFm8j8/b2JiAgwPh85swZ5s6dy8CBAxk2bBgvvvgiXl5ezJo1C09PT4KDg8nKymLp0qUMGzYMm83G8uXLSUhIIDIyEoDExET69u3Lpk2bGDx4MKmpqRX2URGNwEVExDTs9mK3NnesWrWK7Oxspk2bBkB6ejphYWF4ejrGwhERERw6dIicnBwyMzMpKCigV69exn6LxUKnTp1IT093qY+KKMBFREQqYbVaSU5OZtSoUQQGBgKQk5NDUFCQ03HNmzcHIDs72wjg0uPPPSY7O9ulPiqiKXQRETEPN28jy8vLIy8vr0y7v78//v7+5Z739ttvU1hYyKhRo4y206dP4+3t7XRc6efCwkKsVqtT27nH2Gw2l/qoiAJcRETMw81r4CtXriQpKalMe1xcHPHx8eWe9/bbbzNw4ECaNGlitPn4+BhBXKr0s6+vLz4+PkbbuSFts9nw9fV1qY+KKMBFRMQ83ByBjx49mujo6DLtFY2+jx8/zpdffsn48eOd2oOCgsjNzXVqK/0cFBSE3W432iwWi9Mx7du3d6mPiijARUTkD6OyqfLz+eKLL/Dw8CA8PNypPTw8nNWrV1NUVGQsQktLS6NNmzYEBARwySWXYLFY2LFjB+3atQMgPz+fPXv2cPfdd7vUR0W0iE1ERMyjpNi97XfYs2cPrVq1KjOlPXToUKxWK9OnT2f//v1s2LCBFStWMG7cOODstewRI0aQmJjIli1b2Lt3L5MnTyYwMJCoqCiX+qiIRuAiImIedfAs9J9//plLLrmkTHvTpk1JSUlhzpw5REdHExAQwJQpUxgyZIhxzMSJEykuLmbGjBlYrVZ69OjBsmXLjGvirvRRHg976SS9yZ05drCuSxBxm9/l19V1CSLVwlZ4uEb6PZ221q3zfXrdUU2V1D2NwEVExDz0NjKDroGLiIiYkEbgIiJiHrX4LPQLnQJcRETMQwFuUICLiIhpuPtCkouJroGLiIiYkEbgIiJiHppCNyjARUTEPHQbmUEBLiIi5qERuEEBLiIi5qERuEGL2ERERExII3ARETEPTaEbFOAiImIemkI3KMBFRMQ8NAI3KMBFRMQ8FOAGLWITERExIY3ARUTEPHQN3KAAFxER89AUukEBLiIi5qERuEHXwEVERExII3ARETEPTaEbFOAiImIemkI3KMBFRMQ8NAI3KMBFRMQ8FOAGLWITERExIY3ARUTEPOz2uq7ggqEAFxER89AUukEBLiIi5qEANyjARUTEPHQbmUGL2ERERExII3ARETEPTaEbNAIXERHzsNvd236HDRs28H//93906dKFm266iU2bNhn7MjMzGTlyJF27dqV///6kpKQ4nVtSUsLixYvp168foaGhjBkzhqysLKdjKuujPApwERExj5IS97Yqevvtt5k+fTp33HEH//jHPxg0aBAPPvggGRkZHD9+nJiYGFq3bs369euZNGkSixcvJjU11Th/yZIlrFmzhtmzZ7N27Vrq169PbGwshYWFAC71UR5N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/srenDqVx4zHH6zrckRcUtHvbZcuVwHgWb8+H2x5g169epCTc4x585N4MXllXZQrVeDubWSjR48mOjq6TLu/v3+553z++efExcVx2WWXkZycjJeXFz4+PkYQlyr97Ovri4+Pj9F2bkjbbDZ8fX0BKu2jMgpwqdBPPx2t6xJEqqyi39uAgKYUFRXx1psreDF5JU/OTuTWW/9M0nNz+eX4Cdate6cWK5Xa5u/vX2FY/6933nmH6dOn07NnTxYvXmxMqQcFBZGbm+t0bOnnoKAg7Ha70XbuNHxubi7t27d3qY/K6Bq4iPyheHl54enpybKUV3lq3nN8uPUTHpj8OBs3buHxxybXdXlSidq8D/zdd9/loYce4i9/+QvJyclOQRweHk5GRobTGou0tDTatGlDQEAAISEhWCwWduzYYezPz89nz5499OzZ06U+KlOrI/C7777b5VXMq1evrvwgEZEqys//LwD//vdWp/Yt73/Mgj/NwMvLizNnztRBZeKK2noS29GjR3n88ceJiIhg6tSpnDx50tjn5eXF0KFDWbZsGdOnT+e+++7jm2++YcWKFcycORM4ey17xIgRJCYm0qxZM1q2bMmiRYsIDAwkKioKoNI+KlOrAR4ZGckzzzxDu3btuOaaa2rzS4uIAHDgwA8AeHt7ObV7eXni4eFBSYke1nkhq+oo+vfavHkzVquVtLQ0+vVzvjuhe/furFmzhpSUFObMmUN0dDQBAQFMmTKFIUOGGMdNnDiR4uJiZsyYgdVqpUePHixbtsy4Jt60adNK+6hIrQb4uHHjsFgsLFq0iOTkZFq2bFmbX15EhI//k4bVamXo0EF88unnRvv//eVG0tO/ori4uA6rk8rU1p9Xo0aNYtSoURUe06VLF15//fVy99evX5+EhAQSEhJ+dx8VqfVFbMOHD+c///kPzzzzDAsXLqztLy8if3C//prPU/OSmPH4g/z6az4ff5zG7bffzHXX9eLmW0bWdXkiLquTVehPPPEEu3fvrosvLSLCnLnPcOpUHhPuH8OUB8ez77uD3H7HWP69eWtdlyaVKLHrjeClPOz2i+On4el9eV2XICIivymyHamRfke0du36cHlezXqzmiqpe7oPXERETMPdJ7FdTHQfuIiIiAlpBC4iIqZRW7eRmYECXERETEN36TsowEVExDR0DdxBAS4iIqahKXQHLWIT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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# ---------- CONFUSION MATRIX -----------------\n", - "y_pred = np.argmax(lmodel.predict(x_test), axis=1)\n", - "\n", - "cm = metrics.confusion_matrix(y_true = y_test,y_pred = y_pred)\n", - "plot_confu_matrix(cm)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.8" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -}