Employee Retention Prediction

Hiring and retaining employees are extremely complex tasks that require capital, time and skills. Companies spend 15%-20% of the employee's salary to recruit a new candidate.

In this project an AI model will be develop to reduce hiring and training costs of employees by predicting which employees might leave the company.

Importing the Libraries

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

from sklearn.preprocessing import MinMaxScaler
from sklearn.preprocessing import OneHotEncoder
from sklearn.model_selection import train_test_split

from sklearn.neighbors import KNeighborsClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.ensemble import RandomForestClassifier

from sklearn.metrics import accuracy_score
from sklearn.metrics import confusion_matrix, classification_report

from warnings import simplefilter
simplefilter(action='ignore', category=FutureWarning)

Loading the Datasets

In [2]:
df = pd.read_csv('Human_Resources.csv')
pd.set_option('display.max_columns', None)
df
Out[2]:
Age Attrition BusinessTravel DailyRate Department DistanceFromHome Education EducationField EmployeeCount EmployeeNumber EnvironmentSatisfaction Gender HourlyRate JobInvolvement JobLevel JobRole JobSatisfaction MaritalStatus MonthlyIncome MonthlyRate NumCompaniesWorked Over18 OverTime PercentSalaryHike PerformanceRating RelationshipSatisfaction StandardHours StockOptionLevel TotalWorkingYears TrainingTimesLastYear WorkLifeBalance YearsAtCompany YearsInCurrentRole YearsSinceLastPromotion YearsWithCurrManager
0 41 Yes Travel_Rarely 1102 Sales 1 2 Life Sciences 1 1 2 Female 94 3 2 Sales Executive 4 Single 5993 19479 8 Y Yes 11 3 1 80 0 8 0 1 6 4 0 5
1 49 No Travel_Frequently 279 Research & Development 8 1 Life Sciences 1 2 3 Male 61 2 2 Research Scientist 2 Married 5130 24907 1 Y No 23 4 4 80 1 10 3 3 10 7 1 7
2 37 Yes Travel_Rarely 1373 Research & Development 2 2 Other 1 4 4 Male 92 2 1 Laboratory Technician 3 Single 2090 2396 6 Y Yes 15 3 2 80 0 7 3 3 0 0 0 0
3 33 No Travel_Frequently 1392 Research & Development 3 4 Life Sciences 1 5 4 Female 56 3 1 Research Scientist 3 Married 2909 23159 1 Y Yes 11 3 3 80 0 8 3 3 8 7 3 0
4 27 No Travel_Rarely 591 Research & Development 2 1 Medical 1 7 1 Male 40 3 1 Laboratory Technician 2 Married 3468 16632 9 Y No 12 3 4 80 1 6 3 3 2 2 2 2
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
1465 36 No Travel_Frequently 884 Research & Development 23 2 Medical 1 2061 3 Male 41 4 2 Laboratory Technician 4 Married 2571 12290 4 Y No 17 3 3 80 1 17 3 3 5 2 0 3
1466 39 No Travel_Rarely 613 Research & Development 6 1 Medical 1 2062 4 Male 42 2 3 Healthcare Representative 1 Married 9991 21457 4 Y No 15 3 1 80 1 9 5 3 7 7 1 7
1467 27 No Travel_Rarely 155 Research & Development 4 3 Life Sciences 1 2064 2 Male 87 4 2 Manufacturing Director 2 Married 6142 5174 1 Y Yes 20 4 2 80 1 6 0 3 6 2 0 3
1468 49 No Travel_Frequently 1023 Sales 2 3 Medical 1 2065 4 Male 63 2 2 Sales Executive 2 Married 5390 13243 2 Y No 14 3 4 80 0 17 3 2 9 6 0 8
1469 34 No Travel_Rarely 628 Research & Development 8 3 Medical 1 2068 2 Male 82 4 2 Laboratory Technician 3 Married 4404 10228 2 Y No 12 3 1 80 0 6 3 4 4 3 1 2

1470 rows × 35 columns

Data Cleaning

In [3]:
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1470 entries, 0 to 1469
Data columns (total 35 columns):
Age                         1470 non-null int64
Attrition                   1470 non-null object
BusinessTravel              1470 non-null object
DailyRate                   1470 non-null int64
Department                  1470 non-null object
DistanceFromHome            1470 non-null int64
Education                   1470 non-null int64
EducationField              1470 non-null object
EmployeeCount               1470 non-null int64
EmployeeNumber              1470 non-null int64
EnvironmentSatisfaction     1470 non-null int64
Gender                      1470 non-null object
HourlyRate                  1470 non-null int64
JobInvolvement              1470 non-null int64
JobLevel                    1470 non-null int64
JobRole                     1470 non-null object
JobSatisfaction             1470 non-null int64
MaritalStatus               1470 non-null object
MonthlyIncome               1470 non-null int64
MonthlyRate                 1470 non-null int64
NumCompaniesWorked          1470 non-null int64
Over18                      1470 non-null object
OverTime                    1470 non-null object
PercentSalaryHike           1470 non-null int64
PerformanceRating           1470 non-null int64
RelationshipSatisfaction    1470 non-null int64
StandardHours               1470 non-null int64
StockOptionLevel            1470 non-null int64
TotalWorkingYears           1470 non-null int64
TrainingTimesLastYear       1470 non-null int64
WorkLifeBalance             1470 non-null int64
YearsAtCompany              1470 non-null int64
YearsInCurrentRole          1470 non-null int64
YearsSinceLastPromotion     1470 non-null int64
YearsWithCurrManager        1470 non-null int64
dtypes: int64(26), object(9)
memory usage: 402.1+ KB
In [4]:
df.describe()
Out[4]:
Age DailyRate DistanceFromHome Education EmployeeCount EmployeeNumber EnvironmentSatisfaction HourlyRate JobInvolvement JobLevel JobSatisfaction MonthlyIncome MonthlyRate NumCompaniesWorked PercentSalaryHike PerformanceRating RelationshipSatisfaction StandardHours StockOptionLevel TotalWorkingYears TrainingTimesLastYear WorkLifeBalance YearsAtCompany YearsInCurrentRole YearsSinceLastPromotion YearsWithCurrManager
count 1470.000000 1470.000000 1470.000000 1470.000000 1470.0 1470.000000 1470.000000 1470.000000 1470.000000 1470.000000 1470.000000 1470.000000 1470.000000 1470.000000 1470.000000 1470.000000 1470.000000 1470.0 1470.000000 1470.000000 1470.000000 1470.000000 1470.000000 1470.000000 1470.000000 1470.000000
mean 36.923810 802.485714 9.192517 2.912925 1.0 1024.865306 2.721769 65.891156 2.729932 2.063946 2.728571 6502.931293 14313.103401 2.693197 15.209524 3.153741 2.712245 80.0 0.793878 11.279592 2.799320 2.761224 7.008163 4.229252 2.187755 4.123129
std 9.135373 403.509100 8.106864 1.024165 0.0 602.024335 1.093082 20.329428 0.711561 1.106940 1.102846 4707.956783 7117.786044 2.498009 3.659938 0.360824 1.081209 0.0 0.852077 7.780782 1.289271 0.706476 6.126525 3.623137 3.222430 3.568136
min 18.000000 102.000000 1.000000 1.000000 1.0 1.000000 1.000000 30.000000 1.000000 1.000000 1.000000 1009.000000 2094.000000 0.000000 11.000000 3.000000 1.000000 80.0 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000
25% 30.000000 465.000000 2.000000 2.000000 1.0 491.250000 2.000000 48.000000 2.000000 1.000000 2.000000 2911.000000 8047.000000 1.000000 12.000000 3.000000 2.000000 80.0 0.000000 6.000000 2.000000 2.000000 3.000000 2.000000 0.000000 2.000000
50% 36.000000 802.000000 7.000000 3.000000 1.0 1020.500000 3.000000 66.000000 3.000000 2.000000 3.000000 4919.000000 14235.500000 2.000000 14.000000 3.000000 3.000000 80.0 1.000000 10.000000 3.000000 3.000000 5.000000 3.000000 1.000000 3.000000
75% 43.000000 1157.000000 14.000000 4.000000 1.0 1555.750000 4.000000 83.750000 3.000000 3.000000 4.000000 8379.000000 20461.500000 4.000000 18.000000 3.000000 4.000000 80.0 1.000000 15.000000 3.000000 3.000000 9.000000 7.000000 3.000000 7.000000
max 60.000000 1499.000000 29.000000 5.000000 1.0 2068.000000 4.000000 100.000000 4.000000 5.000000 4.000000 19999.000000 26999.000000 9.000000 25.000000 4.000000 4.000000 80.0 3.000000 40.000000 6.000000 4.000000 40.000000 18.000000 15.000000 17.000000
In [5]:
df.columns
Out[5]:
Index(['Age', 'Attrition', 'BusinessTravel', 'DailyRate', 'Department',
       'DistanceFromHome', 'Education', 'EducationField', 'EmployeeCount',
       'EmployeeNumber', 'EnvironmentSatisfaction', 'Gender', 'HourlyRate',
       'JobInvolvement', 'JobLevel', 'JobRole', 'JobSatisfaction',
       'MaritalStatus', 'MonthlyIncome', 'MonthlyRate', 'NumCompaniesWorked',
       'Over18', 'OverTime', 'PercentSalaryHike', 'PerformanceRating',
       'RelationshipSatisfaction', 'StandardHours', 'StockOptionLevel',
       'TotalWorkingYears', 'TrainingTimesLastYear', 'WorkLifeBalance',
       'YearsAtCompany', 'YearsInCurrentRole', 'YearsSinceLastPromotion',
       'YearsWithCurrManager'],
      dtype='object')
