Problem Statement: Bank Churn Prediction

Objective:

Given a Bank customer, build a neural network-based classifier that can determine whether they will leave or not.

Context:

Businesses like banks which provide service have to worry about the problem of 'Churn' i.e. customers leaving and joining another service provider. It is important to understand which aspects of the service influence a customer's decision in this regard. Management can concentrate efforts on improvement of service, keeping in mind these priorities.

Data Description:

The case study is from an open-source dataset from Kaggle. The dataset contains 10,000 sample points with 14 distinct features such as CustomerId, CreditScore, Geography, Gender, Age, Tenure, Balance etc. Link to the Kaggle project site: https://www.kaggle.com/barelydedicated/bank-customer-churn-modeling

Points Distribution:

The points distribution for this case is as follows:

Read the dataset

Drop the columns which are unique for all users like IDs (5points)

Distinguish the features and target variable(5points)

Divide the data set into training and test sets (5points)

Normalize the train and test data (10points)

Initialize & build the model. Identify the points of improvement and implement the same. Note that you need to demonstrate at least two models(the original and the improved one) and highlight the differences to complete this point. You can also demonstrate more models. (20points)

Predict the results using 0.5 as a threshold. Note that you need to first predict the probability and then predict classes using the given threshold (10points)

Print the Accuracy score and confusion matrix (5points)

Happy Learning!!

In [6119]:
import tensorflow as tf
print(tf.__version__)
2.0.0
In [6120]:
import pandas as pd
import numpy as np
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder, StandardScaler
import tensorflow as tf
from sklearn import preprocessing
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, BatchNormalization
from sklearn.metrics import accuracy_score, confusion_matrix, precision_score, recall_score, f1_score, precision_recall_curve, auc
import matplotlib.pyplot as plt
from tensorflow.keras import optimizers
In [6121]:
data = pd.read_csv("bank.csv")
In [6122]:
data.head()
Out[6122]:
RowNumber CustomerId Surname CreditScore Geography Gender Age Tenure Balance NumOfProducts HasCrCard IsActiveMember EstimatedSalary Exited
0 1 15634602 Hargrave 619 France Female 42 2 0.00 1 1 1 101348.88 1
1 2 15647311 Hill 608 Spain Female 41 1 83807.86 1 0 1 112542.58 0
2 3 15619304 Onio 502 France Female 42 8 159660.80 3 1 0 113931.57 1
3 4 15701354 Boni 699 France Female 39 1 0.00 2 0 0 93826.63 0
4 5 15737888 Mitchell 850 Spain Female 43 2 125510.82 1 1 1 79084.10 0
In [6123]:
data.shape
Out[6123]:
(10000, 14)

Drop the columns which are unique for all users like IDs (5points)

In [6124]:
data = data.drop(["RowNumber","CustomerId","Surname"], axis = 1)
data.head()
Out[6124]:
CreditScore Geography Gender Age Tenure Balance NumOfProducts HasCrCard IsActiveMember EstimatedSalary Exited
0 619 France Female 42 2 0.00 1 1 1 101348.88 1
1 608 Spain Female 41 1 83807.86 1 0 1 112542.58 0
2 502 France Female 42 8 159660.80 3 1 0 113931.57 1
3 699 France Female 39 1 0.00 2 0 0 93826.63 0
4 850 Spain Female 43 2 125510.82 1 1 1 79084.10 0
In [6125]:
data.isnull().any()
Out[6125]:
CreditScore        False
Geography          False
Gender             False
Age                False
Tenure             False
Balance            False
NumOfProducts      False
HasCrCard          False
IsActiveMember     False
EstimatedSalary    False
Exited             False
dtype: bool
In [6126]:
data.isna().any()
Out[6126]:
CreditScore        False
Geography          False
Gender             False
Age                False
Tenure             False
Balance            False
NumOfProducts      False
HasCrCard          False
IsActiveMember     False
EstimatedSalary    False
Exited             False
dtype: bool

Distinguish the features and target variable(5points)

Here 'exited' is the target variable and rest are independent variables.

