Neural Network Classification

2_Binary classification

Classification

Survival prediction of patients with heart failure.

d3.jpg

Data Source: Heart Failure

In this project, we will use a dataset from Kaggle to predict the survival of patients with heart failure from serum creatinine and ejection fraction, and other factors such as age, anemia, diabetes, and so on.

About The Dataset:

Cardiovascular diseases (CVDs) are the number 1 cause of death globally, taking an estimated 17.9 million lives each year, which accounts for 31% of all deaths worlwide. Heart failure is a common event caused by CVDs and this dataset contains 12 features that can be used to predict mortality by heart failure.

Most cardiovascular diseases can be prevented by addressing behavioural risk factors such as tobacco use, unhealthy diet and obesity, physical inactivity and harmful use of alcohol using population-wide strategies.

People with cardiovascular disease or who are at high cardiovascular risk (due to the presence of one or more risk factors such as hypertension, diabetes, hyperlipidaemia or already established disease) need early detection and management wherein a machine learning model can be of great help.

Data Dictionary:

  1. Feature details

h.png

  1. Boolean features
    • Sex – 0 = Female, Male = 1
    • Diabetes – 0 = No, 1 = Yes
    • Anaemia – 0 = No, 1 = Yes
    • High_blood_pressure – 0 = No, 1 = Yes
    • Smoking – 0 = No, 1 = Yes
    • DEATH_EVENT – 0 = No, 1 = Yes
  1. Other informations       – mcg/L: micrograms per liter.
    • mL: microliter.
    • mEq/L: milliequivalents per litre
    • The time feature seams to be highly correlated to the death event but there is no concret information of how this metric was measured patient by patient. Which makes it hard to use it in the analysis.

Load Libraries and Data Inspection

In [1]:
import pandas as pd
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
import seaborn as sns

from sklearn.preprocessing import StandardScaler, LabelEncoder
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix, accuracy_score, recall_score, f1_score, classification_report

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, InputLayer, Dropout
from tensorflow.keras.constraints import MaxNorm
from tensorflow.keras import layers
from tensorflow.keras.callbacks import EarlyStopping

from scikeras.wrappers import KerasClassifier
from sklearn.model_selection import GridSearchCV

# from collections import Counter
from tensorflow.keras.utils import to_categorical
from sklearn.compose import ColumnTransformer
In [2]:
df = pd.read_csv('heart_failure.csv')
print(df.shape)
df.head()
(299, 15)
Out[2]:
Unnamed: 0 age anaemia creatinine_phosphokinase diabetes ejection_fraction high_blood_pressure platelets serum_creatinine serum_sodium sex smoking time DEATH_EVENT death_event
0 0 75.0 no 582 no 20 yes 265000.00 1.9 130 yes no 4 1 yes
1 1 55.0 no 7861 no 38 no 263358.03 1.1 136 yes no 6 1 yes
2 2 65.0 no 146 no 20 no 162000.00 1.3 129 yes yes 7 1 yes
3 3 50.0 yes 111 no 20 no 210000.00 1.9 137 yes no 7 1 yes
4 4 65.0 yes 160 yes 20 no 327000.00 2.7 116 no no 8 1 yes

In this dataset, we will use column death_event as our class label.

Class Distribution (death_event)

Only 32% of our samples failed to survive given of heart failure.

In [3]:
print(df['death_event'].value_counts())
# proportion
df['death_event'].value_counts() / len(df)
no     203
yes     96
Name: death_event, dtype: int64
Out[3]:
no     0.67893
yes    0.32107
Name: death_event, dtype: float64

We have a very small and slightly imbalance dataset. We can’t confidently use accuracy as our scoring method.

note: For unbalance dataset we must use recall, precision and f1 for scoring.

recall: number of correct prediction out of total Actual Positive. usecase if we need to reduce the False Negative like in cancer detection, we dont want our model to predict a person to be negative while the truth is positive.

precision: number of positive in Actual out total Positive prediction. i.e in cases we need to reduce the False Positives like in spam detection, we dont want to predict an important mail to be a spam.

General Information

In [4]:
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 299 entries, 0 to 298
Data columns (total 15 columns):
 #   Column                    Non-Null Count  Dtype  
---  ------                    --------------  -----  
 0   Unnamed: 0                299 non-null    int64  
 1   age                       299 non-null    float64
 2   anaemia                   299 non-null    object 
 3   creatinine_phosphokinase  299 non-null    int64  
 4   diabetes                  299 non-null    object 
 5   ejection_fraction         299 non-null    int64  
 6   high_blood_pressure       299 non-null    object 
 7   platelets                 299 non-null    float64
 8   serum_creatinine          299 non-null    float64
 9   serum_sodium              299 non-null    int64  
 10  sex                       299 non-null    object 
 11  smoking                   299 non-null    object 
 12  time                      299 non-null    int64  
 13  DEATH_EVENT               299 non-null    int64  
 14  death_event               299 non-null    object 
dtypes: float64(3), int64(6), object(6)
memory usage: 35.2+ KB

Anaemia, diabets, high_blood_pressure, sex, and smoking are in ‘str’ datatype. In TensorFlow with Keras, we needs to convert all the categorical features and labels into one-hot encoding vectors.

Define X and y

Lets define first our class and features. One advantage of Neural Network to traditional Machine Learning algorithm is that we don’t need to do a feature selection, Neural Network learn from it’s data and adjust features weight accordingly.

In [5]:
y = df['death_event']
X = df.loc[:,'age':'time']
X.head(3)
Out[5]:
age anaemia creatinine_phosphokinase diabetes ejection_fraction high_blood_pressure platelets serum_creatinine serum_sodium sex smoking time
0 75.0 no 582 no 20 yes 265000.00 1.9 130 yes no 4
1 55.0 no 7861 no 38 no 263358.03 1.1 136 yes no 6
2 65.0 no 146 no 20 no 162000.00 1.3 129 yes yes 7