Checking for Duplicates
In [6]:
df.duplicated().sum()
Out[6]:
0
Checking for Null Values
In [7]:
df.isna().sum()
Out[7]:
Age                         0
Attrition                   0
BusinessTravel              0
DailyRate                   0
Department                  0
DistanceFromHome            0
Education                   0
EducationField              0
EmployeeCount               0
EmployeeNumber              0
EnvironmentSatisfaction     0
Gender                      0
HourlyRate                  0
JobInvolvement              0
JobLevel                    0
JobRole                     0
JobSatisfaction             0
MaritalStatus               0
MonthlyIncome               0
MonthlyRate                 0
NumCompaniesWorked          0
Over18                      0
OverTime                    0
PercentSalaryHike           0
PerformanceRating           0
RelationshipSatisfaction    0
StandardHours               0
StockOptionLevel            0
TotalWorkingYears           0
TrainingTimesLastYear       0
WorkLifeBalance             0
YearsAtCompany              0
YearsInCurrentRole          0
YearsSinceLastPromotion     0
YearsWithCurrManager        0
dtype: int64
Changing categorical values to numerical
In [8]:
df['Attrition'] = df['Attrition'].apply(lambda x: 1 if x == 'Yes' else 0)
df['Over18'] = df['Over18'].apply(lambda x: 1 if x == 'Y' else 0)
df['OverTime'] = df['OverTime'].apply(lambda x: 1 if x == 'Yes' else 0)
df
Out[8]:
Age Attrition BusinessTravel DailyRate Department DistanceFromHome Education EducationField EmployeeCount EmployeeNumber EnvironmentSatisfaction Gender HourlyRate JobInvolvement JobLevel JobRole JobSatisfaction MaritalStatus MonthlyIncome MonthlyRate NumCompaniesWorked Over18 OverTime PercentSalaryHike PerformanceRating RelationshipSatisfaction StandardHours StockOptionLevel TotalWorkingYears TrainingTimesLastYear WorkLifeBalance YearsAtCompany YearsInCurrentRole YearsSinceLastPromotion YearsWithCurrManager
0 41 1 Travel_Rarely 1102 Sales 1 2 Life Sciences 1 1 2 Female 94 3 2 Sales Executive 4 Single 5993 19479 8 1 1 11 3 1 80 0 8 0 1 6 4 0 5
1 49 0 Travel_Frequently 279 Research & Development 8 1 Life Sciences 1 2 3 Male 61 2 2 Research Scientist 2 Married 5130 24907 1 1 0 23 4 4 80 1 10 3 3 10 7 1 7
2 37 1 Travel_Rarely 1373 Research & Development 2 2 Other 1 4 4 Male 92 2 1 Laboratory Technician 3 Single 2090 2396 6 1 1 15 3 2 80 0 7 3 3 0 0 0 0
3 33 0 Travel_Frequently 1392 Research & Development 3 4 Life Sciences 1 5 4 Female 56 3 1 Research Scientist 3 Married 2909 23159 1 1 1 11 3 3 80 0 8 3 3 8 7 3 0
4 27 0 Travel_Rarely 591 Research & Development 2 1 Medical 1 7 1 Male 40 3 1 Laboratory Technician 2 Married 3468 16632 9 1 0 12 3 4 80 1 6 3 3 2 2 2 2
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
1465 36 0 Travel_Frequently 884 Research & Development 23 2 Medical 1 2061 3 Male 41 4 2 Laboratory Technician 4 Married 2571 12290 4 1 0 17 3 3 80 1 17 3 3 5 2 0 3
1466 39 0 Travel_Rarely 613 Research & Development 6 1 Medical 1 2062 4 Male 42 2 3 Healthcare Representative 1 Married 9991 21457 4 1 0 15 3 1 80 1 9 5 3 7 7 1 7
1467 27 0 Travel_Rarely 155 Research & Development 4 3 Life Sciences 1 2064 2 Male 87 4 2 Manufacturing Director 2 Married 6142 5174 1 1 1 20 4 2 80 1 6 0 3 6 2 0 3
1468 49 0 Travel_Frequently 1023 Sales 2 3 Medical 1 2065 4 Male 63 2 2 Sales Executive 2 Married 5390 13243 2 1 0 14 3 4 80 0 17 3 2 9 6 0 8
1469 34 0 Travel_Rarely 628 Research & Development 8 3 Medical 1 2068 2 Male 82 4 2 Laboratory Technician 3 Married 4404 10228 2 1 0 12 3 1 80 0 6 3 4 4 3 1 2

1470 rows × 35 columns