In [6127]:
data["Geography"].unique()
Out[6127]:
array(['France', 'Spain', 'Germany'], dtype=object)
In [6128]:
encoder = LabelEncoder()
data["Geography"] = encoder.fit_transform(data["Geography"])
data["Gender"] = encoder.fit_transform(data["Gender"])
data
Out[6128]:
CreditScore Geography Gender Age Tenure Balance NumOfProducts HasCrCard IsActiveMember EstimatedSalary Exited
0 619 0 0 42 2 0.00 1 1 1 101348.88 1
1 608 2 0 41 1 83807.86 1 0 1 112542.58 0
2 502 0 0 42 8 159660.80 3 1 0 113931.57 1
3 699 0 0 39 1 0.00 2 0 0 93826.63 0
4 850 2 0 43 2 125510.82 1 1 1 79084.10 0
... ... ... ... ... ... ... ... ... ... ... ...
9995 771 0 1 39 5 0.00 2 1 0 96270.64 0
9996 516 0 1 35 10 57369.61 1 1 1 101699.77 0
9997 709 0 0 36 7 0.00 1 0 1 42085.58 1
9998 772 1 1 42 3 75075.31 2 1 0 92888.52 1
9999 792 0 0 28 4 130142.79 1 1 0 38190.78 0

10000 rows × 11 columns

In [6129]:
data.describe()
Out[6129]:
CreditScore Geography Gender Age Tenure Balance NumOfProducts HasCrCard IsActiveMember EstimatedSalary Exited
count 10000.000000 10000.000000 10000.000000 10000.000000 10000.000000 10000.000000 10000.000000 10000.00000 10000.000000 10000.000000 10000.000000
mean 650.528800 0.746300 0.545700 38.921800 5.012800 76485.889288 1.530200 0.70550 0.515100 100090.239881 0.203700
std 96.653299 0.827529 0.497932 10.487806 2.892174 62397.405202 0.581654 0.45584 0.499797 57510.492818 0.402769
min 350.000000 0.000000 0.000000 18.000000 0.000000 0.000000 1.000000 0.00000 0.000000 11.580000 0.000000
25% 584.000000 0.000000 0.000000 32.000000 3.000000 0.000000 1.000000 0.00000 0.000000 51002.110000 0.000000
50% 652.000000 0.000000 1.000000 37.000000 5.000000 97198.540000 1.000000 1.00000 1.000000 100193.915000 0.000000
75% 718.000000 1.000000 1.000000 44.000000 7.000000 127644.240000 2.000000 1.00000 1.000000 149388.247500 0.000000
max 850.000000 2.000000 1.000000 92.000000 10.000000 250898.090000 4.000000 1.00000 1.000000 199992.480000 1.000000
In [6130]:
sns.distplot(data['Balance'])
Out[6130]:
<matplotlib.axes._subplots.AxesSubplot at 0x1a403b46c88>
In [6131]:
data[data['Balance']==0].count()
Out[6131]:
CreditScore        3617
Geography          3617
Gender             3617
Age                3617
Tenure             3617
Balance            3617
NumOfProducts      3617
HasCrCard          3617
IsActiveMember     3617
EstimatedSalary    3617
Exited             3617
dtype: int64
In [6132]:
fig,axis = plt.subplots(figsize=(16,12))
axis = sns.heatmap(data=data.corr(method='pearson',min_periods=1),annot=True,cmap="YlGnBu")

Divide the data set into training and test sets (5points)

In [6133]:
X_data = data.iloc[:, :-1]
y_data = data.iloc[:, -1]
X_train, X_test, y_train, y_test = train_test_split(X_data, y_data, test_size = 0.2, random_state = 50)

Normalize the train and test data (10points)

In [6134]:
sc = StandardScaler()
X_train = sc.fit_transform(X_train)
X_test = sc.transform(X_test)
print(X_train.shape)
print(X_test.shape)
print(y_train.shape)
print(y_test.shape)
X_train
X_test
(8000, 10)
(2000, 10)
(8000,)
(2000,)
Out[6134]:
array([[-2.1048926 ,  0.303816  , -1.11058055, ..., -1.53896753,
         0.968496  , -1.21905131],
       [-0.39422826,  0.303816  , -1.11058055, ...,  0.64978629,
         0.968496  , -1.27082363],
       [ 1.07941631,  0.303816  , -1.11058055, ...,  0.64978629,
         0.968496  , -0.21603317],
       ...,
       [ 0.48171432,  0.303816  , -1.11058055, ...,  0.64978629,
         0.968496  , -1.63442673],
       [ 0.63629242, -0.90300029,  0.90042996, ...,  0.64978629,
         0.968496  , -1.27359857],
       [-0.39422826,  0.303816  , -1.11058055, ...,  0.64978629,
        -1.03252879,  1.0489255 ]])

Initialize & build the model. Identify the points of improvement and implement the same. Note that you need to demonstrate at least two models(the original and the improved one) and highlight the differences to complete this point. You can also demonstrate more models. (20points)

Model 1