One-Hot Encoding

One hot encode our X features. Convert categorical features (anaemia, diabets, high_blood_pressure, sex, and smoking are) to one-hot encoding vectors and assign the result back to variable X.

In [6]:
X = pd.get_dummies(X)
X.head(3)
Out[6]:
age creatinine_phosphokinase ejection_fraction platelets serum_creatinine serum_sodium time anaemia_no anaemia_yes diabetes_no diabetes_yes high_blood_pressure_no high_blood_pressure_yes sex_no sex_yes smoking_no smoking_yes
0 75.0 582 20 265000.00 1.9 130 4 1 0 1 0 0 1 0 1 1 0
1 55.0 7861 38 263358.03 1.1 136 6 1 0 1 0 1 0 0 1 1 0
2 65.0 146 20 162000.00 1.3 129 7 1 0 1 0 1 0 0 1 0 1

Split data

Splitting our train and test data to 70:30 ratio.

In [7]:
x_train, x_test, y_train, y_test = train_test_split(X, y, 
                                                    test_size = 0.3, 
                                                    random_state = 7
                                                   )

print(x_train.shape, x_test.shape, y_train.shape, y_test.shape)
(209, 17) (90, 17) (209,) (90,)

Standardized

Standardized our features.

In [8]:
ct = ColumnTransformer([("numeric", StandardScaler(), 
                        x_train.columns 
                        )])
print(ct)
x_train = ct.fit_transform(x_train)
x_test = ct.transform(x_test)
ColumnTransformer(transformers=[('numeric', StandardScaler(),
                                 Index(['age', 'creatinine_phosphokinase', 'ejection_fraction', 'platelets',
       'serum_creatinine', 'serum_sodium', 'time', 'anaemia_no', 'anaemia_yes',
       'diabetes_no', 'diabetes_yes', 'high_blood_pressure_no',
       'high_blood_pressure_yes', 'sex_no', 'sex_yes', 'smoking_no',
       'smoking_yes'],
      dtype='object'))])

Label Encoder

Convert the class/label to integers ranging from 0 to the number of classes.

In [9]:
lencoder = LabelEncoder()
y_train = lencoder.fit_transform(y_train.astype(str)) 
y_test = lencoder.fit_transform(y_test.astype(str))

# Show mapping
class_mapping = {l: i for i, l in enumerate(lencoder.classes_)}
class_mapping
Out[9]:
{'no': 0, 'yes': 1}

Re-shape to 2d array

In [10]:
y_train = to_categorical(y_train)
y_test = to_categorical(y_test)

Designing a Deep Learning Model For Classification

The model is optimized using the adam optimizer and seeks to minimize the categorical cross-entropy loss. Using Recall as our metric. We need to reduce the False Negative rate because we dont want our model to predict a person to be negative while the truth is positive.

In [11]:
model = Sequential()

# input layer
model.add(InputLayer(input_shape=(x_train.shape[1],)))

# hidden layer1
model.add(Dense(12, activation='relu'))

# output layer
# supposedly we have to use 'sigmoid' and 'binary_crossentrophy' here 
# but I will try using softmax and input two neurons(we have two classes).
model.add(Dense(2, activation='softmax')) 

# compile
# I want to monitor the recall score for this instance
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['Recall'])


# fix random seed for reproducibility
seed = 7
tf.random.set_seed(seed)

Early Stopping

In [12]:
# reference https://keras.io/api/callbacks/early_stopping/
stop = EarlyStopping(monitor='val_loss',
                     patience=20,
                     verbose=1)

Training Phase

In [13]:
# # fix random seed for reproducibility
tf.random.set_seed(7)


h = model.fit(x_train, y_train, 
               validation_data= (x_test, y_test), 
               epochs=300, 
               batch_size= 64,
               verbose=1,
               callbacks=[stop]
             )