Droppping unneccessary columns
In [9]:
df.hist(bins = 30, figsize = (20,20), color = 'blue')
Out[9]:
array([[<matplotlib.axes._subplots.AxesSubplot object at 0x13d552e90>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x13e2d8ad0>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x13e30cdd0>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x13e34cb90>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x13e386e90>],
       [<matplotlib.axes._subplots.AxesSubplot object at 0x13e3bc8d0>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x13e3fad50>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x13e431910>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x13e43b490>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x13e46fe10>],
       [<matplotlib.axes._subplots.AxesSubplot object at 0x13e4d7f90>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x13e518850>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x13e556bd0>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x13e58d890>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x13e5cbc10>],
       [<matplotlib.axes._subplots.AxesSubplot object at 0x13e6038d0>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x13e63ec50>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x13e676910>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x13e6b3c90>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x13e6e9950>],
       [<matplotlib.axes._subplots.AxesSubplot object at 0x13e727cd0>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x13e75e990>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x13e79bd10>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x13e7d39d0>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x13e811d50>],
       [<matplotlib.axes._subplots.AxesSubplot object at 0x13e847a10>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x13e885d90>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x13e8baa50>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x13e8f9dd0>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x13e92da90>]],
      dtype=object)
In [10]:
df.drop(columns = ['EmployeeCount', 'StandardHours', 'Over18', 'EmployeeNumber'], axis = 1, inplace = True)
df
Out[10]:
Age Attrition BusinessTravel DailyRate Department DistanceFromHome Education EducationField EnvironmentSatisfaction Gender HourlyRate JobInvolvement JobLevel JobRole JobSatisfaction MaritalStatus MonthlyIncome MonthlyRate NumCompaniesWorked OverTime PercentSalaryHike PerformanceRating RelationshipSatisfaction StockOptionLevel TotalWorkingYears TrainingTimesLastYear WorkLifeBalance YearsAtCompany YearsInCurrentRole YearsSinceLastPromotion YearsWithCurrManager
0 41 1 Travel_Rarely 1102 Sales 1 2 Life Sciences 2 Female 94 3 2 Sales Executive 4 Single 5993 19479 8 1 11 3 1 0 8 0 1 6 4 0 5
1 49 0 Travel_Frequently 279 Research & Development 8 1 Life Sciences 3 Male 61 2 2 Research Scientist 2 Married 5130 24907 1 0 23 4 4 1 10 3 3 10 7 1 7
2 37 1 Travel_Rarely 1373 Research & Development 2 2 Other 4 Male 92 2 1 Laboratory Technician 3 Single 2090 2396 6 1 15 3 2 0 7 3 3 0 0 0 0
3 33 0 Travel_Frequently 1392 Research & Development 3 4 Life Sciences 4 Female 56 3 1 Research Scientist 3 Married 2909 23159 1 1 11 3 3 0 8 3 3 8 7 3 0
4 27 0 Travel_Rarely 591 Research & Development 2 1 Medical 1 Male 40 3 1 Laboratory Technician 2 Married 3468 16632 9 0 12 3 4 1 6 3 3 2 2 2 2
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
1465 36 0 Travel_Frequently 884 Research & Development 23 2 Medical 3 Male 41 4 2 Laboratory Technician 4 Married 2571 12290 4 0 17 3 3 1 17 3 3 5 2 0 3
1466 39 0 Travel_Rarely 613 Research & Development 6 1 Medical 4 Male 42 2 3 Healthcare Representative 1 Married 9991 21457 4 0 15 3 1 1 9 5 3 7 7 1 7
1467 27 0 Travel_Rarely 155 Research & Development 4 3 Life Sciences 2 Male 87 4 2 Manufacturing Director 2 Married 6142 5174 1 1 20 4 2 1 6 0 3 6 2 0 3
1468 49 0 Travel_Frequently 1023 Sales 2 3 Medical 4 Male 63 2 2 Sales Executive 2 Married 5390 13243 2 0 14 3 4 0 17 3 2 9 6 0 8
1469 34 0 Travel_Rarely 628 Research & Development 8 3 Medical 2 Male 82 4 2 Laboratory Technician 3 Married 4404 10228 2 0 12 3 1 0 6 3 4 4 3 1 2

1470 rows × 31 columns

Comparision for people who left and stayed in the company
In [11]:
left_df = df[df['Attrition'] == 1]
stayed_df = df[df['Attrition'] == 0]
In [12]:
print('Total numbers of employees: ', len(df))
print('The number of employee who left: ', len(left_df))
print('The number of employee who stayed: ', len(stayed_df))
Total numbers of employees:  1470
The number of employee who left:  237
The number of employee who stayed:  1233
In [13]:
left_df.describe()
Out[13]:
Age Attrition DailyRate DistanceFromHome Education EnvironmentSatisfaction HourlyRate JobInvolvement JobLevel JobSatisfaction MonthlyIncome MonthlyRate NumCompaniesWorked OverTime PercentSalaryHike PerformanceRating RelationshipSatisfaction StockOptionLevel TotalWorkingYears TrainingTimesLastYear WorkLifeBalance YearsAtCompany YearsInCurrentRole YearsSinceLastPromotion YearsWithCurrManager
count 237.000000 237.0 237.000000 237.000000 237.000000 237.000000 237.000000 237.000000 237.000000 237.000000 237.000000 237.000000 237.000000 237.000000 237.000000 237.000000 237.000000 237.000000 237.000000 237.000000 237.000000 237.000000 237.000000 237.000000 237.000000
mean 33.607595 1.0 750.362869 10.632911 2.839662 2.464135 65.573840 2.518987 1.637131 2.468354 4787.092827 14559.308017 2.940928 0.535865 15.097046 3.156118 2.599156 0.527426 8.244726 2.624473 2.658228 5.130802 2.902954 1.945148 2.852321
std 9.689350 0.0 401.899519 8.452525 1.008244 1.169791 20.099958 0.773405 0.940594 1.118058 3640.210367 7208.153264 2.678519 0.499768 3.770294 0.363735 1.125437 0.856361 7.169204 1.254784 0.816453 5.949984 3.174827 3.153077 3.143349
min 18.000000 1.0 103.000000 1.000000 1.000000 1.000000 31.000000 1.000000 1.000000 1.000000 1009.000000 2326.000000 0.000000 0.000000 11.000000 3.000000 1.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000
25% 28.000000 1.0 408.000000 3.000000 2.000000 1.000000 50.000000 2.000000 1.000000 1.000000 2373.000000 8870.000000 1.000000 0.000000 12.000000 3.000000 2.000000 0.000000 3.000000 2.000000 2.000000 1.000000 0.000000 0.000000 0.000000
50% 32.000000 1.0 699.000000 9.000000 3.000000 3.000000 66.000000 3.000000 1.000000 3.000000 3202.000000 14618.000000 1.000000 1.000000 14.000000 3.000000 3.000000 0.000000 7.000000 2.000000 3.000000 3.000000 2.000000 1.000000 2.000000
75% 39.000000 1.0 1092.000000 17.000000 4.000000 4.000000 84.000000 3.000000 2.000000 3.000000 5916.000000 21081.000000 5.000000 1.000000 17.000000 3.000000 4.000000 1.000000 10.000000 3.000000 3.000000 7.000000 4.000000 2.000000 5.000000
max 58.000000 1.0 1496.000000 29.000000 5.000000 4.000000 100.000000 4.000000 5.000000 4.000000 19859.000000 26999.000000 9.000000 1.000000 25.000000 4.000000 4.000000 3.000000 40.000000 6.000000 4.000000 40.000000 15.000000 15.000000 14.000000
In [14]:
stayed_df.describe()
Out[14]:
Age Attrition DailyRate DistanceFromHome Education EnvironmentSatisfaction HourlyRate JobInvolvement JobLevel JobSatisfaction MonthlyIncome MonthlyRate NumCompaniesWorked OverTime PercentSalaryHike PerformanceRating RelationshipSatisfaction StockOptionLevel TotalWorkingYears TrainingTimesLastYear WorkLifeBalance YearsAtCompany YearsInCurrentRole YearsSinceLastPromotion YearsWithCurrManager
count 1233.000000 1233.0 1233.000000 1233.000000 1233.000000 1233.000000 1233.000000 1233.000000 1233.000000 1233.000000 1233.000000 1233.000000 1233.00000 1233.000000 1233.000000 1233.000000 1233.000000 1233.000000 1233.000000 1233.000000 1233.000000 1233.000000 1233.000000 1233.000000 1233.000000
mean 37.561233 0.0 812.504461 8.915653 2.927007 2.771290 65.952149 2.770479 2.145985 2.778589 6832.739659 14265.779400 2.64558 0.234388 15.231144 3.153285 2.733982 0.845093 11.862936 2.832928 2.781022 7.369019 4.484185 2.234388 4.367397
std 8.888360 0.0 403.208379 8.012633 1.027002 1.071132 20.380754 0.692050 1.117933 1.093277 4818.208001 7102.260749 2.46009 0.423787 3.639511 0.360408 1.071603 0.841985 7.760719 1.293585 0.681907 6.096298 3.649402 3.234762 3.594116
min 18.000000 0.0 102.000000 1.000000 1.000000 1.000000 30.000000 1.000000 1.000000 1.000000 1051.000000 2094.000000 0.00000 0.000000 11.000000 3.000000 1.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000
25% 31.000000 0.0 477.000000 2.000000 2.000000 2.000000 48.000000 2.000000 1.000000 2.000000 3211.000000 7973.000000 1.00000 0.000000 12.000000 3.000000 2.000000 0.000000 6.000000 2.000000 2.000000 3.000000 2.000000 0.000000 2.000000
50% 36.000000 0.0 817.000000 7.000000 3.000000 3.000000 66.000000 3.000000 2.000000 3.000000 5204.000000 14120.000000 2.00000 0.000000 14.000000 3.000000 3.000000 1.000000 10.000000 3.000000 3.000000 6.000000 3.000000 1.000000 3.000000
75% 43.000000 0.0 1176.000000 13.000000 4.000000 4.000000 83.000000 3.000000 3.000000 4.000000 8834.000000 20364.000000 4.00000 0.000000 18.000000 3.000000 4.000000 1.000000 16.000000 3.000000 3.000000 10.000000 7.000000 3.000000 7.000000
max 60.000000 0.0 1499.000000 29.000000 5.000000 4.000000 100.000000 4.000000 5.000000 4.000000 19999.000000 26997.000000 9.00000 1.000000 25.000000 4.000000 4.000000 3.000000 38.000000 6.000000 4.000000 37.000000 18.000000 15.000000 17.000000