In [6135]:
model1 = Sequential()
model1.add(Dense(20, input_shape = (10,), activation = 'relu', kernel_initializer='uniform'))
model1.add(Dense(10, activation = 'tanh', kernel_initializer='uniform'))
model1.add(Dense(1,  activation = 'sigmoid',kernel_initializer='uniform'))
In [6136]:
sgd = optimizers.Adam(lr = 0.001)
In [6137]:
model1.compile(optimizer = sgd, loss = 'mean_squared_error', metrics=['accuracy', 'mse'])
In [6138]:
model1.summary()
Model: "sequential_258"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_818 (Dense)            (None, 20)                220       
_________________________________________________________________
dense_819 (Dense)            (None, 10)                210       
_________________________________________________________________
dense_820 (Dense)            (None, 1)                 11        
=================================================================
Total params: 441
Trainable params: 441
Non-trainable params: 0
_________________________________________________________________
In [6139]:
history = model1.fit(X_train, y_train.values, batch_size = 100, validation_split = 0.2,  epochs = 50, verbose = 1)
Train on 6400 samples, validate on 1600 samples
Epoch 1/50
6400/6400 [==============================] - 0s 61us/sample - loss: 0.2349 - accuracy: 0.7920 - mse: 0.2349 - val_loss: 0.2045 - val_accuracy: 0.7894 - val_mse: 0.2045
Epoch 2/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1667 - accuracy: 0.7972 - mse: 0.1667 - val_loss: 0.1505 - val_accuracy: 0.7894 - val_mse: 0.1505
Epoch 3/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1440 - accuracy: 0.7972 - mse: 0.1440 - val_loss: 0.1451 - val_accuracy: 0.7894 - val_mse: 0.1451
Epoch 4/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1402 - accuracy: 0.7972 - mse: 0.1402 - val_loss: 0.1425 - val_accuracy: 0.7894 - val_mse: 0.1425
Epoch 5/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1376 - accuracy: 0.7972 - mse: 0.1376 - val_loss: 0.1404 - val_accuracy: 0.7894 - val_mse: 0.1404
Epoch 6/50
6400/6400 [==============================] - 0s 14us/sample - loss: 0.1356 - accuracy: 0.7972 - mse: 0.1356 - val_loss: 0.1387 - val_accuracy: 0.7894 - val_mse: 0.1387
Epoch 7/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1338 - accuracy: 0.7972 - mse: 0.1338 - val_loss: 0.1372 - val_accuracy: 0.7894 - val_mse: 0.1372
Epoch 8/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1322 - accuracy: 0.8000 - mse: 0.1322 - val_loss: 0.1355 - val_accuracy: 0.8163 - val_mse: 0.1355
Epoch 9/50
6400/6400 [==============================] - 0s 16us/sample - loss: 0.1307 - accuracy: 0.8263 - mse: 0.1307 - val_loss: 0.1339 - val_accuracy: 0.8244 - val_mse: 0.1339
Epoch 10/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1293 - accuracy: 0.8309 - mse: 0.1293 - val_loss: 0.1327 - val_accuracy: 0.8281 - val_mse: 0.1327
Epoch 11/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1282 - accuracy: 0.8342 - mse: 0.1282 - val_loss: 0.1315 - val_accuracy: 0.8319 - val_mse: 0.1315
Epoch 12/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1273 - accuracy: 0.8358 - mse: 0.1273 - val_loss: 0.1305 - val_accuracy: 0.8344 - val_mse: 0.1305
Epoch 13/50
6400/6400 [==============================] - 0s 14us/sample - loss: 0.1263 - accuracy: 0.8366 - mse: 0.1263 - val_loss: 0.1299 - val_accuracy: 0.8388 - val_mse: 0.1299
Epoch 14/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1255 - accuracy: 0.8358 - mse: 0.1255 - val_loss: 0.1291 - val_accuracy: 0.8369 - val_mse: 0.1291
Epoch 15/50
6400/6400 [==============================] - 0s 15us/sample - loss: 0.1249 - accuracy: 0.8364 - mse: 0.1249 - val_loss: 0.1288 - val_accuracy: 0.8369 - val_mse: 0.1288
Epoch 16/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1244 - accuracy: 0.8377 - mse: 0.1244 - val_loss: 0.1279 - val_accuracy: 0.8369 - val_mse: 0.1279
Epoch 17/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1240 - accuracy: 0.8367 - mse: 0.1240 - val_loss: 0.1277 - val_accuracy: 0.8356 - val_mse: 0.1277
Epoch 18/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1236 - accuracy: 0.8369 - mse: 0.1236 - val_loss: 0.1274 - val_accuracy: 0.8363 - val_mse: 0.1274
Epoch 19/50
6400/6400 [==============================] - 0s 14us/sample - loss: 0.1233 - accuracy: 0.8369 - mse: 0.1233 - val_loss: 0.1271 - val_accuracy: 0.8350 - val_mse: 0.1271
Epoch 20/50
6400/6400 [==============================] - 0s 14us/sample - loss: 0.1230 - accuracy: 0.8383 - mse: 0.1230 - val_loss: 0.1270 - val_accuracy: 0.8350 - val_mse: 0.1270
Epoch 21/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1228 - accuracy: 0.8386 - mse: 0.1228 - val_loss: 0.1268 - val_accuracy: 0.8350 - val_mse: 0.1268
Epoch 22/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1226 - accuracy: 0.8377 - mse: 0.1226 - val_loss: 0.1264 - val_accuracy: 0.8356 - val_mse: 0.1264
Epoch 23/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1224 - accuracy: 0.8383 - mse: 0.1224 - val_loss: 0.1268 - val_accuracy: 0.8350 - val_mse: 0.1268
Epoch 24/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1223 - accuracy: 0.8375 - mse: 0.1223 - val_loss: 0.1263 - val_accuracy: 0.8331 - val_mse: 0.1263
Epoch 25/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1219 - accuracy: 0.8391 - mse: 0.1219 - val_loss: 0.1261 - val_accuracy: 0.8350 - val_mse: 0.1261
Epoch 26/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1219 - accuracy: 0.8377 - mse: 0.1219 - val_loss: 0.1262 - val_accuracy: 0.8338 - val_mse: 0.1262
Epoch 27/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1217 - accuracy: 0.8394 - mse: 0.1217 - val_loss: 0.1261 - val_accuracy: 0.8331 - val_mse: 0.1261
Epoch 28/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1216 - accuracy: 0.8389 - mse: 0.1216 - val_loss: 0.1260 - val_accuracy: 0.8331 - val_mse: 0.1260
Epoch 29/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1215 - accuracy: 0.8383 - mse: 0.1215 - val_loss: 0.1260 - val_accuracy: 0.8350 - val_mse: 0.1260
Epoch 30/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1213 - accuracy: 0.8391 - mse: 0.1213 - val_loss: 0.1259 - val_accuracy: 0.8325 - val_mse: 0.1259
Epoch 31/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1213 - accuracy: 0.8395 - mse: 0.1213 - val_loss: 0.1259 - val_accuracy: 0.8338 - val_mse: 0.1259
Epoch 32/50
6400/6400 [==============================] - 0s 15us/sample - loss: 0.1212 - accuracy: 0.8389 - mse: 0.1212 - val_loss: 0.1260 - val_accuracy: 0.8319 - val_mse: 0.1260
Epoch 33/50
6400/6400 [==============================] - 0s 16us/sample - loss: 0.1210 - accuracy: 0.8386 - mse: 0.1210 - val_loss: 0.1259 - val_accuracy: 0.8344 - val_mse: 0.1259
Epoch 34/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1211 - accuracy: 0.8380 - mse: 0.1211 - val_loss: 0.1260 - val_accuracy: 0.8331 - val_mse: 0.1260
Epoch 35/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1209 - accuracy: 0.8400 - mse: 0.1209 - val_loss: 0.1263 - val_accuracy: 0.8319 - val_mse: 0.1263
Epoch 36/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1209 - accuracy: 0.8392 - mse: 0.1209 - val_loss: 0.1261 - val_accuracy: 0.8325 - val_mse: 0.1261
Epoch 37/50
6400/6400 [==============================] - 0s 12us/sample - loss: 0.1207 - accuracy: 0.8409 - mse: 0.1207 - val_loss: 0.1261 - val_accuracy: 0.8331 - val_mse: 0.1261
Epoch 38/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1207 - accuracy: 0.8397 - mse: 0.1207 - val_loss: 0.1260 - val_accuracy: 0.8331 - val_mse: 0.1260
Epoch 39/50
6400/6400 [==============================] - 0s 12us/sample - loss: 0.1206 - accuracy: 0.8391 - mse: 0.1206 - val_loss: 0.1260 - val_accuracy: 0.8319 - val_mse: 0.1260
Epoch 40/50
6400/6400 [==============================] - 0s 12us/sample - loss: 0.1207 - accuracy: 0.8398 - mse: 0.1207 - val_loss: 0.1261 - val_accuracy: 0.8338 - val_mse: 0.1261
Epoch 41/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1205 - accuracy: 0.8397 - mse: 0.1205 - val_loss: 0.1260 - val_accuracy: 0.8331 - val_mse: 0.1260
Epoch 42/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1204 - accuracy: 0.8408 - mse: 0.1204 - val_loss: 0.1258 - val_accuracy: 0.8331 - val_mse: 0.1258
Epoch 43/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1204 - accuracy: 0.8397 - mse: 0.1204 - val_loss: 0.1257 - val_accuracy: 0.8338 - val_mse: 0.1257
Epoch 44/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1203 - accuracy: 0.8392 - mse: 0.1203 - val_loss: 0.1258 - val_accuracy: 0.8331 - val_mse: 0.1258
Epoch 45/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1202 - accuracy: 0.8408 - mse: 0.1202 - val_loss: 0.1261 - val_accuracy: 0.8313 - val_mse: 0.1261
Epoch 46/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1202 - accuracy: 0.8405 - mse: 0.1202 - val_loss: 0.1258 - val_accuracy: 0.8350 - val_mse: 0.1258
Epoch 47/50
6400/6400 [==============================] - 0s 12us/sample - loss: 0.1202 - accuracy: 0.8397 - mse: 0.1202 - val_loss: 0.1258 - val_accuracy: 0.8344 - val_mse: 0.1258
Epoch 48/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1201 - accuracy: 0.8381 - mse: 0.1201 - val_loss: 0.1261 - val_accuracy: 0.8338 - val_mse: 0.1261
Epoch 49/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1201 - accuracy: 0.8409 - mse: 0.1201 - val_loss: 0.1260 - val_accuracy: 0.8325 - val_mse: 0.1260
Epoch 50/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.1200 - accuracy: 0.8403 - mse: 0.1200 - val_loss: 0.1259 - val_accuracy: 0.8325 - val_mse: 0.1259
In [6140]:
hist  = pd.DataFrame(history.history)
hist['epoch'] = history.epoch
plt.plot(hist['mse'])
plt.plot(hist['val_mse'])
plt.legend(("train" , "valid") , loc =0)
Out[6140]:
<matplotlib.legend.Legend at 0x1a40474c688>
In [6141]:
results = model1.evaluate(X_test, y_test.values, verbose =0)
accuracy = str(model1.evaluate(X_test,y_test.values, verbose=0)[1])
print('Accuracy: '+ accuracy)
Accuracy: 0.834
In [6142]:
print(model1.metrics_names)
print(results) 
['loss', 'accuracy', 'mse']
[0.12618024319410323, 0.834, 0.12618025]