Epoch 1/300
4/4 [==============================] - 1s 80ms/step - loss: 0.8256 - recall: 0.4928 - val_loss: 0.7558 - val_recall: 0.5889
Epoch 2/300
4/4 [==============================] - 0s 10ms/step - loss: 0.8039 - recall: 0.5215 - val_loss: 0.7346 - val_recall: 0.6111
Epoch 3/300
4/4 [==============================] - 0s 11ms/step - loss: 0.7832 - recall: 0.5167 - val_loss: 0.7159 - val_recall: 0.6222
Epoch 4/300
4/4 [==============================] - 0s 10ms/step - loss: 0.7652 - recall: 0.5455 - val_loss: 0.6980 - val_recall: 0.6444
Epoch 5/300
4/4 [==============================] - 0s 10ms/step - loss: 0.7470 - recall: 0.5694 - val_loss: 0.6812 - val_recall: 0.6556
Epoch 6/300
4/4 [==============================] - 0s 11ms/step - loss: 0.7315 - recall: 0.5885 - val_loss: 0.6660 - val_recall: 0.6778
Epoch 7/300
4/4 [==============================] - 0s 11ms/step - loss: 0.7164 - recall: 0.5981 - val_loss: 0.6518 - val_recall: 0.6889
Epoch 8/300
4/4 [==============================] - 0s 11ms/step - loss: 0.7025 - recall: 0.6172 - val_loss: 0.6384 - val_recall: 0.6667
Epoch 9/300
4/4 [==============================] - 0s 12ms/step - loss: 0.6898 - recall: 0.6172 - val_loss: 0.6260 - val_recall: 0.6667
Epoch 10/300
4/4 [==============================] - 0s 11ms/step - loss: 0.6778 - recall: 0.6220 - val_loss: 0.6142 - val_recall: 0.6667
Epoch 11/300
4/4 [==============================] - 0s 11ms/step - loss: 0.6669 - recall: 0.6316 - val_loss: 0.6031 - val_recall: 0.6889
Epoch 12/300
4/4 [==============================] - 0s 10ms/step - loss: 0.6565 - recall: 0.6411 - val_loss: 0.5928 - val_recall: 0.6889
Epoch 13/300
4/4 [==============================] - 0s 11ms/step - loss: 0.6472 - recall: 0.6459 - val_loss: 0.5831 - val_recall: 0.7000
Epoch 14/300
4/4 [==============================] - 0s 10ms/step - loss: 0.6389 - recall: 0.6507 - val_loss: 0.5742 - val_recall: 0.7222
Epoch 15/300
4/4 [==============================] - 0s 10ms/step - loss: 0.6304 - recall: 0.6507 - val_loss: 0.5664 - val_recall: 0.7222
Epoch 16/300
4/4 [==============================] - 0s 10ms/step - loss: 0.6229 - recall: 0.6603 - val_loss: 0.5592 - val_recall: 0.7222
Epoch 17/300
4/4 [==============================] - 0s 10ms/step - loss: 0.6161 - recall: 0.6794 - val_loss: 0.5527 - val_recall: 0.7333
Epoch 18/300
4/4 [==============================] - 0s 10ms/step - loss: 0.6092 - recall: 0.6842 - val_loss: 0.5466 - val_recall: 0.7444
Epoch 19/300
4/4 [==============================] - 0s 10ms/step - loss: 0.6030 - recall: 0.6938 - val_loss: 0.5405 - val_recall: 0.7556
Epoch 20/300
4/4 [==============================] - 0s 9ms/step - loss: 0.5972 - recall: 0.6986 - val_loss: 0.5345 - val_recall: 0.7667
Epoch 21/300
4/4 [==============================] - 0s 11ms/step - loss: 0.5914 - recall: 0.6938 - val_loss: 0.5285 - val_recall: 0.7667
Epoch 22/300
4/4 [==============================] - 0s 11ms/step - loss: 0.5856 - recall: 0.6938 - val_loss: 0.5224 - val_recall: 0.7667
Epoch 23/300
4/4 [==============================] - 0s 11ms/step - loss: 0.5800 - recall: 0.7081 - val_loss: 0.5163 - val_recall: 0.7667
Epoch 24/300
4/4 [==============================] - 0s 10ms/step - loss: 0.5749 - recall: 0.7225 - val_loss: 0.5108 - val_recall: 0.7889
Epoch 25/300
4/4 [==============================] - 0s 11ms/step - loss: 0.5697 - recall: 0.7273 - val_loss: 0.5050 - val_recall: 0.8000
Epoch 26/300
4/4 [==============================] - 0s 10ms/step - loss: 0.5648 - recall: 0.7321 - val_loss: 0.4994 - val_recall: 0.8111
Epoch 27/300
4/4 [==============================] - 0s 10ms/step - loss: 0.5600 - recall: 0.7273 - val_loss: 0.4944 - val_recall: 0.8111
Epoch 28/300
4/4 [==============================] - 0s 9ms/step - loss: 0.5557 - recall: 0.7273 - val_loss: 0.4898 - val_recall: 0.8222
Epoch 29/300
4/4 [==============================] - 0s 11ms/step - loss: 0.5511 - recall: 0.7321 - val_loss: 0.4859 - val_recall: 0.8222
Epoch 30/300
4/4 [==============================] - 0s 10ms/step - loss: 0.5469 - recall: 0.7368 - val_loss: 0.4824 - val_recall: 0.8222
Epoch 31/300
4/4 [==============================] - 0s 10ms/step - loss: 0.5432 - recall: 0.7368 - val_loss: 0.4784 - val_recall: 0.8222
Epoch 32/300
4/4 [==============================] - 0s 10ms/step - loss: 0.5390 - recall: 0.7368 - val_loss: 0.4740 - val_recall: 0.8222
Epoch 33/300
4/4 [==============================] - 0s 10ms/step - loss: 0.5351 - recall: 0.7416 - val_loss: 0.4693 - val_recall: 0.8222
Epoch 34/300
4/4 [==============================] - 0s 10ms/step - loss: 0.5312 - recall: 0.7416 - val_loss: 0.4646 - val_recall: 0.8111
Epoch 35/300
4/4 [==============================] - 0s 12ms/step - loss: 0.5272 - recall: 0.7464 - val_loss: 0.4601 - val_recall: 0.8111
Epoch 36/300
4/4 [==============================] - 0s 10ms/step - loss: 0.5239 - recall: 0.7512 - val_loss: 0.4559 - val_recall: 0.8111
Epoch 37/300
4/4 [==============================] - 0s 11ms/step - loss: 0.5203 - recall: 0.7512 - val_loss: 0.4521 - val_recall: 0.8111
Epoch 38/300
4/4 [==============================] - 0s 9ms/step - loss: 0.5170 - recall: 0.7560 - val_loss: 0.4484 - val_recall: 0.8111
Epoch 39/300
4/4 [==============================] - 0s 11ms/step - loss: 0.5134 - recall: 0.7656 - val_loss: 0.4448 - val_recall: 0.8111
Epoch 40/300
4/4 [==============================] - 0s 10ms/step - loss: 0.5103 - recall: 0.7656 - val_loss: 0.4413 - val_recall: 0.8111
Epoch 41/300
4/4 [==============================] - 0s 11ms/step - loss: 0.5072 - recall: 0.7656 - val_loss: 0.4377 - val_recall: 0.8333
Epoch 42/300
4/4 [==============================] - 0s 10ms/step - loss: 0.5041 - recall: 0.7656 - val_loss: 0.4341 - val_recall: 0.8333
Epoch 43/300
4/4 [==============================] - 0s 10ms/step - loss: 0.5011 - recall: 0.7703 - val_loss: 0.4304 - val_recall: 0.8333
Epoch 44/300
4/4 [==============================] - 0s 11ms/step - loss: 0.4981 - recall: 0.7656 - val_loss: 0.4269 - val_recall: 0.8333
Epoch 45/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4952 - recall: 0.7656 - val_loss: 0.4237 - val_recall: 0.8333
Epoch 46/300
4/4 [==============================] - 0s 11ms/step - loss: 0.4924 - recall: 0.7703 - val_loss: 0.4207 - val_recall: 0.8333
Epoch 47/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4895 - recall: 0.7703 - val_loss: 0.4176 - val_recall: 0.8333
Epoch 48/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4869 - recall: 0.7703 - val_loss: 0.4145 - val_recall: 0.8333
Epoch 49/300
4/4 [==============================] - 0s 11ms/step - loss: 0.4841 - recall: 0.7751 - val_loss: 0.4115 - val_recall: 0.8444
Epoch 50/300
4/4 [==============================] - 0s 11ms/step - loss: 0.4814 - recall: 0.7799 - val_loss: 0.4090 - val_recall: 0.8556
Epoch 51/300
4/4 [==============================] - 0s 11ms/step - loss: 0.4787 - recall: 0.7799 - val_loss: 0.4061 - val_recall: 0.8556
Epoch 52/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4760 - recall: 0.7799 - val_loss: 0.4033 - val_recall: 0.8556
Epoch 53/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4736 - recall: 0.7799 - val_loss: 0.4006 - val_recall: 0.8556
Epoch 54/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4707 - recall: 0.7751 - val_loss: 0.3981 - val_recall: 0.8556
Epoch 55/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4684 - recall: 0.7751 - val_loss: 0.3959 - val_recall: 0.8556
Epoch 56/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4660 - recall: 0.7751 - val_loss: 0.3934 - val_recall: 0.8667
Epoch 57/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4636 - recall: 0.7799 - val_loss: 0.3909 - val_recall: 0.8556
Epoch 58/300
4/4 [==============================] - 0s 11ms/step - loss: 0.4612 - recall: 0.7847 - val_loss: 0.3881 - val_recall: 0.8556
Epoch 59/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4591 - recall: 0.7895 - val_loss: 0.3853 - val_recall: 0.8556
Epoch 60/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4567 - recall: 0.7943 - val_loss: 0.3827 - val_recall: 0.8667
Epoch 61/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4544 - recall: 0.7943 - val_loss: 0.3806 - val_recall: 0.8556
Epoch 62/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4522 - recall: 0.7990 - val_loss: 0.3783 - val_recall: 0.8556
Epoch 63/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4499 - recall: 0.8038 - val_loss: 0.3761 - val_recall: 0.8556
Epoch 64/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4479 - recall: 0.7943 - val_loss: 0.3737 - val_recall: 0.8667
Epoch 65/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4458 - recall: 0.7943 - val_loss: 0.3715 - val_recall: 0.8778
Epoch 66/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4441 - recall: 0.7943 - val_loss: 0.3692 - val_recall: 0.8778
Epoch 67/300
4/4 [==============================] - 0s 9ms/step - loss: 0.4420 - recall: 0.7943 - val_loss: 0.3672 - val_recall: 0.8778
Epoch 68/300
4/4 [==============================] - 0s 9ms/step - loss: 0.4400 - recall: 0.7943 - val_loss: 0.3649 - val_recall: 0.8778
Epoch 69/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4381 - recall: 0.7943 - val_loss: 0.3629 - val_recall: 0.8778
Epoch 70/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4362 - recall: 0.7943 - val_loss: 0.3612 - val_recall: 0.8778
Epoch 71/300
4/4 [==============================] - 0s 9ms/step - loss: 0.4343 - recall: 0.7943 - val_loss: 0.3600 - val_recall: 0.8778
Epoch 72/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4328 - recall: 0.7943 - val_loss: 0.3588 - val_recall: 0.8778
Epoch 73/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4309 - recall: 0.7943 - val_loss: 0.3573 - val_recall: 0.8778
Epoch 74/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4293 - recall: 0.7990 - val_loss: 0.3558 - val_recall: 0.8778
Epoch 75/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4279 - recall: 0.7943 - val_loss: 0.3547 - val_recall: 0.8778
Epoch 76/300
4/4 [==============================] - 0s 9ms/step - loss: 0.4259 - recall: 0.7990 - val_loss: 0.3534 - val_recall: 0.8778
Epoch 77/300
4/4 [==============================] - 0s 9ms/step - loss: 0.4245 - recall: 0.7990 - val_loss: 0.3521 - val_recall: 0.8778
Epoch 78/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4229 - recall: 0.7990 - val_loss: 0.3506 - val_recall: 0.8667
Epoch 79/300
4/4 [==============================] - 0s 9ms/step - loss: 0.4214 - recall: 0.7990 - val_loss: 0.3491 - val_recall: 0.8778
Epoch 80/300
4/4 [==============================] - 0s 9ms/step - loss: 0.4198 - recall: 0.7943 - val_loss: 0.3476 - val_recall: 0.8778
Epoch 81/300
4/4 [==============================] - 0s 9ms/step - loss: 0.4185 - recall: 0.7943 - val_loss: 0.3464 - val_recall: 0.8778
Epoch 82/300
4/4 [==============================] - 0s 9ms/step - loss: 0.4168 - recall: 0.7943 - val_loss: 0.3452 - val_recall: 0.8889
Epoch 83/300
4/4 [==============================] - 0s 9ms/step - loss: 0.4155 - recall: 0.7943 - val_loss: 0.3439 - val_recall: 0.9000
Epoch 84/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4141 - recall: 0.7943 - val_loss: 0.3430 - val_recall: 0.9000
Epoch 85/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4126 - recall: 0.7943 - val_loss: 0.3421 - val_recall: 0.9000
Epoch 86/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4111 - recall: 0.7943 - val_loss: 0.3415 - val_recall: 0.8889
Epoch 87/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4097 - recall: 0.7990 - val_loss: 0.3409 - val_recall: 0.8889
Epoch 88/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4085 - recall: 0.8038 - val_loss: 0.3404 - val_recall: 0.9000
Epoch 89/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4071 - recall: 0.8038 - val_loss: 0.3397 - val_recall: 0.9000
Epoch 90/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4059 - recall: 0.8086 - val_loss: 0.3389 - val_recall: 0.9111
Epoch 91/300
4/4 [==============================] - 0s 9ms/step - loss: 0.4047 - recall: 0.8230 - val_loss: 0.3384 - val_recall: 0.9111
Epoch 92/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4033 - recall: 0.8278 - val_loss: 0.3377 - val_recall: 0.9111
Epoch 93/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4020 - recall: 0.8278 - val_loss: 0.3368 - val_recall: 0.9000
Epoch 94/300
4/4 [==============================] - 0s 10ms/step - loss: 0.4007 - recall: 0.8278 - val_loss: 0.3359 - val_recall: 0.9000
Epoch 95/300
4/4 [==============================] - 0s 13ms/step - loss: 0.3994 - recall: 0.8278 - val_loss: 0.3349 - val_recall: 0.9000
Epoch 96/300
4/4 [==============================] - 0s 10ms/step - loss: 0.3982 - recall: 0.8278 - val_loss: 0.3336 - val_recall: 0.9000
Epoch 97/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3969 - recall: 0.8278 - val_loss: 0.3325 - val_recall: 0.9000
Epoch 98/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3957 - recall: 0.8278 - val_loss: 0.3312 - val_recall: 0.9000
Epoch 99/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3945 - recall: 0.8278 - val_loss: 0.3298 - val_recall: 0.9000
Epoch 100/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3932 - recall: 0.8278 - val_loss: 0.3283 - val_recall: 0.9000
Epoch 101/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3922 - recall: 0.8278 - val_loss: 0.3268 - val_recall: 0.9000
Epoch 102/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3911 - recall: 0.8278 - val_loss: 0.3253 - val_recall: 0.9000
Epoch 103/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3901 - recall: 0.8278 - val_loss: 0.3242 - val_recall: 0.9000
Epoch 104/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3891 - recall: 0.8278 - val_loss: 0.3233 - val_recall: 0.9000
Epoch 105/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3880 - recall: 0.8278 - val_loss: 0.3225 - val_recall: 0.9000
Epoch 106/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3871 - recall: 0.8278 - val_loss: 0.3218 - val_recall: 0.9000
Epoch 107/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3861 - recall: 0.8278 - val_loss: 0.3211 - val_recall: 0.9000
Epoch 108/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3852 - recall: 0.8325 - val_loss: 0.3205 - val_recall: 0.9000
Epoch 109/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3844 - recall: 0.8325 - val_loss: 0.3194 - val_recall: 0.9000
Epoch 110/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3832 - recall: 0.8325 - val_loss: 0.3184 - val_recall: 0.9000
Epoch 111/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3825 - recall: 0.8325 - val_loss: 0.3175 - val_recall: 0.9000
Epoch 112/300
4/4 [==============================] - 0s 10ms/step - loss: 0.3817 - recall: 0.8325 - val_loss: 0.3170 - val_recall: 0.9111
Epoch 113/300
4/4 [==============================] - 0s 18ms/step - loss: 0.3809 - recall: 0.8325 - val_loss: 0.3163 - val_recall: 0.9000
Epoch 114/300
4/4 [==============================] - 0s 11ms/step - loss: 0.3802 - recall: 0.8230 - val_loss: 0.3158 - val_recall: 0.9000
Epoch 115/300
4/4 [==============================] - 0s 11ms/step - loss: 0.3792 - recall: 0.8278 - val_loss: 0.3152 - val_recall: 0.9000
Epoch 116/300
4/4 [==============================] - 0s 10ms/step - loss: 0.3785 - recall: 0.8325 - val_loss: 0.3147 - val_recall: 0.9000
Epoch 117/300
4/4 [==============================] - 0s 10ms/step - loss: 0.3777 - recall: 0.8325 - val_loss: 0.3140 - val_recall: 0.9000
Epoch 118/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3769 - recall: 0.8325 - val_loss: 0.3131 - val_recall: 0.9000
Epoch 119/300
4/4 [==============================] - 0s 10ms/step - loss: 0.3760 - recall: 0.8373 - val_loss: 0.3121 - val_recall: 0.9111
Epoch 120/300
4/4 [==============================] - 0s 10ms/step - loss: 0.3753 - recall: 0.8373 - val_loss: 0.3114 - val_recall: 0.9111
Epoch 121/300
4/4 [==============================] - 0s 10ms/step - loss: 0.3745 - recall: 0.8373 - val_loss: 0.3109 - val_recall: 0.9000
Epoch 122/300
4/4 [==============================] - 0s 10ms/step - loss: 0.3735 - recall: 0.8421 - val_loss: 0.3105 - val_recall: 0.9000
Epoch 123/300
4/4 [==============================] - 0s 10ms/step - loss: 0.3728 - recall: 0.8421 - val_loss: 0.3101 - val_recall: 0.9000
Epoch 124/300
4/4 [==============================] - 0s 10ms/step - loss: 0.3720 - recall: 0.8421 - val_loss: 0.3098 - val_recall: 0.9000
Epoch 125/300
4/4 [==============================] - 0s 11ms/step - loss: 0.3711 - recall: 0.8373 - val_loss: 0.3096 - val_recall: 0.9000
Epoch 126/300
4/4 [==============================] - 0s 15ms/step - loss: 0.3705 - recall: 0.8421 - val_loss: 0.3093 - val_recall: 0.9000
Epoch 127/300
4/4 [==============================] - 0s 10ms/step - loss: 0.3698 - recall: 0.8421 - val_loss: 0.3085 - val_recall: 0.9000
Epoch 128/300
4/4 [==============================] - 0s 11ms/step - loss: 0.3690 - recall: 0.8421 - val_loss: 0.3082 - val_recall: 0.9000
Epoch 129/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3683 - recall: 0.8421 - val_loss: 0.3081 - val_recall: 0.9000
Epoch 130/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3679 - recall: 0.8469 - val_loss: 0.3076 - val_recall: 0.9000
Epoch 131/300
4/4 [==============================] - 0s 10ms/step - loss: 0.3674 - recall: 0.8469 - val_loss: 0.3073 - val_recall: 0.9000
Epoch 132/300
4/4 [==============================] - 0s 10ms/step - loss: 0.3666 - recall: 0.8469 - val_loss: 0.3067 - val_recall: 0.9000
Epoch 133/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3660 - recall: 0.8469 - val_loss: 0.3059 - val_recall: 0.9000
Epoch 134/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3652 - recall: 0.8469 - val_loss: 0.3050 - val_recall: 0.9000
Epoch 135/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3646 - recall: 0.8469 - val_loss: 0.3044 - val_recall: 0.9000
Epoch 136/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3639 - recall: 0.8469 - val_loss: 0.3042 - val_recall: 0.9000
Epoch 137/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3631 - recall: 0.8469 - val_loss: 0.3039 - val_recall: 0.9000
Epoch 138/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3624 - recall: 0.8469 - val_loss: 0.3038 - val_recall: 0.9000
Epoch 139/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3616 - recall: 0.8469 - val_loss: 0.3037 - val_recall: 0.8889
Epoch 140/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3609 - recall: 0.8469 - val_loss: 0.3035 - val_recall: 0.8889
Epoch 141/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3602 - recall: 0.8469 - val_loss: 0.3034 - val_recall: 0.8889
Epoch 142/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3594 - recall: 0.8469 - val_loss: 0.3031 - val_recall: 0.8889
Epoch 143/300
4/4 [==============================] - 0s 10ms/step - loss: 0.3587 - recall: 0.8517 - val_loss: 0.3024 - val_recall: 0.8889
Epoch 144/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3580 - recall: 0.8517 - val_loss: 0.3021 - val_recall: 0.8889
Epoch 145/300
4/4 [==============================] - 0s 8ms/step - loss: 0.3573 - recall: 0.8517 - val_loss: 0.3021 - val_recall: 0.9000
Epoch 146/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3565 - recall: 0.8517 - val_loss: 0.3020 - val_recall: 0.9000
Epoch 147/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3560 - recall: 0.8517 - val_loss: 0.3020 - val_recall: 0.9000
Epoch 148/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3553 - recall: 0.8517 - val_loss: 0.3020 - val_recall: 0.9000
Epoch 149/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3545 - recall: 0.8517 - val_loss: 0.3013 - val_recall: 0.9000
Epoch 150/300
4/4 [==============================] - 0s 10ms/step - loss: 0.3537 - recall: 0.8517 - val_loss: 0.3006 - val_recall: 0.9000
Epoch 151/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3530 - recall: 0.8517 - val_loss: 0.3000 - val_recall: 0.9000
Epoch 152/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3526 - recall: 0.8517 - val_loss: 0.2995 - val_recall: 0.9000
Epoch 153/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3519 - recall: 0.8517 - val_loss: 0.2990 - val_recall: 0.9000
Epoch 154/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3514 - recall: 0.8565 - val_loss: 0.2986 - val_recall: 0.9000
Epoch 155/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3508 - recall: 0.8565 - val_loss: 0.2985 - val_recall: 0.9111
Epoch 156/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3502 - recall: 0.8565 - val_loss: 0.2984 - val_recall: 0.9111
Epoch 157/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3494 - recall: 0.8565 - val_loss: 0.2985 - val_recall: 0.9111
Epoch 158/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3488 - recall: 0.8565 - val_loss: 0.2986 - val_recall: 0.9111
Epoch 159/300
4/4 [==============================] - 0s 8ms/step - loss: 0.3483 - recall: 0.8565 - val_loss: 0.2992 - val_recall: 0.9111
Epoch 160/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3474 - recall: 0.8612 - val_loss: 0.2995 - val_recall: 0.9111
Epoch 161/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3468 - recall: 0.8565 - val_loss: 0.3002 - val_recall: 0.9111
Epoch 162/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3462 - recall: 0.8565 - val_loss: 0.3008 - val_recall: 0.9111
Epoch 163/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3457 - recall: 0.8565 - val_loss: 0.3009 - val_recall: 0.9111
Epoch 164/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3451 - recall: 0.8517 - val_loss: 0.3010 - val_recall: 0.9111
Epoch 165/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3446 - recall: 0.8517 - val_loss: 0.3019 - val_recall: 0.9111
Epoch 166/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3441 - recall: 0.8517 - val_loss: 0.3028 - val_recall: 0.9111
Epoch 167/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3437 - recall: 0.8517 - val_loss: 0.3033 - val_recall: 0.9111
Epoch 168/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3431 - recall: 0.8517 - val_loss: 0.3031 - val_recall: 0.9111
Epoch 169/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3425 - recall: 0.8517 - val_loss: 0.3026 - val_recall: 0.9111
Epoch 170/300
4/4 [==============================] - 0s 10ms/step - loss: 0.3421 - recall: 0.8469 - val_loss: 0.3023 - val_recall: 0.9111
Epoch 171/300
4/4 [==============================] - 0s 10ms/step - loss: 0.3415 - recall: 0.8469 - val_loss: 0.3022 - val_recall: 0.9111
Epoch 172/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3411 - recall: 0.8517 - val_loss: 0.3018 - val_recall: 0.9111
Epoch 173/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3406 - recall: 0.8517 - val_loss: 0.3012 - val_recall: 0.9111
Epoch 174/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3402 - recall: 0.8565 - val_loss: 0.3011 - val_recall: 0.9111
Epoch 175/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3396 - recall: 0.8565 - val_loss: 0.3010 - val_recall: 0.9111
Epoch 176/300
4/4 [==============================] - 0s 9ms/step - loss: 0.3391 - recall: 0.8565 - val_loss: 0.3007 - val_recall: 0.9111
Epoch 176: early stopping

