diff --git "a/AutoEncoderTestConnected.ipynb" "b/AutoEncoderTestConnected.ipynb"
new file mode 100644--- /dev/null
+++ "b/AutoEncoderTestConnected.ipynb"
@@ -0,0 +1,1705 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Auto Encoder Developement"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "4d48baab",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "import pandas as pd\n",
+ "import pandas as pd\n",
+ "import numpy as np\n",
+ "import matplotlib.pyplot as plt\n",
+ "import seaborn as sns\n",
+ "import tensorflow as tf\n",
+ "from tensorflow import keras\n",
+ "from tensorflow.keras import layers\n",
+ "from tensorflow.keras.models import Model\n",
+ "import keras_tuner as kt\n",
+ "from keras.wrappers.scikit_learn import KerasRegressor\n",
+ "from sklearn.model_selection import KFold,GridSearchCV,RandomizedSearchCV,train_test_split,StratifiedKFold\n",
+ "from sklearn.metrics import confusion_matrix,accuracy_score,r2_score,roc_auc_score,precision_score,recall_score,f1_score,mean_squared_error\n",
+ "from jupyterthemes import jtplot\n",
+ "jtplot.style(theme='monokai', context='notebook', ticks=True, grid=True)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 46,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from pathlib import Path"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " remaining_cycles | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " 191 | \n",
+ "
\n",
+ " \n",
+ " 1 | \n",
+ " 190 | \n",
+ "
\n",
+ " \n",
+ " 2 | \n",
+ " 189 | \n",
+ "
\n",
+ " \n",
+ " 3 | \n",
+ " 188 | \n",
+ "
\n",
+ " \n",
+ " 4 | \n",
+ " 187 | \n",
+ "
\n",
+ " \n",
+ " ... | \n",
+ " ... | \n",
+ "
\n",
+ " \n",
+ " 20626 | \n",
+ " 4 | \n",
+ "
\n",
+ " \n",
+ " 20627 | \n",
+ " 3 | \n",
+ "
\n",
+ " \n",
+ " 20628 | \n",
+ " 2 | \n",
+ "
\n",
+ " \n",
+ " 20629 | \n",
+ " 1 | \n",
+ "
\n",
+ " \n",
+ " 20630 | \n",
+ " 0 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
20631 rows × 1 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " remaining_cycles\n",
+ "0 191\n",
+ "1 190\n",
+ "2 189\n",
+ "3 188\n",
+ "4 187\n",
+ "... ...\n",
+ "20626 4\n",
+ "20627 3\n",
+ "20628 2\n",
+ "20629 1\n",
+ "20630 0\n",
+ "\n",
+ "[20631 rows x 1 columns]"
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "df = pd.read_csv('traininglabels.csv')\n",
+ "df.drop(columns='Unnamed: 0')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 48,
+ "id": "f48dd172",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "col_names = ['id', 'cycle', 'setting1', 'setting2', 'setting3', 'T2', 'T24'\n",
+ " , 'T30', 'T50','P2', 'P15', 'P30', 'Nf', 'Nc', 'epr', 'Ps30'\n",
+ " , 'phi', 'NRf', 'NRc', 'BPR','farB', 'htBleed', 'Nf_dmd',\n",
+ " 'PCNfR_dmd','W31', 'W32', 's22', 's23']"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cc90d235",
+ "metadata": {},
+ "source": [
+ "Import the training, test, and remaining useful life data and remove all NaN values."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 49,
+ "id": "b1cb9faf",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " remaining_cycles | \n",
+ " Nan | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " 112 | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " 1 | \n",
+ " 98 | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " 2 | \n",
+ " 69 | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " 3 | \n",
+ " 82 | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " 4 | \n",
+ " 91 | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " remaining_cycles Nan\n",
+ "0 112 NaN\n",
+ "1 98 NaN\n",
+ "2 69 NaN\n",
+ "3 82 NaN\n",
+ "4 91 NaN"
+ ]
+ },
+ "execution_count": 49,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "train = pd.read_csv(\"train.txt\", sep=' ', names=col_names)\n",
+ "test = pd.read_csv(\"test.txt\", sep=' ', names=col_names)\n",
+ "RUL = pd.read_csv(\"RUL.txt\", sep=' ', names=['remaining_cycles', 'Nan'])\n",
+ "RUL.head()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 50,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "train.to_csv('testin123.txt')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 51,
+ "id": "a9224d1f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "train.drop(columns=['s22', 's23'], axis=1, inplace=True)\n",
+ "test.drop(columns=['s22', 's23'], axis=1, inplace=True)\n",
+ "RUL.drop(columns=['Nan'], axis=1, inplace=True)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 52,
+ "id": "be6ccb37",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " remaining_cycles | \n",
+ " id | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " 112 | \n",
+ " 1 | \n",
+ "
\n",
+ " \n",
+ " 1 | \n",
+ " 98 | \n",
+ " 2 | \n",
+ "
\n",
+ " \n",
+ " 2 | \n",
+ " 69 | \n",
+ " 3 | \n",
+ "
\n",
+ " \n",
+ " 3 | \n",
+ " 82 | \n",
+ " 4 | \n",
+ "
\n",
+ " \n",
+ " 4 | \n",
+ " 91 | \n",
+ " 5 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " remaining_cycles id\n",
+ "0 112 1\n",
+ "1 98 2\n",
+ "2 69 3\n",
+ "3 82 4\n",
+ "4 91 5"
+ ]
+ },
+ "execution_count": 52,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "RUL['id'] = RUL.index + 1\n",
+ "\n",
+ "RUL.head()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f00a7399",
+ "metadata": {},
+ "source": [
+ "The dataset is made up of sensor data for 100 different engines, as can be seen below."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 53,
+ "id": "1bc5c3d4",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Engine IDs: [ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18\n",
+ " 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36\n",
+ " 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54\n",
+ " 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72\n",
+ " 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90\n",
+ " 91 92 93 94 95 96 97 98 99 100]\n"
+ ]
+ }
+ ],
+ "source": [
+ "print('Engine IDs:', train.id.unique())"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a1ad2e86",
+ "metadata": {},
+ "source": [
+ "## Processing Data"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "49eb2c6e",
+ "metadata": {},
+ "source": [
+ "A testing dataset is provided where the engines are not ran until failure, and a complimentary vector is provided for the remaining useful life (RUL) for each engine ID. In order to match the engines in the test set with their corresponding RUL, we must concatenate the two datasets."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f34cf0cb",
+ "metadata": {},
+ "source": [
+ "Since the engines in the test set are ran until failure, you can calculate the remaining cycles until failure by subtracting the current cycle from the maximum cycle for each engine ID. He does this for the test set as well. Since the remaining useful life for all the test engines are given, as well as their current cycle, the maximum cycles for each engine can be calculated."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 54,
+ "id": "f53a4ce3",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "train['remaining_cycles'] = train.groupby(['id'])['cycle'].transform(max)-train['cycle']"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 55,
+ "id": "fb095086",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " id | \n",
+ " cycle | \n",
+ " setting1 | \n",
+ " setting2 | \n",
+ " setting3 | \n",
+ " T2 | \n",
+ " T24 | \n",
+ " T30 | \n",
+ " T50 | \n",
+ " P2 | \n",
+ " ... | \n",
+ " NRf | \n",
+ " NRc | \n",
+ " BPR | \n",
+ " farB | \n",
+ " htBleed | \n",
+ " Nf_dmd | \n",
+ " PCNfR_dmd | \n",
+ " W31 | \n",
+ " W32 | \n",
+ " remaining_cycles | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " 1 | \n",
+ " 1 | \n",
+ " -0.0007 | \n",
+ " -0.0004 | \n",
+ " 100.0 | \n",
+ " 518.67 | \n",
+ " 641.82 | \n",
+ " 1589.70 | \n",
+ " 1400.60 | \n",
+ " 14.62 | \n",
+ " ... | \n",
+ " 2388.02 | \n",
+ " 8138.62 | \n",
+ " 8.4195 | \n",
+ " 0.03 | \n",
+ " 392 | \n",
+ " 2388 | \n",
+ " 100.0 | \n",
+ " 39.06 | \n",
+ " 23.4190 | \n",
+ " 191 | \n",
+ "
\n",
+ " \n",
+ " 1 | \n",
+ " 1 | \n",
+ " 2 | \n",
+ " 0.0019 | \n",
+ " -0.0003 | \n",
+ " 100.0 | \n",
+ " 518.67 | \n",
+ " 642.15 | \n",
+ " 1591.82 | \n",
+ " 1403.14 | \n",
+ " 14.62 | \n",
+ " ... | \n",
+ " 2388.07 | \n",
+ " 8131.49 | \n",
+ " 8.4318 | \n",
+ " 0.03 | \n",
+ " 392 | \n",
+ " 2388 | \n",
+ " 100.0 | \n",
+ " 39.00 | \n",
+ " 23.4236 | \n",
+ " 190 | \n",
+ "
\n",
+ " \n",
+ " 2 | \n",
+ " 1 | \n",
+ " 3 | \n",
+ " -0.0043 | \n",
+ " 0.0003 | \n",
+ " 100.0 | \n",
+ " 518.67 | \n",
+ " 642.35 | \n",
+ " 1587.99 | \n",
+ " 1404.20 | \n",
+ " 14.62 | \n",
+ " ... | \n",
+ " 2388.03 | \n",
+ " 8133.23 | \n",
+ " 8.4178 | \n",
+ " 0.03 | \n",
+ " 390 | \n",
+ " 2388 | \n",
+ " 100.0 | \n",
+ " 38.95 | \n",
+ " 23.3442 | \n",
+ " 189 | \n",
+ "
\n",
+ " \n",
+ " 3 | \n",
+ " 1 | \n",
+ " 4 | \n",
+ " 0.0007 | \n",
+ " 0.0000 | \n",
+ " 100.0 | \n",
+ " 518.67 | \n",
+ " 642.35 | \n",
+ " 1582.79 | \n",
+ " 1401.87 | \n",
+ " 14.62 | \n",
+ " ... | \n",
+ " 2388.08 | \n",
+ " 8133.83 | \n",
+ " 8.3682 | \n",
+ " 0.03 | \n",
+ " 392 | \n",
+ " 2388 | \n",
+ " 100.0 | \n",
+ " 38.88 | \n",
+ " 23.3739 | \n",
+ " 188 | \n",
+ "
\n",
+ " \n",
+ " 4 | \n",
+ " 1 | \n",
+ " 5 | \n",
+ " -0.0019 | \n",
+ " -0.0002 | \n",
+ " 100.0 | \n",
+ " 518.67 | \n",
+ " 642.37 | \n",
+ " 1582.85 | \n",
+ " 1406.22 | \n",
+ " 14.62 | \n",
+ " ... | \n",
+ " 2388.04 | \n",
+ " 8133.80 | \n",
+ " 8.4294 | \n",
+ " 0.03 | \n",
+ " 393 | \n",
+ " 2388 | \n",
+ " 100.0 | \n",
+ " 38.90 | \n",
+ " 23.4044 | \n",
+ " 187 | \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",
+ " 20626 | \n",
+ " 100 | \n",
+ " 196 | \n",
+ " -0.0004 | \n",
+ " -0.0003 | \n",
+ " 100.0 | \n",
+ " 518.67 | \n",
+ " 643.49 | \n",
+ " 1597.98 | \n",
+ " 1428.63 | \n",
+ " 14.62 | \n",
+ " ... | \n",
+ " 2388.26 | \n",
+ " 8137.60 | \n",
+ " 8.4956 | \n",
+ " 0.03 | \n",
+ " 397 | \n",
+ " 2388 | \n",
+ " 100.0 | \n",
+ " 38.49 | \n",
+ " 22.9735 | \n",
+ " 4 | \n",
+ "
\n",
+ " \n",
+ " 20627 | \n",
+ " 100 | \n",
+ " 197 | \n",
+ " -0.0016 | \n",
+ " -0.0005 | \n",
+ " 100.0 | \n",
+ " 518.67 | \n",
+ " 643.54 | \n",
+ " 1604.50 | \n",
+ " 1433.58 | \n",
+ " 14.62 | \n",
+ " ... | \n",
+ " 2388.22 | \n",
+ " 8136.50 | \n",
+ " 8.5139 | \n",
+ " 0.03 | \n",
+ " 395 | \n",
+ " 2388 | \n",
+ " 100.0 | \n",
+ " 38.30 | \n",
+ " 23.1594 | \n",
+ " 3 | \n",
+ "
\n",
+ " \n",
+ " 20628 | \n",
+ " 100 | \n",
+ " 198 | \n",
+ " 0.0004 | \n",
+ " 0.0000 | \n",
+ " 100.0 | \n",
+ " 518.67 | \n",
+ " 643.42 | \n",
+ " 1602.46 | \n",
+ " 1428.18 | \n",
+ " 14.62 | \n",
+ " ... | \n",
+ " 2388.24 | \n",
+ " 8141.05 | \n",
+ " 8.5646 | \n",
+ " 0.03 | \n",
+ " 398 | \n",
+ " 2388 | \n",
+ " 100.0 | \n",
+ " 38.44 | \n",
+ " 22.9333 | \n",
+ " 2 | \n",
+ "
\n",
+ " \n",
+ " 20629 | \n",
+ " 100 | \n",
+ " 199 | \n",
+ " -0.0011 | \n",
+ " 0.0003 | \n",
+ " 100.0 | \n",
+ " 518.67 | \n",
+ " 643.23 | \n",
+ " 1605.26 | \n",
+ " 1426.53 | \n",
+ " 14.62 | \n",
+ " ... | \n",
+ " 2388.23 | \n",
+ " 8139.29 | \n",
+ " 8.5389 | \n",
+ " 0.03 | \n",
+ " 395 | \n",
+ " 2388 | \n",
+ " 100.0 | \n",
+ " 38.29 | \n",
+ " 23.0640 | \n",
+ " 1 | \n",
+ "
\n",
+ " \n",
+ " 20630 | \n",
+ " 100 | \n",
+ " 200 | \n",
+ " -0.0032 | \n",
+ " -0.0005 | \n",
+ " 100.0 | \n",
+ " 518.67 | \n",
+ " 643.85 | \n",
+ " 1600.38 | \n",
+ " 1432.14 | \n",
+ " 14.62 | \n",
+ " ... | \n",
+ " 2388.26 | \n",
+ " 8137.33 | \n",
+ " 8.5036 | \n",
+ " 0.03 | \n",
+ " 396 | \n",
+ " 2388 | \n",
+ " 100.0 | \n",
+ " 38.37 | \n",
+ " 23.0522 | \n",
+ " 0 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
20631 rows × 27 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " id cycle setting1 setting2 setting3 T2 T24 T30 \\\n",
+ "0 1 1 -0.0007 -0.0004 100.0 518.67 641.82 1589.70 \n",
+ "1 1 2 0.0019 -0.0003 100.0 518.67 642.15 1591.82 \n",
+ "2 1 3 -0.0043 0.0003 100.0 518.67 642.35 1587.99 \n",
+ "3 1 4 0.0007 0.0000 100.0 518.67 642.35 1582.79 \n",
+ "4 1 5 -0.0019 -0.0002 100.0 518.67 642.37 1582.85 \n",
+ "... ... ... ... ... ... ... ... ... \n",
+ "20626 100 196 -0.0004 -0.0003 100.0 518.67 643.49 1597.98 \n",
+ "20627 100 197 -0.0016 -0.0005 100.0 518.67 643.54 1604.50 \n",
+ "20628 100 198 0.0004 0.0000 100.0 518.67 643.42 1602.46 \n",
+ "20629 100 199 -0.0011 0.0003 100.0 518.67 643.23 1605.26 \n",
+ "20630 100 200 -0.0032 -0.0005 100.0 518.67 643.85 1600.38 \n",
+ "\n",
+ " T50 P2 ... NRf NRc BPR farB htBleed Nf_dmd \\\n",
+ "0 1400.60 14.62 ... 2388.02 8138.62 8.4195 0.03 392 2388 \n",
+ "1 1403.14 14.62 ... 2388.07 8131.49 8.4318 0.03 392 2388 \n",
+ "2 1404.20 14.62 ... 2388.03 8133.23 8.4178 0.03 390 2388 \n",
+ "3 1401.87 14.62 ... 2388.08 8133.83 8.3682 0.03 392 2388 \n",
+ "4 1406.22 14.62 ... 2388.04 8133.80 8.4294 0.03 393 2388 \n",
+ "... ... ... ... ... ... ... ... ... ... \n",
+ "20626 1428.63 14.62 ... 2388.26 8137.60 8.4956 0.03 397 2388 \n",
+ "20627 1433.58 14.62 ... 2388.22 8136.50 8.5139 0.03 395 2388 \n",
+ "20628 1428.18 14.62 ... 2388.24 8141.05 8.5646 0.03 398 2388 \n",
+ "20629 1426.53 14.62 ... 2388.23 8139.29 8.5389 0.03 395 2388 \n",
+ "20630 1432.14 14.62 ... 2388.26 8137.33 8.5036 0.03 396 2388 \n",
+ "\n",
+ " PCNfR_dmd W31 W32 remaining_cycles \n",
+ "0 100.0 39.06 23.4190 191 \n",
+ "1 100.0 39.00 23.4236 190 \n",
+ "2 100.0 38.95 23.3442 189 \n",
+ "3 100.0 38.88 23.3739 188 \n",
+ "4 100.0 38.90 23.4044 187 \n",
+ "... ... ... ... ... \n",
+ "20626 100.0 38.49 22.9735 4 \n",
+ "20627 100.0 38.30 23.1594 3 \n",
+ "20628 100.0 38.44 22.9333 2 \n",
+ "20629 100.0 38.29 23.0640 1 \n",
+ "20630 100.0 38.37 23.0522 0 \n",
+ "\n",
+ "[20631 rows x 27 columns]"
+ ]
+ },
+ "execution_count": 55,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "train"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 56,
+ "id": "1b33f6b4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Maximum cycles = cycles at test end + remaining useful life\n",
+ "\n",
+ "maxCycles = pd.DataFrame(test.groupby('id')['cycle'].max()).reset_index()\n",
+ "maxCycles.columns = ['id', 'max_tested']\n",
+ "maxCycles['max_cycles'] = RUL['remaining_cycles'] + maxCycles['max_tested']\n",
+ "maxCycles.drop(['max_tested'], axis=1, inplace=True)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 57,
+ "id": "50f53584",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " id | \n",
+ " max_cycles | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " 1 | \n",
+ " 143 | \n",
+ "
\n",
+ " \n",
+ " 1 | \n",
+ " 2 | \n",
+ " 147 | \n",
+ "
\n",
+ " \n",
+ " 2 | \n",
+ " 3 | \n",
+ " 195 | \n",
+ "
\n",
+ " \n",
+ " 3 | \n",
+ " 4 | \n",
+ " 188 | \n",
+ "
\n",
+ " \n",
+ " 4 | \n",
+ " 5 | \n",
+ " 189 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " id max_cycles\n",
+ "0 1 143\n",
+ "1 2 147\n",
+ "2 3 195\n",
+ "3 4 188\n",
+ "4 5 189"
+ ]
+ },
+ "execution_count": 57,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "maxCycles.head()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 58,
+ "id": "4a58ed0c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test = test.merge(maxCycles, on=['id'], how='left')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 59,
+ "id": "a8f89b67",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test['remaining_cycles'] = test['max_cycles'] - test['cycle']\n",
+ "test.drop(['max_cycles'], axis=1, inplace=True)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 60,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# X = train.drop(['id', 'setting3', 'P2', 'P15', 'epr', 'htBleed', 'PCNfR_dmd', 'W31',\n",
+ "# 'remaining_cycles'], axis=1)\n",
+ "# X_test = test.drop(['id', 'setting3', 'P2', 'P15', 'epr', 'htBleed', 'PCNfR_dmd', 'W31',\n",
+ "# 'remaining_cycles'], axis=1)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 61,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "X = train.drop(['id', 'cycle', 'setting2', 'setting3', 'T2', 'T24', 'epr', 'farB', 'Nf_dmd', 'PCNfR_dmd',\n",
+ " 'remaining_cycles'], axis=1)\n",
+ "X_test = test.drop(['id', 'cycle', 'setting2', 'setting3', 'T2', 'T24', 'epr', 'farB', 'Nf_dmd', 'PCNfR_dmd',\n",
+ " 'remaining_cycles'], axis=1)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 62,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "C:\\Users\\Arash\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python39\\site-packages\\sklearn\\preprocessing\\_data.py:3251: RuntimeWarning: divide by zero encountered in log\n",
+ " loglike = -n_samples / 2 * np.log(x_trans.var())\n"
+ ]
+ }
+ ],
+ "source": [
+ "from sklearn.preprocessing import MinMaxScaler, PowerTransformer\n",
+ "gen = MinMaxScaler(feature_range=(0,1))\n",
+ "X = gen.fit_transform(X)\n",
+ "X = pd.DataFrame(X)\n",
+ "X = np.nan_to_num(X)\n",
+ "\n",
+ "pt = PowerTransformer()\n",
+ "X = pt.fit_transform(X)\n",
+ "X = np.array(X)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 63,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "y_test = test.remaining_cycles"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 64,
+ "id": "0607bc22",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "C:\\Users\\Arash\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python39\\site-packages\\sklearn\\preprocessing\\_data.py:3251: RuntimeWarning: divide by zero encountered in log\n",
+ " loglike = -n_samples / 2 * np.log(x_trans.var())\n"
+ ]
+ }
+ ],
+ "source": [
+ "gen2 = MinMaxScaler(feature_range=(0,1))\n",
+ "X_test = gen.fit_transform(X_test)\n",
+ "X_test = pd.DataFrame(X_test)\n",
+ "X_test = np.nan_to_num(X_test)\n",
+ "pt = PowerTransformer()\n",
+ "X_test = pt.fit_transform(X_test)\n",
+ "X_test = np.array(X_test)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 65,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "class AutoEncoder(Model):\n",
+ " def __init__(self, latent_dim, input_dim):\n",
+ " super(AutoEncoder, self).__init__()\n",
+ " self.latent_dim = latent_dim\n",
+ " self.encoder = tf.keras.Sequential([\n",
+ " # layers.Dense(16*latent_dim, activation = \"relu\"),\n",
+ " # layers.Dense(8*latent_dim, activation = \"relu\"),\n",
+ " # layers.Dense(4*latent_dim, activation = \"relu\"),\n",
+ " layers.Dense(2*latent_dim, activation = \"relu\"),\n",
+ " layers.Dense(latent_dim, activation = \"relu\"),\n",
+ " ])\n",
+ " self.decoder = tf.keras.Sequential([\n",
+ " layers.Dense(2*latent_dim, activation = \"relu\"),\n",
+ " # layers.Dense(4*latent_dim, activation = \"relu\"),\n",
+ " # layers.Dense(8*latent_dim, activation = \"relu\"),\n",
+ " # layers.Dense(16*latent_dim, activation = \"relu\"),\n",
+ " layers.Dense(input_dim, activation = \"relu\"), \n",
+ " ])\n",
+ " \n",
+ " def call(self, x):\n",
+ " encoded = self.encoder(x)\n",
+ " decoded = self.decoder(encoded)\n",
+ " return decoded"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 66,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def find_latent_dims(AutoEncoder, latent_dim):\n",
+ " tf.keras.backend.clear_session()\n",
+ " callback = tf.keras.callbacks.EarlyStopping(monitor='val_loss', min_delta=0, patience=10)\n",
+ " autoencoder = AutoEncoder(latent_dim, X.shape[1])\n",
+ " autoencoder.compile(optimizer=\"adam\", loss=\"mean_squared_error\")\n",
+ " history = autoencoder.fit(X, X, epochs=1000, shuffle=True, validation_data=(X, X), verbose=False, callbacks=callback)\n",
+ " return history"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 67,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "latent_dim = 11\n",
+ "\n",
+ "tf.keras.backend.clear_session()\n",
+ "callback = tf.keras.callbacks.EarlyStopping(monitor='val_loss', min_delta=0, patience=10)\n",
+ "autoencoder = AutoEncoder(latent_dim, X.shape[1])\n",
+ "autoencoder.compile(optimizer=\"adam\", loss=\"mean_squared_error\")\n",
+ "history = autoencoder.fit(X, X, epochs=1000, shuffle=True, validation_data=(X, X), verbose=False, callbacks=callback)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 68,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(13096, 16)"
+ ]
+ },
+ "execution_count": 68,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "X_test.shape"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 69,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "410/410 [==============================] - 0s 506us/step - loss: 0.0000e+00\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "0.0"
+ ]
+ },
+ "execution_count": 69,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "autoencoder.evaluate(X_test)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 70,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# latent_dim = np.arange(X.shape[1]) + 1\n",
+ "\n",
+ "# lossSave = []\n",
+ "# lowestLoss = []\n",
+ "# i = 0\n",
+ "# for dim in latent_dim:\n",
+ "# history = find_latent_dims(AutoEncoder, dim)\n",
+ "# lossSave.append(history.history['loss'])\n",
+ "# lowestLoss.append(lossSave[i][-1])\n",
+ "# i += 1"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 71,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# plt.figure(figsize=(20,20))\n",
+ "# plt.scatter(range(len(lowestLoss)), lowestLoss) \n",
+ "# plt.xlabel(\"Number of Latent Dimensions\")\n",
+ "# plt.ylabel(\"Mean Squared Error\")\n",
+ "# plt.show()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 72,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# plt.figure(figsize=(20,20))\n",
+ "# for losses in lossSave:\n",
+ "# plt.plot(losses) \n",
+ "# plt.xlabel(\"Epochs\")\n",
+ "# plt.ylabel(\"Mean Squared Error\")\n",
+ "# plt.legend(latent_dim)\n",
+ "# plt.show()\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 73,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def plot_loss(fit):\n",
+ " plt.figure(figsize=(16,9))\n",
+ " plt.plot(fit.history['loss'], label='loss')\n",
+ " plt.plot(fit.history['val_loss'], label='val_loss')\n",
+ " plt.xlabel('Epoch')\n",
+ " plt.ylabel('Remaining Cycles Error')\n",
+ " plt.legend(loc=0, prop={'size':26})\n",
+ " plt.grid(True)\n",
+ " plt.show()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 74,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def make_fully_connected_model(autoencoder, loss_type, activation_type):\n",
+ " autoencoder.encoder.trainable = False\n",
+ " model = keras.Sequential([autoencoder.encoder,\n",
+ " layers.Dense(512, kernel_initializer= \"glorot_normal\", activation=activation_type),\n",
+ " layers.BatchNormalization(axis=1),\n",
+ " layers.Dense(256, kernel_initializer= \"glorot_normal\", activation=activation_type),\n",
+ " layers.BatchNormalization(axis=1),\n",
+ " layers.Dense(128, kernel_initializer= \"glorot_normal\", activation=activation_type),\n",
+ " layers.BatchNormalization(axis=1),\n",
+ " layers.Dense(64, kernel_initializer= \"glorot_normal\", activation=activation_type),\n",
+ " layers.Dropout(0.5),\n",
+ " layers.BatchNormalization(axis=1),\n",
+ " layers.Dense(16, kernel_initializer= \"glorot_normal\", activation=activation_type),\n",
+ " layers.Dense(1, kernel_initializer= \"glorot_normal\", activation=\"linear\")])\n",
+ " model.compile(loss=loss_type, optimizer=keras.optimizers.Adam(learning_rate=0.001))\n",
+ " return model"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 75,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Model: \"auto_encoder\"\n",
+ "_________________________________________________________________\n",
+ "Layer (type) Output Shape Param # \n",
+ "=================================================================\n",
+ "sequential (Sequential) (20631, 11) 627 \n",
+ "_________________________________________________________________\n",
+ "sequential_1 (Sequential) (20631, 16) 632 \n",
+ "=================================================================\n",
+ "Total params: 1,259\n",
+ "Trainable params: 1,259\n",
+ "Non-trainable params: 0\n",
+ "_________________________________________________________________\n"
+ ]
+ }
+ ],
+ "source": [
+ "latent_dim = 11\n",
+ "tf.keras.backend.clear_session()\n",
+ "autoencoder = AutoEncoder(latent_dim, X.shape[1])\n",
+ "autoencoder.compile(optimizer=\"adam\", loss=\"mean_squared_error\")\n",
+ "autoencoder.build(X.shape)\n",
+ "autoencoder.summary()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 76,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Epoch 1/1000\n",
+ "645/645 [==============================] - 1s 926us/step - loss: 0.7004 - val_loss: 0.6486\n",
+ "Epoch 2/1000\n",
+ "645/645 [==============================] - 1s 827us/step - loss: 0.6314 - val_loss: 0.6116\n",
+ "Epoch 3/1000\n",
+ "645/645 [==============================] - 1s 853us/step - loss: 0.6071 - val_loss: 0.6041\n",
+ "Epoch 4/1000\n",
+ "645/645 [==============================] - 1s 883us/step - loss: 0.6015 - val_loss: 0.5990\n",
+ "Epoch 5/1000\n",
+ "645/645 [==============================] - 1s 830us/step - loss: 0.5982 - val_loss: 0.5974\n",
+ "Epoch 6/1000\n",
+ "645/645 [==============================] - 1s 866us/step - loss: 0.5968 - val_loss: 0.5964\n",
+ "Epoch 7/1000\n",
+ "645/645 [==============================] - 1s 812us/step - loss: 0.5958 - val_loss: 0.5954\n",
+ "Epoch 8/1000\n",
+ "645/645 [==============================] - 1s 790us/step - loss: 0.5951 - val_loss: 0.5950\n",
+ "Epoch 9/1000\n",
+ "645/645 [==============================] - 0s 763us/step - loss: 0.5948 - val_loss: 0.5947\n",
+ "Epoch 10/1000\n",
+ "645/645 [==============================] - 1s 777us/step - loss: 0.5946 - val_loss: 0.5945\n",
+ "Epoch 11/1000\n",
+ "645/645 [==============================] - 1s 777us/step - loss: 0.5945 - val_loss: 0.5946\n",
+ "Epoch 12/1000\n",
+ "645/645 [==============================] - 1s 804us/step - loss: 0.5945 - val_loss: 0.5945\n",
+ "Epoch 13/1000\n",
+ "645/645 [==============================] - 1s 780us/step - loss: 0.5944 - val_loss: 0.5944\n",
+ "Epoch 14/1000\n",
+ "645/645 [==============================] - 0s 763us/step - loss: 0.5944 - val_loss: 0.5943\n",
+ "Epoch 15/1000\n",
+ "645/645 [==============================] - 0s 761us/step - loss: 0.5944 - val_loss: 0.5943\n",
+ "Epoch 16/1000\n",
+ "645/645 [==============================] - 0s 767us/step - loss: 0.5943 - val_loss: 0.5944\n",
+ "Epoch 17/1000\n",
+ "645/645 [==============================] - 1s 802us/step - loss: 0.5943 - val_loss: 0.5943\n",
+ "Epoch 18/1000\n",
+ "645/645 [==============================] - 1s 848us/step - loss: 0.5943 - val_loss: 0.5942\n",
+ "Epoch 19/1000\n",
+ "645/645 [==============================] - 0s 768us/step - loss: 0.5943 - val_loss: 0.5941\n",
+ "Epoch 20/1000\n",
+ "645/645 [==============================] - 1s 799us/step - loss: 0.5941 - val_loss: 0.5940\n",
+ "Epoch 21/1000\n",
+ "645/645 [==============================] - 0s 768us/step - loss: 0.5940 - val_loss: 0.5939\n",
+ "Epoch 22/1000\n",
+ "645/645 [==============================] - 1s 791us/step - loss: 0.5940 - val_loss: 0.5939\n",
+ "Epoch 23/1000\n",
+ "645/645 [==============================] - 1s 846us/step - loss: 0.5939 - val_loss: 0.5941\n",
+ "Epoch 24/1000\n",
+ "645/645 [==============================] - 1s 783us/step - loss: 0.5939 - val_loss: 0.5938\n",
+ "Epoch 25/1000\n",
+ "645/645 [==============================] - 1s 794us/step - loss: 0.5939 - val_loss: 0.5938\n",
+ "Epoch 26/1000\n",
+ "645/645 [==============================] - 0s 754us/step - loss: 0.5939 - val_loss: 0.5940\n",
+ "Epoch 27/1000\n",
+ "645/645 [==============================] - 1s 789us/step - loss: 0.5939 - val_loss: 0.5938\n",
+ "Epoch 28/1000\n",
+ "645/645 [==============================] - 0s 764us/step - loss: 0.5938 - val_loss: 0.5938\n",
+ "Epoch 29/1000\n",
+ "645/645 [==============================] - 0s 769us/step - loss: 0.5938 - val_loss: 0.5938\n",
+ "Epoch 30/1000\n",
+ "645/645 [==============================] - 1s 798us/step - loss: 0.5938 - val_loss: 0.5938\n",
+ "Epoch 31/1000\n",
+ "645/645 [==============================] - 1s 812us/step - loss: 0.5938 - val_loss: 0.5938\n",
+ "Epoch 32/1000\n",
+ "645/645 [==============================] - 0s 772us/step - loss: 0.5938 - val_loss: 0.5940\n",
+ "Epoch 33/1000\n",
+ "645/645 [==============================] - 1s 836us/step - loss: 0.5938 - val_loss: 0.5938\n",
+ "Epoch 34/1000\n",
+ "645/645 [==============================] - 1s 785us/step - loss: 0.5938 - val_loss: 0.5938\n",
+ "Epoch 35/1000\n",
+ "645/645 [==============================] - 0s 755us/step - loss: 0.5938 - val_loss: 0.5937\n",
+ "Epoch 36/1000\n",
+ "645/645 [==============================] - 1s 777us/step - loss: 0.5938 - val_loss: 0.5938\n",
+ "Epoch 37/1000\n",
+ "645/645 [==============================] - 0s 771us/step - loss: 0.5938 - val_loss: 0.5938\n",
+ "Epoch 38/1000\n",
+ "645/645 [==============================] - 0s 771us/step - loss: 0.5938 - val_loss: 0.5937\n",
+ "Epoch 39/1000\n",
+ "645/645 [==============================] - 0s 762us/step - loss: 0.5938 - val_loss: 0.5938\n",
+ "Epoch 40/1000\n",
+ "645/645 [==============================] - 1s 794us/step - loss: 0.5938 - val_loss: 0.5937\n",
+ "Epoch 41/1000\n",
+ "645/645 [==============================] - 1s 782us/step - loss: 0.5938 - val_loss: 0.5937\n",
+ "Epoch 42/1000\n",
+ "645/645 [==============================] - 1s 809us/step - loss: 0.5937 - val_loss: 0.5937\n",
+ "Epoch 43/1000\n",
+ "645/645 [==============================] - 0s 758us/step - loss: 0.5938 - val_loss: 0.5937\n",
+ "Epoch 44/1000\n",
+ "645/645 [==============================] - 1s 790us/step - loss: 0.5938 - val_loss: 0.5939\n",
+ "Epoch 45/1000\n",
+ "645/645 [==============================] - 0s 759us/step - loss: 0.5938 - val_loss: 0.5937\n",
+ "Epoch 46/1000\n",
+ "645/645 [==============================] - 1s 780us/step - loss: 0.5938 - val_loss: 0.5937\n",
+ "Epoch 47/1000\n",
+ "645/645 [==============================] - 1s 787us/step - loss: 0.5938 - val_loss: 0.5937\n",
+ "Epoch 48/1000\n",
+ "645/645 [==============================] - 0s 764us/step - loss: 0.5938 - val_loss: 0.5937\n",
+ "Epoch 49/1000\n",
+ "645/645 [==============================] - 1s 785us/step - loss: 0.5938 - val_loss: 0.5937\n",
+ "Epoch 50/1000\n",
+ "645/645 [==============================] - 0s 747us/step - loss: 0.5937 - val_loss: 0.5938\n",
+ "Epoch 51/1000\n",
+ "645/645 [==============================] - 0s 750us/step - loss: 0.5938 - val_loss: 0.5937\n",
+ "Epoch 52/1000\n",
+ "645/645 [==============================] - 0s 772us/step - loss: 0.5937 - val_loss: 0.5937\n",
+ "Epoch 53/1000\n",
+ "645/645 [==============================] - 0s 765us/step - loss: 0.5938 - val_loss: 0.5938\n",
+ "Epoch 54/1000\n",
+ "645/645 [==============================] - 0s 767us/step - loss: 0.5938 - val_loss: 0.5938\n",
+ "Epoch 55/1000\n",
+ "645/645 [==============================] - 0s 762us/step - loss: 0.5937 - val_loss: 0.5937\n",
+ "Epoch 56/1000\n",
+ "645/645 [==============================] - 1s 782us/step - loss: 0.5937 - val_loss: 0.5938\n",
+ "Epoch 57/1000\n",
+ "645/645 [==============================] - 1s 828us/step - loss: 0.5937 - val_loss: 0.5937\n",
+ "Epoch 58/1000\n",
+ "645/645 [==============================] - 1s 846us/step - loss: 0.5937 - val_loss: 0.5937\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "False"
+ ]
+ },
+ "execution_count": 76,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "callback = tf.keras.callbacks.EarlyStopping(monitor='val_loss', min_delta=0, patience=10)\n",
+ "autoencoder.fit(X, X, epochs=1000, shuffle=True, validation_data=(X, X), verbose=True, callbacks=callback)\n",
+ "autoencoder.encoder.trainable = False\n",
+ "autoencoder.encoder.trainable"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 77,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# train_shuffled = train.sample(frac=1)\n",
+ "# X_shuffled = train_shuffled.drop(['remaining_cycles'], axis=1)\n",
+ "# y = train_shuffled.remaining_cycles\n",
+ "y = train.remaining_cycles"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 78,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "0.18864815084096742"
+ ]
+ },
+ "execution_count": 78,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "(1-(len(X)-(len(X)-16739))/len(X))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 79,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "dnn = make_fully_connected_model(autoencoder, 'mean_squared_error', 'relu')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 80,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Epoch 1/200\n",
+ "524/524 [==============================] - 2s 2ms/step - loss: 7278.1138 - val_loss: 2674.4407\n",
+ "Epoch 2/200\n",
+ "524/524 [==============================] - 1s 2ms/step - loss: 1893.8789 - val_loss: 2626.8767\n",
+ "Epoch 3/200\n",
+ "524/524 [==============================] - 1s 2ms/step - loss: 1832.4019 - val_loss: 2660.2070\n",
+ "Epoch 4/200\n",
+ "524/524 [==============================] - 1s 2ms/step - loss: 1769.7224 - val_loss: 2808.4233\n",
+ "Epoch 5/200\n",
+ "524/524 [==============================] - 1s 2ms/step - loss: 1719.7145 - val_loss: 2845.0103\n",
+ "Epoch 6/200\n",
+ "524/524 [==============================] - 1s 2ms/step - loss: 1716.2521 - val_loss: 2736.5913\n",
+ "Epoch 7/200\n",
+ "524/524 [==============================] - 1s 2ms/step - loss: 1714.2373 - val_loss: 2782.4182\n",
+ "Epoch 8/200\n",
+ "524/524 [==============================] - 1s 2ms/step - loss: 1710.5170 - val_loss: 2614.4263\n",
+ "Epoch 9/200\n",
+ "524/524 [==============================] - 1s 2ms/step - loss: 1670.0110 - val_loss: 2640.8169\n",
+ "Epoch 10/200\n",
+ "524/524 [==============================] - 1s 2ms/step - loss: 1671.2395 - val_loss: 2856.2546\n",
+ "Epoch 11/200\n",
+ "524/524 [==============================] - 1s 2ms/step - loss: 1665.1494 - val_loss: 2719.6948\n",
+ "Epoch 12/200\n",
+ "524/524 [==============================] - 1s 2ms/step - loss: 1666.6438 - val_loss: 2800.3516\n",
+ "Epoch 13/200\n",
+ "524/524 [==============================] - 1s 2ms/step - loss: 1653.4049 - val_loss: 2889.2249\n",
+ "Epoch 14/200\n",
+ "524/524 [==============================] - 1s 2ms/step - loss: 1649.0724 - val_loss: 2638.1091\n",
+ "Epoch 15/200\n",
+ "524/524 [==============================] - 1s 2ms/step - loss: 1653.8826 - val_loss: 2751.6404\n",
+ "Epoch 16/200\n",
+ "524/524 [==============================] - 1s 2ms/step - loss: 1626.2393 - val_loss: 2693.3792\n",
+ "Epoch 17/200\n",
+ "524/524 [==============================] - 1s 2ms/step - loss: 1637.8171 - val_loss: 2867.2119\n",
+ "Epoch 18/200\n",
+ "524/524 [==============================] - 1s 2ms/step - loss: 1636.0332 - val_loss: 2897.6934\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 80,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "callback = tf.keras.callbacks.EarlyStopping(monitor='val_loss', min_delta=0, patience=10)\n",
+ "dnn.fit(X, y, validation_split=(1-(len(train)-(len(train)-16739))/len(train)), verbose=1, epochs=200, callbacks=callback)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "4"
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "import numpy as np\n",
+ "test1 = np.array([0, 1, 2, 3])\n",
+ "test1.shape[0]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 85,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "WindowsPath('~/ML_Capstone')"
+ ]
+ },
+ "execution_count": 85,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "Path('~/ML_Capstone')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 91,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "INFO:tensorflow:Assets written to: ../saved_model/AutoEncoderTestConnected\\assets\n"
+ ]
+ }
+ ],
+ "source": [
+ "\n",
+ "dnn.save('../saved_model/AutoEncoderTestConnected')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 33,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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Ql144YWSMr3gGzZs0Msvv5yzYNdQznELwbhEOOkuWbGj8tSyABcAAACQL1u3blU4HFZtba3OP/98bdiwQeecc45qa2sVjUa1adOm7LF+v1/3339/tqc1mUxq3759OnTokEKhkN59911deeWVWr58uSuvZbBh/GTHPfvss3rllVe0cOFCnXfeeZozZ478fr8aGhq0YsUKXXnllfr617+uQ4cOndU5biAYlxArHOKSTQAAAEAe2batN954Q1dffbUWL16sDRs2ZIdRb9iwQel0Onvs7/3e72nq1KlKJpN67LHHtGHDhn7DhXsu4+SGSCQzjL6uru6Ux40ePTrn+BMf49VXX9Wrr74q0zQ1ffp0LVq0SFdeeaWqq6t166236t///d/P+pyRNvID2zFsrHBInupJksFfKwAAAJAvPcOl58+fL7/frwsuuCBne4++w6vXrVs34BzahoaGYa725Pbt2ydJGj9+fDb8DqRnHnQoFJKUCfNXXnmlPvKRj6i2tjZ7nG3b2r17t37605/qxRdflNQ7j3ko57iJBFVCrHCzDE+FzGC926UAAAAAJaO5uVkHDhyQ3+/XzTffrKqqKh05ckS7d+/OOa6nN/hkQ5Evuugi1ddnPqt7PJ7hLXoA27ZtU2dnp0zTzF626UTz58/XnDlzJEkbN26UJFmWpVtvvVVXXnmlli1bdsrn6JkvPJRz3EQwLiFWJPONDvOMAQAAgPzq6R2+4oorcu73tXfvXknSsmXLtGTJkmxArq2t1YoVK/SHf/iH2WN9Pt/wFjyAVCqVvUzT8uXLdeedd2aHVXu9Xl1yySW65557JEk7d+7MXp85lUppzZo1kqSbb75Z73vf+7L1e71eXXzxxbrmmmsk9f65DOUcNzHHuIRYkYNyHFvemialtM7tcgAAAICSsW7dOv3e7/1etqd3oDD35JNP6oEHHpDP59Ndd92lj3/840omkwoEApKkWCym7du3a+HChRo7duyI1t/jN7/5jUaPHq0bbrhBl156qS699FJFo1FVVlbK683Ew507d+p73/ueHMfJnvf0009rxowZampq0h133KE77rhD0WhUgUAge+mpd955Ry+88MJZneMWgnEpsVOyO1voMQYAAADyrL29XTt27NC8efO0e/duHTlypN8xe/fu1cMPP6wbb7xRc+bMUXV1tQzDUCgU0rZt2/TrX/9a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",
+ "text/plain": [
+ "