Model2

In [6143]:
model2 = Sequential()
model2.add(Dense(10, input_shape = (10,), activation = 'relu', kernel_initializer='normal'))
model2.add(Dense(10, activation = 'relu', kernel_initializer='normal'))
model2.add(Dense(10, activation = 'relu', kernel_initializer='normal'))
model2.add(Dense(1,  activation = 'sigmoid',kernel_initializer='normal'))
In [6144]:
sgd = optimizers.Adam(lr = 0.001)
In [6145]:
model2.compile(optimizer = sgd, loss = 'binary_crossentropy', metrics=['accuracy', 'mse'])
In [6146]:
model2.summary()
Model: "sequential_259"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_821 (Dense)            (None, 10)                110       
_________________________________________________________________
dense_822 (Dense)            (None, 10)                110       
_________________________________________________________________
dense_823 (Dense)            (None, 10)                110       
_________________________________________________________________
dense_824 (Dense)            (None, 1)                 11        
=================================================================
Total params: 341
Trainable params: 341
Non-trainable params: 0
_________________________________________________________________
In [6147]:
history = model2.fit(X_train, y_train.values, batch_size = 100, validation_split = 0.2,  epochs =50, verbose = 1)
Train on 6400 samples, validate on 1600 samples
Epoch 1/50
6400/6400 [==============================] - 0s 72us/sample - loss: 0.6735 - accuracy: 0.7953 - mse: 0.2402 - val_loss: 0.6369 - val_accuracy: 0.7894 - val_mse: 0.2220
Epoch 2/50
6400/6400 [==============================] - 0s 14us/sample - loss: 0.5420 - accuracy: 0.7972 - mse: 0.1789 - val_loss: 0.4656 - val_accuracy: 0.7894 - val_mse: 0.1499
Epoch 3/50
6400/6400 [==============================] - 0s 14us/sample - loss: 0.4480 - accuracy: 0.7972 - mse: 0.1439 - val_loss: 0.4483 - val_accuracy: 0.7894 - val_mse: 0.1447
Epoch 4/50
6400/6400 [==============================] - 0s 14us/sample - loss: 0.4357 - accuracy: 0.7972 - mse: 0.1397 - val_loss: 0.4416 - val_accuracy: 0.7894 - val_mse: 0.1420
Epoch 5/50
6400/6400 [==============================] - 0s 14us/sample - loss: 0.4298 - accuracy: 0.7972 - mse: 0.1373 - val_loss: 0.4372 - val_accuracy: 0.7894 - val_mse: 0.1399
Epoch 6/50
6400/6400 [==============================] - 0s 15us/sample - loss: 0.4263 - accuracy: 0.7972 - mse: 0.1356 - val_loss: 0.4342 - val_accuracy: 0.7894 - val_mse: 0.1385
Epoch 7/50
6400/6400 [==============================] - 0s 15us/sample - loss: 0.4237 - accuracy: 0.7972 - mse: 0.1343 - val_loss: 0.4324 - val_accuracy: 0.7894 - val_mse: 0.1376
Epoch 8/50
6400/6400 [==============================] - 0s 14us/sample - loss: 0.4209 - accuracy: 0.8100 - mse: 0.1332 - val_loss: 0.4303 - val_accuracy: 0.8125 - val_mse: 0.1364
Epoch 9/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.4175 - accuracy: 0.8217 - mse: 0.1316 - val_loss: 0.4271 - val_accuracy: 0.8250 - val_mse: 0.1349
Epoch 10/50
6400/6400 [==============================] - 0s 14us/sample - loss: 0.4138 - accuracy: 0.8283 - mse: 0.1300 - val_loss: 0.4234 - val_accuracy: 0.8294 - val_mse: 0.1330
Epoch 11/50
6400/6400 [==============================] - 0s 14us/sample - loss: 0.4104 - accuracy: 0.8320 - mse: 0.1284 - val_loss: 0.4198 - val_accuracy: 0.8363 - val_mse: 0.1312
Epoch 12/50
6400/6400 [==============================] - 0s 14us/sample - loss: 0.4073 - accuracy: 0.8358 - mse: 0.1268 - val_loss: 0.4164 - val_accuracy: 0.8350 - val_mse: 0.1297
Epoch 13/50
6400/6400 [==============================] - 0s 14us/sample - loss: 0.4033 - accuracy: 0.8345 - mse: 0.1253 - val_loss: 0.4132 - val_accuracy: 0.8375 - val_mse: 0.1281
Epoch 14/50
6400/6400 [==============================] - 0s 14us/sample - loss: 0.4006 - accuracy: 0.8377 - mse: 0.1241 - val_loss: 0.4103 - val_accuracy: 0.8400 - val_mse: 0.1268
Epoch 15/50
6400/6400 [==============================] - 0s 14us/sample - loss: 0.3983 - accuracy: 0.8369 - mse: 0.1232 - val_loss: 0.4083 - val_accuracy: 0.8338 - val_mse: 0.1262
Epoch 16/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.3968 - accuracy: 0.8355 - mse: 0.1227 - val_loss: 0.4073 - val_accuracy: 0.8375 - val_mse: 0.1256
Epoch 17/50
6400/6400 [==============================] - 0s 15us/sample - loss: 0.3951 - accuracy: 0.8348 - mse: 0.1220 - val_loss: 0.4072 - val_accuracy: 0.8375 - val_mse: 0.1255
Epoch 18/50
6400/6400 [==============================] - 0s 15us/sample - loss: 0.3942 - accuracy: 0.8361 - mse: 0.1217 - val_loss: 0.4062 - val_accuracy: 0.8350 - val_mse: 0.1256
Epoch 19/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.3933 - accuracy: 0.8364 - mse: 0.1214 - val_loss: 0.4077 - val_accuracy: 0.8331 - val_mse: 0.1264
Epoch 20/50
6400/6400 [==============================] - 0s 14us/sample - loss: 0.3929 - accuracy: 0.8348 - mse: 0.1213 - val_loss: 0.4077 - val_accuracy: 0.8363 - val_mse: 0.1254
Epoch 21/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.3925 - accuracy: 0.8378 - mse: 0.1212 - val_loss: 0.4056 - val_accuracy: 0.8356 - val_mse: 0.1250
Epoch 22/50
6400/6400 [==============================] - 0s 14us/sample - loss: 0.3913 - accuracy: 0.8380 - mse: 0.1208 - val_loss: 0.4052 - val_accuracy: 0.8344 - val_mse: 0.1251
Epoch 23/50
6400/6400 [==============================] - 0s 14us/sample - loss: 0.3913 - accuracy: 0.8356 - mse: 0.1209 - val_loss: 0.4047 - val_accuracy: 0.8388 - val_mse: 0.1246
Epoch 24/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.3904 - accuracy: 0.8377 - mse: 0.1205 - val_loss: 0.4042 - val_accuracy: 0.8356 - val_mse: 0.1247
Epoch 25/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.3898 - accuracy: 0.8369 - mse: 0.1204 - val_loss: 0.4044 - val_accuracy: 0.8363 - val_mse: 0.1249
Epoch 26/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.3897 - accuracy: 0.8381 - mse: 0.1204 - val_loss: 0.4039 - val_accuracy: 0.8338 - val_mse: 0.1245
Epoch 27/50
6400/6400 [==============================] - 0s 14us/sample - loss: 0.3886 - accuracy: 0.8384 - mse: 0.1200 - val_loss: 0.4045 - val_accuracy: 0.8356 - val_mse: 0.1249
Epoch 28/50
6400/6400 [==============================] - 0s 14us/sample - loss: 0.3881 - accuracy: 0.8392 - mse: 0.1198 - val_loss: 0.4041 - val_accuracy: 0.8350 - val_mse: 0.1246
Epoch 29/50
6400/6400 [==============================] - 0s 14us/sample - loss: 0.3877 - accuracy: 0.8384 - mse: 0.1196 - val_loss: 0.4029 - val_accuracy: 0.8331 - val_mse: 0.1246
Epoch 30/50
6400/6400 [==============================] - 0s 14us/sample - loss: 0.3873 - accuracy: 0.8405 - mse: 0.1194 - val_loss: 0.4029 - val_accuracy: 0.8356 - val_mse: 0.1242
Epoch 31/50
6400/6400 [==============================] - 0s 15us/sample - loss: 0.3858 - accuracy: 0.8425 - mse: 0.1189 - val_loss: 0.4013 - val_accuracy: 0.8394 - val_mse: 0.1235
Epoch 32/50
6400/6400 [==============================] - 0s 15us/sample - loss: 0.3845 - accuracy: 0.8427 - mse: 0.1184 - val_loss: 0.3985 - val_accuracy: 0.8356 - val_mse: 0.1231
Epoch 33/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.3822 - accuracy: 0.8430 - mse: 0.1175 - val_loss: 0.3963 - val_accuracy: 0.8394 - val_mse: 0.1223
Epoch 34/50
6400/6400 [==============================] - 0s 14us/sample - loss: 0.3790 - accuracy: 0.8448 - mse: 0.1165 - val_loss: 0.3951 - val_accuracy: 0.8375 - val_mse: 0.1220
Epoch 35/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.3738 - accuracy: 0.8478 - mse: 0.1147 - val_loss: 0.3893 - val_accuracy: 0.8400 - val_mse: 0.1203
Epoch 36/50
6400/6400 [==============================] - 0s 14us/sample - loss: 0.3686 - accuracy: 0.8480 - mse: 0.1131 - val_loss: 0.3861 - val_accuracy: 0.8388 - val_mse: 0.1197
Epoch 37/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.3647 - accuracy: 0.8505 - mse: 0.1118 - val_loss: 0.3827 - val_accuracy: 0.8456 - val_mse: 0.1184
Epoch 38/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.3597 - accuracy: 0.8533 - mse: 0.1102 - val_loss: 0.3806 - val_accuracy: 0.8469 - val_mse: 0.1172
Epoch 39/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.3569 - accuracy: 0.8530 - mse: 0.1095 - val_loss: 0.3746 - val_accuracy: 0.8419 - val_mse: 0.1158
Epoch 40/50
6400/6400 [==============================] - 0s 14us/sample - loss: 0.3532 - accuracy: 0.8530 - mse: 0.1082 - val_loss: 0.3747 - val_accuracy: 0.8444 - val_mse: 0.1160
Epoch 41/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.3511 - accuracy: 0.8573 - mse: 0.1074 - val_loss: 0.3716 - val_accuracy: 0.8444 - val_mse: 0.1149
Epoch 42/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.3491 - accuracy: 0.8566 - mse: 0.1070 - val_loss: 0.3696 - val_accuracy: 0.8431 - val_mse: 0.1142
Epoch 43/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.3481 - accuracy: 0.8586 - mse: 0.1065 - val_loss: 0.3683 - val_accuracy: 0.8494 - val_mse: 0.1138
Epoch 44/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.3444 - accuracy: 0.8600 - mse: 0.1053 - val_loss: 0.3681 - val_accuracy: 0.8462 - val_mse: 0.1140
Epoch 45/50
6400/6400 [==============================] - 0s 14us/sample - loss: 0.3433 - accuracy: 0.8602 - mse: 0.1048 - val_loss: 0.3659 - val_accuracy: 0.8469 - val_mse: 0.1131
Epoch 46/50
6400/6400 [==============================] - 0s 15us/sample - loss: 0.3422 - accuracy: 0.8614 - mse: 0.1047 - val_loss: 0.3660 - val_accuracy: 0.8481 - val_mse: 0.1131
Epoch 47/50
6400/6400 [==============================] - 0s 15us/sample - loss: 0.3406 - accuracy: 0.8602 - mse: 0.1043 - val_loss: 0.3670 - val_accuracy: 0.8438 - val_mse: 0.1139
Epoch 48/50
6400/6400 [==============================] - 0s 14us/sample - loss: 0.3390 - accuracy: 0.8602 - mse: 0.1036 - val_loss: 0.3657 - val_accuracy: 0.8494 - val_mse: 0.1134
Epoch 49/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.3378 - accuracy: 0.8639 - mse: 0.1032 - val_loss: 0.3651 - val_accuracy: 0.8506 - val_mse: 0.1128
Epoch 50/50
6400/6400 [==============================] - 0s 13us/sample - loss: 0.3373 - accuracy: 0.8622 - mse: 0.1030 - val_loss: 0.3631 - val_accuracy: 0.8481 - val_mse: 0.1116
In [6148]:
hist  = pd.DataFrame(history.history)
hist['epoch'] = history.epoch
plt.plot(hist['mse'])
plt.plot(hist['val_mse'])
plt.legend(("train" , "valid") , loc =0)
Out[6148]:
<matplotlib.legend.Legend at 0x1a40613b608>
In [6149]:
results = model2.evaluate(X_test, y_test.values, verbose =0)
accuracy = str(model1.evaluate(X_test,y_test.values, verbose=0)[1])
print('Accuracy: '+ accuracy)
Accuracy: 0.834
In [6150]:
print(model2.metrics_names)
print(results) 
['loss', 'accuracy', 'mse']
[0.3624837958812714, 0.8575, 0.11011941]