Note: We will get slightly different results if we re-run the training phase multiple times due to algorithm nature (callbacks and validation data).

Consider running the training phase a few times and compare the average outcome.

In [14]:
h.history.keys()
Out[14]:
dict_keys(['loss', 'recall', 'val_loss', 'val_recall'])

Plotting for Recall Score

In [15]:
#plotting for Recall

fig, axs = plt.subplots(1,2,
                        figsize=(15, 6),
                        gridspec_kw={'hspace': 0.5, 'wspace': 0.2}) 
(ax1, ax2) = axs
# Binary Entrophy
ax1.plot(h.history['loss'], label='Train')
ax1.plot(h.history['val_loss'], label='Validation')
ax1.set_title('Categorical cross entrophy for train vs validation set')
ax1.legend(loc="upper right")
ax1.set_xlabel("# of epochs")
ax1.set_ylabel("Categorical Cross Entrophy")

# Recall
ax2.plot(h.history['recall'], label='Train')
ax2.plot(h.history['val_recall'], label='Validation')
ax2.set_title('Recall for train vs validation set')
ax2.legend(loc="upper right")
ax2.set_xlabel("# of epochs")
ax2.set_ylabel("Recall")
Out[15]:
Text(0, 0.5, 'Recall')

Accuracy

In [16]:
loss, acc = model.evaluate(x_test, y_test, verbose=0)
print("Loss", loss, "Accuracy:", acc)
Loss 0.30071821808815 Accuracy: 0.9111111164093018