From the data, It is shown that the mean age of the employees who stayed is higher compare to the employees who left. It is also observed that the daily rate is higher for the employees who stayed. Employees who lives closer to home stays in the company. Employees who stayed are generally more satisfied with their jobs and environment.

Exploratory Data Analysis

In [15]:
correlation = df.corr()
f, ax = plt.subplots(figsize = (20,20))
a = sns.heatmap(correlation, annot = True, cmap = sns.cubehelix_palette(light=1, as_cmap=True))
bottom, top = a.get_ylim()
a.set_ylim(bottom + 0.5, top - 0.5)
Out[15]:
(25.0, 0.0)

The Job Level is strongly correlated with the Monthly Income and Total Working Years. The monthly income is strongly correlated with the total working years. The more employees stayed longer in the company the higher the income. The age is also correlated with the Monthly income.

In [16]:
plt.figure(figsize = (25,12))
sns.countplot(x = 'Age', hue = 'Attrition', data = df)
Out[16]:
<matplotlib.axes._subplots.AxesSubplot at 0x13ff5df10>

Around ages of 28-31 years old has a higher count of employees who leave the company.However as the age grows older less employees leave the company.

In [17]:
plt.figure(figsize = (20,20))
plt.subplot(4,1,1)
sns.countplot(x = 'JobRole', hue = 'Attrition', data = df)
plt.subplot(4,1,2)
sns.countplot(x = 'MaritalStatus', hue = 'Attrition', data = df)
plt.subplot(4,1,3)
sns.countplot(x = 'JobInvolvement', hue = 'Attrition', data = df)
plt.subplot(4,1,4)
sns.countplot(x = 'JobLevel', hue = 'Attrition', data = df)
Out[17]:
<matplotlib.axes._subplots.AxesSubplot at 0x141f0b690>

Almost half of the employees in the Sales Representative left the company. However employees in the Research Director and Manager has a very low of percentage of employees who left the company.

People who has little involvement in the job has a higher tendecies to leave the company while employees with greater involvement tend not to. As you become more experienced it is highly unlikely to leave the company however if the employee is starting out or exploring, they have more tendecies to leave the company.

In [18]:
plt.figure(figsize = (12,7))
sns.kdeplot(left_df['DistanceFromHome'], label = 'Employees who left', shade = True, color = 'b')
sns.kdeplot(stayed_df['DistanceFromHome'], label = 'Employees who stayed', shade = True, color = 'r')

plt.xlabel('Distance From Home')
Out[18]:
Text(0.5, 0, 'Distance From Home')

From the distance between 10-30 , as the distance increases, the number of employees who tend to leave is higher than the employees who stayed.

In [19]:
plt.figure(figsize = (12,7))
sns.kdeplot(left_df['YearsWithCurrManager'], label = 'Employees who left', shade = True, color = 'b')
sns.kdeplot(stayed_df['YearsWithCurrManager'], label = 'Employees who stayed', shade = True, color = 'r')

plt.xlabel('Years with Current Manager')
Out[19]:
Text(0.5, 0, 'Years with Current Manager')

If you had smaller number of years with the current manager, employees tend to leave more. However as the years increases, starting from 3 years employees tend to stay in the company.

In [20]:
plt.figure(figsize = (12,7))
sns.kdeplot(left_df['TotalWorkingYears'], label = 'Employees who left', shade = True, color = 'b')
sns.kdeplot(stayed_df['TotalWorkingYears'], label = 'Employees who stayed', shade = True, color = 'r')

plt.xlabel('Total Working Years')
Out[20]:
Text(0.5, 0, 'Total Working Years')

Same with total working years, employees tend to leave the company when they spent smaller number of years in the company. However, as the years increases starting from a little less than 10 years the employees tend to stay with the company.

In [21]:
sns.boxplot(x='MonthlyIncome', y = 'Gender', data = df)
Out[21]:
<matplotlib.axes._subplots.AxesSubplot at 0x1427d1a90>

The average of the monthly income tend to be pretty the same with females are actually little more than the males.

In [22]:
plt.figure(figsize = (15,10))
sns.boxplot(x='MonthlyIncome', y = 'JobRole', data = df)
Out[22]:
<matplotlib.axes._subplots.AxesSubplot at 0x14294ded0>

The Manager and Research Director tend to be paid more. Where the Sales Representative tend to be paid less.

Data Preprocessing