Predict the results using 0.5 as a threshold. Note that you need to first predict the probability and then predict classes using the given threshold (10points)

In [6151]:
def predict_with_threshold(model, x, batch_size, verbose):
    proba = model.predict(x, batch_size=batch_size, verbose=verbose)
    return (proba >= 0.50).astype('int32')
    
In [6152]:
Y_pred1 = predict_with_threshold(model1 , X_test, batch_size=1000, verbose=0)
Y_pred2 = predict_with_threshold(model2 , X_test, batch_size=1000, verbose=0)

Model_1

In [6153]:
print('Recall_score: ' + str(recall_score(y_test.values,Y_pred1)))
print('Precision_score: ' + str(precision_score(y_test.values, Y_pred1)))
print('F-score: ' + str(f1_score(y_test.values,Y_pred1)))
confusionMatrix = confusion_matrix(y_test.values,Y_pred1)
Recall_score: 0.35074626865671643
Precision_score: 0.6650943396226415
F-score: 0.4592833876221499
In [6154]:
group_names = ['True Neg','False Pos','False Neg','True Pos']
group_counts = ["{0:0.0f}".format(value) for value in confusionMatrix.flatten()]
group_percentages = ["{0:.2%}".format(value) for value in confusionMatrix.flatten()/np.sum(confusionMatrix)]
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(confusionMatrix, annot=labels, fmt='', cmap='Blues')
Out[6154]:
<matplotlib.axes._subplots.AxesSubplot at 0x1a4066b03c8>

Model_2

In [6155]:
print('Recall_score: ' + str(recall_score(y_test.values,Y_pred2)))
print('Precision_score: ' + str(precision_score(y_test.values, Y_pred2)))
print('F-score: ' + str(f1_score(y_test.values,Y_pred2)))
confusionMatrix = confusion_matrix(y_test.values,Y_pred2)
Recall_score: 0.4701492537313433
Precision_score: 0.7241379310344828
F-score: 0.5701357466063348
In [6156]:
group_names = ['True Neg','False Pos','False Neg','True Pos']
group_counts = ["{0:0.0f}".format(value) for value in confusionMatrix.flatten()]
group_percentages = ["{0:.2%}".format(value) for value in confusionMatrix.flatten()/np.sum(confusionMatrix)]
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(confusionMatrix, annot=labels, fmt='', cmap='Blues')
Out[6156]:
<matplotlib.axes._subplots.AxesSubplot at 0x1a40674bfc8>

Model 2 is giving a better F1 score than Model 1. In Model 2 we had introduced different set of hidden relu layers. Model 1 uses one relu and a tanh activation function hidden layers. Learning rates are same.