Evaluation

In [17]:
y_pred = model.predict(x_test, verbose=0)
y_pred = np.argmax(y_pred, axis=1)
y_pred
Out[17]:
array([0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
       0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0,
       0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,
       0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0,
       0, 1], dtype=int64)
In [18]:
y_true = np.argmax(y_test, axis=1)
y_true
Out[18]:
array([0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
       0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0,
       0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
       1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1,
       0, 1], dtype=int64)
In [19]:
print(classification_report(y_true, y_pred))
              precision    recall  f1-score   support

           0       0.91      0.97      0.94        65
           1       0.90      0.76      0.83        25

    accuracy                           0.91        90
   macro avg       0.91      0.86      0.88        90
weighted avg       0.91      0.91      0.91        90

In [20]:
model_matrix = confusion_matrix(y_true, y_pred)
model_matrix
Out[20]:
array([[63,  2],
       [ 6, 19]], dtype=int64)
In [21]:
# Visualize
fig, ax = plt.subplots(figsize=(8,5))

# setting variables
group_names = ['True Neg','False Pos','False Neg','True Pos']
group_counts = ['{0:0.0f}'.format(value) for value in model_matrix.flatten()]
group_percentages = ['{0:.2%}'.format(value) for value in model_matrix.flatten()/np.sum(model_matrix)]
labels = [f'{v1}\n{v2}\n{v3}' for v1, v2, v3 in zip(group_names,group_counts,group_percentages)]
labels = np.asarray(labels).reshape(2,2)