In [23]:
df
Out[23]:
Age Attrition BusinessTravel DailyRate Department DistanceFromHome Education EducationField EnvironmentSatisfaction Gender HourlyRate JobInvolvement JobLevel JobRole JobSatisfaction MaritalStatus MonthlyIncome MonthlyRate NumCompaniesWorked OverTime PercentSalaryHike PerformanceRating RelationshipSatisfaction StockOptionLevel TotalWorkingYears TrainingTimesLastYear WorkLifeBalance YearsAtCompany YearsInCurrentRole YearsSinceLastPromotion YearsWithCurrManager
0 41 1 Travel_Rarely 1102 Sales 1 2 Life Sciences 2 Female 94 3 2 Sales Executive 4 Single 5993 19479 8 1 11 3 1 0 8 0 1 6 4 0 5
1 49 0 Travel_Frequently 279 Research & Development 8 1 Life Sciences 3 Male 61 2 2 Research Scientist 2 Married 5130 24907 1 0 23 4 4 1 10 3 3 10 7 1 7
2 37 1 Travel_Rarely 1373 Research & Development 2 2 Other 4 Male 92 2 1 Laboratory Technician 3 Single 2090 2396 6 1 15 3 2 0 7 3 3 0 0 0 0
3 33 0 Travel_Frequently 1392 Research & Development 3 4 Life Sciences 4 Female 56 3 1 Research Scientist 3 Married 2909 23159 1 1 11 3 3 0 8 3 3 8 7 3 0
4 27 0 Travel_Rarely 591 Research & Development 2 1 Medical 1 Male 40 3 1 Laboratory Technician 2 Married 3468 16632 9 0 12 3 4 1 6 3 3 2 2 2 2
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
1465 36 0 Travel_Frequently 884 Research & Development 23 2 Medical 3 Male 41 4 2 Laboratory Technician 4 Married 2571 12290 4 0 17 3 3 1 17 3 3 5 2 0 3
1466 39 0 Travel_Rarely 613 Research & Development 6 1 Medical 4 Male 42 2 3 Healthcare Representative 1 Married 9991 21457 4 0 15 3 1 1 9 5 3 7 7 1 7
1467 27 0 Travel_Rarely 155 Research & Development 4 3 Life Sciences 2 Male 87 4 2 Manufacturing Director 2 Married 6142 5174 1 1 20 4 2 1 6 0 3 6 2 0 3
1468 49 0 Travel_Frequently 1023 Sales 2 3 Medical 4 Male 63 2 2 Sales Executive 2 Married 5390 13243 2 0 14 3 4 0 17 3 2 9 6 0 8
1469 34 0 Travel_Rarely 628 Research & Development 8 3 Medical 2 Male 82 4 2 Laboratory Technician 3 Married 4404 10228 2 0 12 3 1 0 6 3 4 4 3 1 2

1470 rows × 31 columns

In [24]:
categorical_col = ['BusinessTravel', 'Department', 'EducationField', 'Gender', 'JobRole', 'MaritalStatus']
cat_col = df[categorical_col]
cat_col
Out[24]:
BusinessTravel Department EducationField Gender JobRole MaritalStatus
0 Travel_Rarely Sales Life Sciences Female Sales Executive Single
1 Travel_Frequently Research & Development Life Sciences Male Research Scientist Married
2 Travel_Rarely Research & Development Other Male Laboratory Technician Single
3 Travel_Frequently Research & Development Life Sciences Female Research Scientist Married
4 Travel_Rarely Research & Development Medical Male Laboratory Technician Married
... ... ... ... ... ... ...
1465 Travel_Frequently Research & Development Medical Male Laboratory Technician Married
1466 Travel_Rarely Research & Development Medical Male Healthcare Representative Married
1467 Travel_Rarely Research & Development Life Sciences Male Manufacturing Director Married
1468 Travel_Frequently Sales Medical Male Sales Executive Married
1469 Travel_Rarely Research & Development Medical Male Laboratory Technician Married

1470 rows × 6 columns

In [25]:
onehotencoder = OneHotEncoder()
cat_col = onehotencoder.fit_transform(cat_col).toarray()
cat_col
Out[25]:
array([[0., 0., 1., ..., 0., 0., 1.],
       [0., 1., 0., ..., 0., 1., 0.],
       [0., 0., 1., ..., 0., 0., 1.],
       ...,
       [0., 0., 1., ..., 0., 1., 0.],
       [0., 1., 0., ..., 0., 1., 0.],
       [0., 0., 1., ..., 0., 1., 0.]])
In [26]:
cat_col = pd.DataFrame(cat_col)
cat_col
Out[26]:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
0 0.0 0.0 1.0 0.0 0.0 1.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0
1 0.0 1.0 0.0 0.0 1.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 0.0
2 0.0 0.0 1.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 1.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0
3 0.0 1.0 0.0 0.0 1.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 0.0
4 0.0 0.0 1.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
1465 0.0 1.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0
1466 0.0 0.0 1.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0
1467 0.0 0.0 1.0 0.0 1.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0
1468 0.0 1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 1.0 0.0
1469 0.0 0.0 1.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0

1470 rows × 26 columns

In [27]:
numerical_col = ['Age', 'DailyRate','DistanceFromHome', 'Education', 'EnvironmentSatisfaction', 'HourlyRate','JobInvolvement', 'JobLevel', 'JobSatisfaction', 'MonthlyIncome', 'MonthlyRate', 'NumCompaniesWorked', 'OverTime', 'PercentSalaryHike', 'PerformanceRating',
       'RelationshipSatisfaction', 'StockOptionLevel','TotalWorkingYears', 'TrainingTimesLastYear', 'WorkLifeBalance','YearsAtCompany', 'YearsInCurrentRole', 'YearsSinceLastPromotion','YearsWithCurrManager']
num_col = df[numerical_col]
num_col
Out[27]:
Age DailyRate DistanceFromHome Education EnvironmentSatisfaction HourlyRate JobInvolvement JobLevel JobSatisfaction MonthlyIncome MonthlyRate NumCompaniesWorked OverTime PercentSalaryHike PerformanceRating RelationshipSatisfaction StockOptionLevel TotalWorkingYears TrainingTimesLastYear WorkLifeBalance YearsAtCompany YearsInCurrentRole YearsSinceLastPromotion YearsWithCurrManager
0 41 1102 1 2 2 94 3 2 4 5993 19479 8 1 11 3 1 0 8 0 1 6 4 0 5
1 49 279 8 1 3 61 2 2 2 5130 24907 1 0 23 4 4 1 10 3 3 10 7 1 7
2 37 1373 2 2 4 92 2 1 3 2090 2396 6 1 15 3 2 0 7 3 3 0 0 0 0
3 33 1392 3 4 4 56 3 1 3 2909 23159 1 1 11 3 3 0 8 3 3 8 7 3 0
4 27 591 2 1 1 40 3 1 2 3468 16632 9 0 12 3 4 1 6 3 3 2 2 2 2
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
1465 36 884 23 2 3 41 4 2 4 2571 12290 4 0 17 3 3 1 17 3 3 5 2 0 3
1466 39 613 6 1 4 42 2 3 1 9991 21457 4 0 15 3 1 1 9 5 3 7 7 1 7
1467 27 155 4 3 2 87 4 2 2 6142 5174 1 1 20 4 2 1 6 0 3 6 2 0 3
1468 49 1023 2 3 4 63 2 2 2 5390 13243 2 0 14 3 4 0 17 3 2 9 6 0 8
1469 34 628 8 3 2 82 4 2 3 4404 10228 2 0 12 3 1 0 6 3 4 4 3 1 2