sns.heatmap(model_matrix, annot=labels, fmt='', cmap='Purples')
Out[21]:
<AxesSubplot:>
In [22]:
Recall2    = recall_score(y_true, y_pred)
Recall2
Out[22]:
0.76

After playing with different hyperparameters combination value, we were able to produce a model thats not overfit nor underfit and at the same time we minimize the recall score.

Let’s try using GridSearchCV if we can reproduce the same hyperpameter and recall score.

Hyperpameter Tunning

We will use GridSearchCV to find the optimal hyperparameter value, however using this method is very CPU computational expensive (there’s a technique that can improve training/gridsearch speed but we will not do it here). We will do search each hyperameter individually with minimum search value.

Data Preparation for GridSearchCV

In [23]:
df = pd.read_csv('heart_failure.csv')
y = df['death_event']
X = df.loc[:,'age':'time']
#
X  = pd.get_dummies(X)
#
X_train, X_test, Y_train, Y_test = train_test_split(X, y, test_size = 0.3, random_state = 0)
#
ct = ColumnTransformer([("numeric", StandardScaler(), 
                        X_train.columns 
                        )])
#
X_train = ct.fit_transform(X_train)
X_test = ct.transform(X_test)
#
le= LabelEncoder()
Y_train = le.fit_transform(Y_train.astype(str))
Y_test = le.transform(Y_test.astype(str))