1470 rows × 24 columns

In [28]:
data = pd.concat([cat_col, num_col], axis = 1)
data
Out[28]:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 Age DailyRate DistanceFromHome Education EnvironmentSatisfaction HourlyRate JobInvolvement JobLevel JobSatisfaction MonthlyIncome MonthlyRate NumCompaniesWorked OverTime PercentSalaryHike PerformanceRating RelationshipSatisfaction StockOptionLevel TotalWorkingYears TrainingTimesLastYear WorkLifeBalance YearsAtCompany YearsInCurrentRole YearsSinceLastPromotion YearsWithCurrManager
0 0.0 0.0 1.0 0.0 0.0 1.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 41 1102 1 2 2 94 3 2 4 5993 19479 8 1 11 3 1 0 8 0 1 6 4 0 5
1 0.0 1.0 0.0 0.0 1.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 0.0 49 279 8 1 3 61 2 2 2 5130 24907 1 0 23 4 4 1 10 3 3 10 7 1 7
2 0.0 0.0 1.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 1.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 37 1373 2 2 4 92 2 1 3 2090 2396 6 1 15 3 2 0 7 3 3 0 0 0 0
3 0.0 1.0 0.0 0.0 1.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 0.0 33 1392 3 4 4 56 3 1 3 2909 23159 1 1 11 3 3 0 8 3 3 8 7 3 0
4 0.0 0.0 1.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 27 591 2 1 1 40 3 1 2 3468 16632 9 0 12 3 4 1 6 3 3 2 2 2 2
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
1465 0.0 1.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 36 884 23 2 3 41 4 2 4 2571 12290 4 0 17 3 3 1 17 3 3 5 2 0 3
1466 0.0 0.0 1.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 39 613 6 1 4 42 2 3 1 9991 21457 4 0 15 3 1 1 9 5 3 7 7 1 7
1467 0.0 0.0 1.0 0.0 1.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 27 155 4 3 2 87 4 2 2 6142 5174 1 1 20 4 2 1 6 0 3 6 2 0 3
1468 0.0 1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 1.0 0.0 49 1023 2 3 4 63 2 2 2 5390 13243 2 0 14 3 4 0 17 3 2 9 6 0 8
1469 0.0 0.0 1.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 34 628 8 3 2 82 4 2 3 4404 10228 2 0 12 3 1 0 6 3 4 4 3 1 2

1470 rows × 50 columns

In [29]:
scaler = MinMaxScaler()
data = scaler.fit_transform(data)
data
Out[29]:
array([[0.        , 0.        , 1.        , ..., 0.22222222, 0.        ,
        0.29411765],
       [0.        , 1.        , 0.        , ..., 0.38888889, 0.06666667,
        0.41176471],
       [0.        , 0.        , 1.        , ..., 0.        , 0.        ,
        0.        ],
       ...,
       [0.        , 0.        , 1.        , ..., 0.11111111, 0.        ,
        0.17647059],
       [0.        , 1.        , 0.        , ..., 0.33333333, 0.        ,
        0.47058824],
       [0.        , 0.        , 1.        , ..., 0.16666667, 0.06666667,
        0.11764706]])
In [30]:
target = df['Attrition']
target
Out[30]:
0       1
1       0
2       1
3       0
4       0
       ..
1465    0
1466    0
1467    0
1468    0
1469    0
Name: Attrition, Length: 1470, dtype: int64

Model Training

In [31]:
X_train, X_test, y_train, y_test = train_test_split(data,target, test_size = 0.25)
In [32]:
X_train.shape
Out[32]:
(1102, 50)
In [33]:
X_test.shape
Out[33]:
(368, 50)
In [34]:
Logistic_model = LogisticRegression()
Logistic_model.fit(X_train, y_train)

RF_model = RandomForestClassifier()
RF_model.fit(X_train, y_train)
Out[34]:
RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
                       max_depth=None, max_features='auto', max_leaf_nodes=None,
                       min_impurity_decrease=0.0, min_impurity_split=None,
                       min_samples_leaf=1, min_samples_split=2,
                       min_weight_fraction_leaf=0.0, n_estimators=10,
                       n_jobs=None, oob_score=False, random_state=None,
                       verbose=0, warm_start=False)

Testing the Model

In [35]:
y_predict_L = Logistic_model.predict(X_test)
y_predict_RF = RF_model.predict(X_test)
In [36]:
print('Logistic Regression Accuracy: {}  %'.format(100*accuracy_score(y_predict_L,y_test)))
print('Random Forest Classifier Accuracy: {}  %'.format(100*accuracy_score(y_predict_RF,y_test)))
Logistic Regression Accuracy: 87.5  %
Random Forest Classifier Accuracy: 84.78260869565217  %
In [37]:
cm = confusion_matrix(y_predict_L,y_test)
ax = sns.heatmap(cm, annot = True, cmap = 'Blues')
bottom, top = ax.get_ylim()
ax.set_ylim(bottom + 0.5, top - 0.5)
Out[37]:
(2.0, 0.0)
In [38]:
print(classification_report(y_test, y_predict_L))
              precision    recall  f1-score   support

           0       0.87      0.99      0.93       306
           1       0.90      0.29      0.44        62

    accuracy                           0.88       368
   macro avg       0.89      0.64      0.68       368
weighted avg       0.88      0.88      0.85       368

Random Forest Classifier
In [39]:
cm = confusion_matrix(y_predict_RF,y_test)
ax = sns.heatmap(cm, annot = True, cmap = 'PuRd')
bottom, top = ax.get_ylim()
ax.set_ylim(bottom + 0.5, top - 0.5)
Out[39]:
(2.0, 0.0)
In [40]:
print(classification_report(y_test, y_predict_RF))
              precision    recall  f1-score   support

           0       0.85      1.00      0.92       306
           1       1.00      0.10      0.18        62

    accuracy                           0.85       368
   macro avg       0.92      0.55      0.55       368
weighted avg       0.87      0.85      0.79       368

Training and Testing a Deep Learning Model