Batch_size and Epoch

Batch size define how many patterns to read at a time and keep in memory. The number of epochs is the number of times the entire training dataset is shown to the network during training

In [24]:
# Function to create model, required for KerasClassifier
def create_model():
    model = Sequential()
    
    model.add(InputLayer(input_shape=(X_train.shape[1])))
    model.add(Dense(12, activation='relu'))
    model.add(Dense(1, activation='sigmoid'))
    
    model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
    return model

# fix random seed for reproducibility
seed = 7
tf.random.set_seed(seed)

# create model
model = KerasClassifier(model=create_model, verbose=0)

Note: We will do small search for epoches and batch sizes here. Unfotunately my computer can’t handle the computational power of searching with big data.

But I did gridsearch this in google collab. Here’s the link for reference:

My_GoogleCollab

In [25]:
# define the grid search parameters

# See in google collab
# batch_size = [X_train.shape[1], 64, 100]
# epochs = [50, 80, 100]
# cv = 3

batch_size = [x_train.shape[1], 64]
epochs = [50, 80]

param_grid = dict(
                  batch_size = batch_size,
                  epochs = epochs
                  )
In [26]:
grid = GridSearchCV(estimator = model, 
                    param_grid = param_grid,
                    n_jobs=-1,
                    verbose=1, 
                    cv=2)


grid_result = grid.fit(X_train, Y_train)
Fitting 2 folds for each of 4 candidates, totalling 8 fits
In [27]:
# summarize results
print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_))
means = grid_result.cv_results_['mean_test_score']
stds = grid_result.cv_results_['std_test_score']
params = grid_result.cv_results_['params']
for mean, stdev, param in zip(means, stds, params):
    print("%f (%f) with: %r" % (mean, stdev, param))
Best: 0.794277 using {'batch_size': 17, 'epochs': 50}
0.794277 (0.003800) with: {'batch_size': 17, 'epochs': 50}
0.775092 (0.005861) with: {'batch_size': 17, 'epochs': 80}
0.741621 (0.001236) with: {'batch_size': 64, 'epochs': 50}
0.770284 (0.010668) with: {'batch_size': 64, 'epochs': 80}

Number of Neurons in the Hidden Layer

The number of neurons in a layer is an important parameter to tune. Generally the number of neurons in a layer controls the representational capacity of the network, at least at that point in the topology.

Also, generally, a large enough single layer network can approximate any other neural network, at least in theory.

In [28]:
# Function for number of neurons in hidden layer 1
def create_model_neurons(neurons):
    model = Sequential()
    
    model.add(InputLayer(input_shape=(X_train.shape[1])))
    model.add(Dense(neurons, activation='relu'))
    model.add(Dense(1, activation='sigmoid'))
    
    model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
    return model

# fix random seed for reproducibility
seed = 7
tf.random.set_seed(seed)
In [29]:
# create model
model = KerasClassifier(model = create_model_neurons,
                          epochs = 80,
                          batch_size = 17,
                          verbose=0)
In [30]:
# define the grid search parameters
neurons = [1, 5, 10, 15, 20]

param_grid = dict(
                  model__neurons = neurons
                  )
In [31]:
grid = GridSearchCV(estimator=model, 
                    param_grid = param_grid, 
                    n_jobs=-1, 
                    cv=2)

grid_result = grid.fit(X_train, Y_train)
In [32]:
# summarize results
print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_))
means = grid_result.cv_results_['mean_test_score']
stds = grid_result.cv_results_['std_test_score']
params = grid_result.cv_results_['params']
for mean, stdev, param in zip(means, stds, params):
    print("%f (%f) with: %r" % (mean, stdev, param))
Best: 0.798993 using {'model__neurons': 15}
0.674634 (0.001557) with: {'model__neurons': 1}
0.727518 (0.051328) with: {'model__neurons': 5}
0.789377 (0.020147) with: {'model__neurons': 10}
0.798993 (0.010531) with: {'model__neurons': 15}
0.789515 (0.008562) with: {'model__neurons': 20}

Dropout Regularization

Limit overfitting and improve the model’s ability to generalize. For the best results, dropout is best combined with a weight constraint such as the max norm constraint.

In [33]:
# Function for dropout value in hidden layer 1
def create_model_dropout(dropout_rate, weight_constraint):
    model = Sequential()
    
    # input layer
    model.add(InputLayer(input_shape=(X_train.shape[1])))
    
    # hidden layer1
    model.add(Dense(15, activation ='relu', kernel_constraint=MaxNorm(weight_constraint)))
    model.add(Dropout(dropout_rate))
    
    #output layer
    model.add(Dense(1, activation='sigmoid'))
    
    # compile
    model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
    return model

# fix random seed for reproducibility
seed = 7
tf.random.set_seed(seed)
In [34]:
# create model
model = KerasClassifier(model = create_model_dropout,
                          epochs = 80,
                          batch_size = 17,
                          verbose=0)
In [35]:
# define the grid search parameters
# weight_constraint = [1.0, 2.0, 3.0, 4.0, 5.0]
# dropout_rate = [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]

weight_constraint = [1.0, 2.0]
dropout_rate = [0.0, 0.1, 0.2]

param_grid = dict(
                  model__dropout_rate = dropout_rate,
                  model__weight_constraint = weight_constraint
                 )
In [36]:
grid = GridSearchCV(estimator = model, 
                    param_grid = param_grid, 
                    n_jobs = -1, 
                    cv=2)

grid_result = grid.fit(X_train, Y_train)
In [37]:
# summarize results
print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_))
means = grid_result.cv_results_['mean_test_score']
stds = grid_result.cv_results_['std_test_score']
params = grid_result.cv_results_['params']
for mean, stdev, param in zip(means, stds, params):
    print("%f (%f) with: %r" % (mean, stdev, param))
Best: 0.808654 using {'model__dropout_rate': 0.2, 'model__weight_constraint': 2.0}
0.755907 (0.015522) with: {'model__dropout_rate': 0.0, 'model__weight_constraint': 1.0}
0.755998 (0.003617) with: {'model__dropout_rate': 0.0, 'model__weight_constraint': 2.0}
0.780082 (0.037225) with: {'model__dropout_rate': 0.1, 'model__weight_constraint': 1.0}
0.789560 (0.018132) with: {'model__dropout_rate': 0.1, 'model__weight_constraint': 2.0}
0.794185 (0.015339) with: {'model__dropout_rate': 0.2, 'model__weight_constraint': 1.0}
0.808654 (0.008654) with: {'model__dropout_rate': 0.2, 'model__weight_constraint': 2.0}

Neuron Activation Function

activation = [‘softmax’, ‘softplus’, ‘softsign’, ‘relu’, ‘tanh’, ‘sigmoid’, ‘hard_sigmoid’, ‘linear’]

–WIP–

Learning Rate and Momentum

–WIP–

To be continue…

Leave a Reply