In [41]:
model = tf.keras.models.Sequential()
model.add(tf.keras.layers.Dense(units = 500, activation = 'relu', input_shape = (50,)))
model.add(tf.keras.layers.Dense(units = 500, activation = 'relu'))
model.add(tf.keras.layers.Dense(units = 500, activation = 'relu'))
model.add(tf.keras.layers.Dense(units = 1, activation = 'sigmoid'))
WARNING:tensorflow:From /opt/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/init_ops.py:1251: calling VarianceScaling.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.
Instructions for updating:
Call initializer instance with the dtype argument instead of passing it to the constructor
In [42]:
model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
dense (Dense)                (None, 500)               25500
_________________________________________________________________
dense_1 (Dense)              (None, 500)               250500
_________________________________________________________________
dense_2 (Dense)              (None, 500)               250500
_________________________________________________________________
dense_3 (Dense)              (None, 1)                 501
=================================================================
Total params: 527,001
Trainable params: 527,001
Non-trainable params: 0
_________________________________________________________________
In [43]:
model.compile(optimizer = 'Adam', loss = 'binary_crossentropy', metrics = ['accuracy'])
WARNING:tensorflow:From /opt/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/nn_impl.py:180: add_dispatch_support.<locals>.wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use tf.where in 2.0, which has the same broadcast rule as np.where
In [44]:
epochs_hist = model.fit(X_train, y_train, epochs = 100, batch_size = 50)
Epoch 1/100
1102/1102 [==============================] - 0s 377us/sample - loss: 0.4268 - acc: 0.8167
Epoch 2/100
1102/1102 [==============================] - 0s 211us/sample - loss: 0.3516 - acc: 0.8557
Epoch 3/100
1102/1102 [==============================] - 0s 213us/sample - loss: 0.3179 - acc: 0.8784
Epoch 4/100
1102/1102 [==============================] - 0s 296us/sample - loss: 0.2896 - acc: 0.8993
Epoch 5/100
1102/1102 [==============================] - 0s 247us/sample - loss: 0.2608 - acc: 0.9038
Epoch 6/100
1102/1102 [==============================] - 0s 212us/sample - loss: 0.2233 - acc: 0.9183
Epoch 7/100
1102/1102 [==============================] - 0s 196us/sample - loss: 0.2031 - acc: 0.9247
Epoch 8/100
1102/1102 [==============================] - 0s 246us/sample - loss: 0.1731 - acc: 0.9283
Epoch 9/100
1102/1102 [==============================] - 0s 264us/sample - loss: 0.1229 - acc: 0.9555
Epoch 10/100
1102/1102 [==============================] - 0s 262us/sample - loss: 0.1043 - acc: 0.9583
Epoch 11/100
1102/1102 [==============================] - 0s 307us/sample - loss: 0.1276 - acc: 0.9501
Epoch 12/100
1102/1102 [==============================] - 0s 226us/sample - loss: 0.0874 - acc: 0.9719
Epoch 13/100
1102/1102 [==============================] - 0s 228us/sample - loss: 0.0720 - acc: 0.9737
Epoch 14/100
1102/1102 [==============================] - 0s 202us/sample - loss: 0.0613 - acc: 0.9828
Epoch 15/100
1102/1102 [==============================] - 0s 199us/sample - loss: 0.0379 - acc: 0.9864
Epoch 16/100
1102/1102 [==============================] - 0s 195us/sample - loss: 0.0194 - acc: 0.9964
Epoch 17/100
1102/1102 [==============================] - 0s 193us/sample - loss: 0.0094 - acc: 0.9973
Epoch 18/100
1102/1102 [==============================] - 0s 206us/sample - loss: 0.0044 - acc: 1.0000
Epoch 19/100
1102/1102 [==============================] - 0s 270us/sample - loss: 0.0115 - acc: 0.9973
Epoch 20/100
1102/1102 [==============================] - 0s 216us/sample - loss: 0.0059 - acc: 0.9991
Epoch 21/100
1102/1102 [==============================] - 0s 230us/sample - loss: 0.0022 - acc: 1.0000
Epoch 22/100
1102/1102 [==============================] - 0s 248us/sample - loss: 9.9990e-04 - acc: 1.0000
Epoch 23/100
1102/1102 [==============================] - 0s 332us/sample - loss: 6.0598e-04 - acc: 1.0000
Epoch 24/100
1102/1102 [==============================] - 0s 278us/sample - loss: 4.5729e-04 - acc: 1.0000
Epoch 25/100
1102/1102 [==============================] - 0s 331us/sample - loss: 3.7516e-04 - acc: 1.0000
Epoch 26/100
1102/1102 [==============================] - 0s 302us/sample - loss: 3.1528e-04 - acc: 1.0000
Epoch 27/100
1102/1102 [==============================] - 0s 284us/sample - loss: 2.7183e-04 - acc: 1.0000
Epoch 28/100
1102/1102 [==============================] - 0s 269us/sample - loss: 2.3833e-04 - acc: 1.0000
Epoch 29/100
1102/1102 [==============================] - 0s 269us/sample - loss: 2.1058e-04 - acc: 1.0000
Epoch 30/100
1102/1102 [==============================] - 0s 308us/sample - loss: 1.8836e-04 - acc: 1.0000
Epoch 31/100
1102/1102 [==============================] - 0s 327us/sample - loss: 1.7010e-04 - acc: 1.0000
Epoch 32/100
1102/1102 [==============================] - 0s 321us/sample - loss: 1.5294e-04 - acc: 1.0000
Epoch 33/100
1102/1102 [==============================] - 0s 309us/sample - loss: 1.3882e-04 - acc: 1.0000
Epoch 34/100
1102/1102 [==============================] - 0s 316us/sample - loss: 1.2984e-04 - acc: 1.0000
Epoch 35/100
1102/1102 [==============================] - 0s 285us/sample - loss: 1.1567e-04 - acc: 1.0000
Epoch 36/100
1102/1102 [==============================] - 0s 326us/sample - loss: 1.0566e-04 - acc: 1.0000
Epoch 37/100
1102/1102 [==============================] - 0s 313us/sample - loss: 9.7045e-05 - acc: 1.0000
Epoch 38/100
1102/1102 [==============================] - 0s 293us/sample - loss: 8.9739e-05 - acc: 1.0000
Epoch 39/100
1102/1102 [==============================] - 0s 294us/sample - loss: 8.2697e-05 - acc: 1.0000
Epoch 40/100
1102/1102 [==============================] - 0s 308us/sample - loss: 7.6338e-05 - acc: 1.0000
Epoch 41/100
1102/1102 [==============================] - 0s 288us/sample - loss: 7.1182e-05 - acc: 1.0000
Epoch 42/100
1102/1102 [==============================] - 0s 265us/sample - loss: 6.6391e-05 - acc: 1.0000
Epoch 43/100
1102/1102 [==============================] - 0s 251us/sample - loss: 6.2049e-05 - acc: 1.0000
Epoch 44/100
1102/1102 [==============================] - 0s 279us/sample - loss: 5.8737e-05 - acc: 1.0000
Epoch 45/100
1102/1102 [==============================] - 0s 261us/sample - loss: 5.4999e-05 - acc: 1.0000
Epoch 46/100
1102/1102 [==============================] - 0s 252us/sample - loss: 5.1336e-05 - acc: 1.0000
Epoch 47/100
1102/1102 [==============================] - 0s 301us/sample - loss: 4.8289e-05 - acc: 1.0000
Epoch 48/100
1102/1102 [==============================] - 0s 293us/sample - loss: 4.5310e-05 - acc: 1.0000
Epoch 49/100
1102/1102 [==============================] - 0s 334us/sample - loss: 4.2728e-05 - acc: 1.0000
Epoch 50/100
1102/1102 [==============================] - 0s 350us/sample - loss: 4.0264e-05 - acc: 1.0000
Epoch 51/100
1102/1102 [==============================] - 0s 291us/sample - loss: 3.7992e-05 - acc: 1.0000
Epoch 52/100
1102/1102 [==============================] - 0s 294us/sample - loss: 3.6641e-05 - acc: 1.0000
Epoch 53/100
1102/1102 [==============================] - 0s 336us/sample - loss: 3.3991e-05 - acc: 1.0000
Epoch 54/100
1102/1102 [==============================] - 0s 447us/sample - loss: 3.2139e-05 - acc: 1.0000
Epoch 55/100
1102/1102 [==============================] - 0s 317us/sample - loss: 3.0498e-05 - acc: 1.0000
Epoch 56/100
1102/1102 [==============================] - 0s 296us/sample - loss: 2.9056e-05 - acc: 1.0000
Epoch 57/100
1102/1102 [==============================] - 0s 273us/sample - loss: 2.7330e-05 - acc: 1.0000
Epoch 58/100
1102/1102 [==============================] - 0s 274us/sample - loss: 2.6012e-05 - acc: 1.0000
Epoch 59/100
1102/1102 [==============================] - 0s 260us/sample - loss: 2.4993e-05 - acc: 1.0000
Epoch 60/100
1102/1102 [==============================] - 0s 252us/sample - loss: 2.3834e-05 - acc: 1.0000
Epoch 61/100
1102/1102 [==============================] - 0s 265us/sample - loss: 2.2673e-05 - acc: 1.0000
Epoch 62/100
1102/1102 [==============================] - 0s 218us/sample - loss: 2.1442e-05 - acc: 1.0000
Epoch 63/100
1102/1102 [==============================] - 0s 235us/sample - loss: 2.0494e-05 - acc: 1.0000
Epoch 64/100
1102/1102 [==============================] - 0s 269us/sample - loss: 1.9590e-05 - acc: 1.0000
Epoch 65/100
1102/1102 [==============================] - 0s 301us/sample - loss: 1.8766e-05 - acc: 1.0000
Epoch 66/100
1102/1102 [==============================] - 0s 255us/sample - loss: 1.8031e-05 - acc: 1.0000
Epoch 67/100
1102/1102 [==============================] - 0s 246us/sample - loss: 1.7295e-05 - acc: 1.0000
Epoch 68/100
1102/1102 [==============================] - 0s 262us/sample - loss: 1.6616e-05 - acc: 1.0000
Epoch 69/100
1102/1102 [==============================] - 0s 252us/sample - loss: 1.5989e-05 - acc: 1.0000
Epoch 70/100
1102/1102 [==============================] - 0s 261us/sample - loss: 1.5274e-05 - acc: 1.0000
Epoch 71/100
1102/1102 [==============================] - 0s 249us/sample - loss: 1.4778e-05 - acc: 1.0000
Epoch 72/100
1102/1102 [==============================] - 0s 248us/sample - loss: 1.4200e-05 - acc: 1.0000
Epoch 73/100
1102/1102 [==============================] - 0s 249us/sample - loss: 1.3593e-05 - acc: 1.0000
Epoch 74/100
1102/1102 [==============================] - 0s 319us/sample - loss: 1.3129e-05 - acc: 1.0000
Epoch 75/100
1102/1102 [==============================] - 0s 319us/sample - loss: 1.2598e-05 - acc: 1.0000
Epoch 76/100
1102/1102 [==============================] - 0s 302us/sample - loss: 1.2155e-05 - acc: 1.0000
Epoch 77/100
1102/1102 [==============================] - 0s 292us/sample - loss: 1.1863e-05 - acc: 1.0000
Epoch 78/100
1102/1102 [==============================] - 0s 295us/sample - loss: 1.1516e-05 - acc: 1.0000
Epoch 79/100
1102/1102 [==============================] - 0s 312us/sample - loss: 1.0947e-05 - acc: 1.0000
Epoch 80/100
1102/1102 [==============================] - 0s 243us/sample - loss: 1.0535e-05 - acc: 1.0000
Epoch 81/100
1102/1102 [==============================] - 0s 281us/sample - loss: 1.0157e-05 - acc: 1.0000
Epoch 82/100
1102/1102 [==============================] - 0s 313us/sample - loss: 9.8193e-06 - acc: 1.0000
Epoch 83/100
1102/1102 [==============================] - 0s 237us/sample - loss: 9.4559e-06 - acc: 1.0000
Epoch 84/100
1102/1102 [==============================] - 0s 307us/sample - loss: 9.1788e-06 - acc: 1.0000
Epoch 85/100
1102/1102 [==============================] - 0s 279us/sample - loss: 8.8377e-06 - acc: 1.0000
Epoch 86/100
1102/1102 [==============================] - 0s 272us/sample - loss: 8.5510e-06 - acc: 1.0000
Epoch 87/100
1102/1102 [==============================] - 0s 236us/sample - loss: 8.3163e-06 - acc: 1.0000
Epoch 88/100
1102/1102 [==============================] - 0s 204us/sample - loss: 8.0540e-06 - acc: 1.0000s - loss: 7.7659e-06 - acc: 1.0
Epoch 89/100
1102/1102 [==============================] - 0s 235us/sample - loss: 7.8116e-06 - acc: 1.0000
Epoch 90/100
1102/1102 [==============================] - 0s 213us/sample - loss: 7.5458e-06 - acc: 1.0000
Epoch 91/100
1102/1102 [==============================] - 0s 287us/sample - loss: 7.2989e-06 - acc: 1.0000
Epoch 92/100
1102/1102 [==============================] - 0s 240us/sample - loss: 7.0700e-06 - acc: 1.0000
Epoch 93/100
1102/1102 [==============================] - 0s 226us/sample - loss: 6.8565e-06 - acc: 1.0000
Epoch 94/100
1102/1102 [==============================] - 0s 282us/sample - loss: 6.6438e-06 - acc: 1.0000
Epoch 95/100
1102/1102 [==============================] - 0s 339us/sample - loss: 6.4767e-06 - acc: 1.0000
Epoch 96/100
1102/1102 [==============================] - 0s 242us/sample - loss: 6.2694e-06 - acc: 1.0000
Epoch 97/100
1102/1102 [==============================] - 0s 198us/sample - loss: 6.0600e-06 - acc: 1.0000
Epoch 98/100
1102/1102 [==============================] - 0s 322us/sample - loss: 5.8852e-06 - acc: 1.0000
Epoch 99/100
1102/1102 [==============================] - 0s 266us/sample - loss: 5.7223e-06 - acc: 1.0000
Epoch 100/100
1102/1102 [==============================] - 0s 287us/sample - loss: 5.5479e-06 - acc: 1.0000
In [45]:
y_pred = model.predict(X_test)
y_pred = (y_pred > 0.5)
In [46]:
plt.plot(epochs_hist.history['loss'])
plt.title('Model Loss Progress During Training')
plt.xlabel('Epoch')
plt.ylabel('Training Loss')
Out[46]:
Text(0, 0.5, 'Training Loss')
In [47]:
plt.plot(epochs_hist.history['acc'])
plt.title('Model Accuracy Progress During Training')
plt.xlabel('Epoch')
plt.ylabel('Training Accuracy')
Out[47]:
Text(0, 0.5, 'Training Accuracy')
In [48]:
sn = confusion_matrix(y_test, y_pred)
ax = sns.heatmap(sn, annot = True, cmap = 'PuBu')
bottom, top = ax.get_ylim()
ax.set_ylim(bottom + 0.5, top - 0.5)
Out[48]:
(2.0, 0.0)
In [49]:
print(classification_report(y_test, y_pred))
              precision    recall  f1-score   support

           0       0.89      0.97      0.93       306
           1       0.76      0.40      0.53        62

    accuracy                           0.88       368
   macro avg       0.82      0.69      0.73       368
weighted avg       0.87      0.88      0.86       368

In [ ]: