Reading Time: 10 minutes




Stroke is the fifth leading cause of death and disability in the United States according to the American Heart Association. Every 40 seconds in the US, someone experiences a stroke, and every four minutes, someone dies from it according to the CDC. A recent figure of stroke-related cost almost reached $46 billion. With my interest in healthcare and parents aging into a new decade, I chose this Stroke Prediction Dataset from Kaggle for my Python project. 


Through this project, I will explore which factors are the leading drivers for stroke and build a descriptive model using Machine Learning to bring awareness to individuals and help healthcare providers and insurers estimate risk and cost.  


The Kaggle dataset is used to predict whether a patient is likely to get a stroke based on dependent variables like gender, age, various health conditions, and smoking status.  Each row in the data provides relevant information about the patient; there are 5110 observations with 12 features.  Of the features, 3 were numeric and continuous whereas the rest of the 8 features were categorical (7 dependent and 1 independent).  The target feature ‘stroke’ was binary and therefore classification modeling was used.  


Exploratory Data Analysis

One of the very first things noticed was that the ‘bmi’ (Body Mass Index) feature was the only feature that had null values.  The null values only made up 3.9% of the whole dataset. That seemed negligible until I realized upon further check that 20% of them made up 16% of all the strokes in the dataset.  So in order to keep all of the stroke positive observations, I filled the null values with the mean bmi.  This brings me to the next discovery of the dataset – the stroke percentage was only 4.9%. That meant that the dataset is imbalanced, making it hard for predictive modeling to classify correctly.  This imbalance issue had to be addressed before doing any modeling:

imbalance 339892 mTLSzkJm |

Next,  the ‘id’ field was dropped because it was a unique identifier for the patients which was not useful for any modeling purposes as a feature.  Then I started to dig-in to the numbers by first looking at the numeric features.  


Numeric Features:

A heatmap correlation was done on the 3 numeric features – ‘age’, ‘bmi’, and  ‘avg_glucose_level.’It revealed  that they were weakly correlated with each other:

heatmap 776082 q5C0j01V |

As for the distribution, I contrasted each of them with respect to the presence of Stroke to see the difference:

agedistribution 788401 MSHLS47o |

The plot above makes it clear that the older you get, the higher your chance of experiencing a stroke becomes. That risk increases dramatically after the age of 50.

bmidistribution 239543 2j2v95Ry |

Interestingly, the plot above shows results that are contrary to my assumption of  a higher correlation between BMI and stroke.  My thinking was that higher BMI correlated to a  high body fat percentage in general. However,  the plot shows that high BMI is not necessarily a significant factor. There is  just a slight increase in the bmi range of overweight and obese (beyond the >25 bmi).  

Here is the guide for BMI according to National Institute of Health (NIH) for reference: 

A BMI of less than 18.5 means that a person is underweight.

A BMI of between 18.5 and 24.9 is ideal.

A BMI of between 25 and 29.9 is overweight.

A BMI over 30 indicates obesity.

bloodsugardistribution 145727 |

It can be seen from the distribution that most people in the set are in healthy range of blood sugar with the exception of some people who have higher than 180 mg/dL having above normal levels of blood sugar, making up 11% of the records. Upon further investigation, these same 11% of people who have higher than 180mg/dL accounted for 32% or a third of all strokes.  

From the Blood Sugar and Stroke Density Distribution above, there’s no clear correlation between a high avg_glucose_level and the risk of stroke. However, an explanation for the rise in stroke probability density among the higher than 180mg/dL glucose level group could be attributed to the presence of diabetes. According to the American Diabetes Association, a reading between 180-200mg/dL is categorized as prediabetic, and a reading of more than 200mg/dL falls within the diabetic category.  Given that someone who has  diabetes has 1.5 times higher odds of having a stroke, this could be a very probable explanation for the 2nd bell-curve of stroke in the plot above.  


Here is the guide for Average Glucose level according to experts for reference: 

Less than 70 means blood sugar is below normal levels and requires treatment.

71-90 means blood sugar should be monitored and treated as necessary.

90-140 means normal. 

140-199 indicates prediabetes.

Higher than 200 indicates diabetes.  


Categorical Features 

In order to explore the categorical features – since many of them were binary fields with yes or no answer, I used bar charts to first show the attribute amount/count and then on a separate graph, showed the stroke percentage within each attribute to observe any trend.  Here for the blog, I included the stacked bar charts with the percentage of strokes within each sub-category that showed some trends:

evermarried 981925 faeVbskQ |heartdisease 405031 IKFNS9il |hypertension 298020 LrSsHIUu |smokingstatus 700778 zcFhIkIQ |worktype 226906 FtBuodNA |


Out of the 7 categorical features, both ‘gender’ and ‘Residence_type’ (urban vs rural) didn’t have much difference in each of its percentage of stroke.  For the rest of the 5 features shown above, having been married and having heart disease as well as hypertension do matter and increase the risk of stroke.  Also, having formerly smoked and currently smoking seem to have a slight increase compared to people who have never smoked or in the unknown category.  As for the work_type feature, the Never_worked and children categories don’t have any presence of stroke which makes sense.  

These bar charts seemed to be intuitive until I did further investigation and cross-referenced each of them with the one feature that showed the most stark trend so far – ‘age.’  I found that there were correlations in most of the categorical features with respect to ‘age.’  Notice the ‘age’ in each of the following tables of categorical features with respect to the presence of stroke (1):

evermarriedtable 394713 |heartdiseasetable 339546 Vw8AMSvC |hypertensiontable 099457 hjkslMR6 |smokingstatustable 884114 8fQ5G4ZX |worktypetable 973752 BWOSckZc |


Thus the impact of ‘age’ is seen in each of the categorical features indicating that the increase of stroke percentage in each subcategory is not entirely due to its own merit but to ‘age’ as well.  Later on this will cause multicollinearity among our predictor variables that will need to be handled before modeling.  


EDA Insight & Learnings:

1) Age is a strong driving factor for the risk of stroke. 

2) Contrary to my assumption, BMI was not highly correlated to risk of Stroke. This came as a surprise as BMI is used to diagnose obesity which is often linked to other risks like heart disease and stroke.

3) Blood sugar was not correlated to stroke risk however, diabetes is a risk for stroke because it raises the risk by 1.5 times if your avg_glucose_level is greater than 200mg/dL reaching the diabetic category and that was reflected in this dataset.

4) Sometimes what appears to be a correlation on the surface isn’t. For example, attributes like Heart disease, hypertension, ever_married and smoking_status all upon further analysis, pointed to age.

5) When dealing with null values, it’s good to check what impact they may have in your target feature before removing them. It was found that 20% of the missing BMI values made up 1/6th (16%) of all strokes. 


Feature Engineering

Before feature engineering and modeling, first I checked logistic regression assumptions to see which ones I have yet to satisfy:

The logistic regression assumes that there is minimal or no multicollinearity among the independent variables. (The Correlation Heatmap showed no collinearity among the Numeric Features but Variance Inflation Factor will be used later on to further check this)

The logistic regression assumes that the independent variables are linearly related to the log of odds: 

ageassumption 196092 PeZupvhK |bmiassumption 114039 hQ0dZ5e1 |bloodsugarassumption 160879 gJhVcqt4 |   


Logistic regression usually requires a large sample size to predict properly. (will Upsample the stroke data using SMOTE technique)

The logistic regression with two classes assumes that the dependent variable is binary (already binary)

Logistic regression assumes the observations to be independent of each other. (independent as far as the source goes – no duplicate subjects)

In order to fulfill the rest of the assumptions and perform feature engineering, we first label encoded the binary features – ‘gender’(Male 1), ‘ever_married’(Yes 1), ‘Residence_type’(Urban 1).  Then tried ordinally encoding the features – ‘smoking_status’ along with ‘work_type’ and label encoding the numeric features into binary – ‘age’(over 50 or not), ‘bmi’(over 25 or not), ‘avg_glucose_level’(over 180 or not).  After trying different types of feature encoding and modeling multiple times, it was found that the best training accuracy score was obtained from keeping all of the numeric features as original and only ordinal-encoding the ‘work_type’ while turning the ‘smoking_status’ into a binary variable (having smoked or not).


Feature Selection

For feature selection, chi-square test was used.  Three features – ‘smoking_status,’ ‘gender,’ and ‘Residence_type’– were found to have p-values higher than 0.05 indicating that they have an insignificant effect on the log odds of experiencing stroke.  However, after converting ‘smoking_status’ from an ordinally encoded to binary encoded, the p-value decreased, and ‘smoking_status’ came to have a significant effect on the risk of stroke.  ‘Residence_type’ and ‘gender’ were withheld from being dropped in order to see further supporting evidence.  

Variance Inflation Factor was used to detect multicollinearity among the predictor variables. ‘Work_type’ was found to have the highest VIF value of 19.25 and was dropped.  ‘Bmi’ had the second highest VIF value of 14.83 the first time around and then lowered to a value of 9.05 after dropping ‘work_type,’ but ‘bmi’ was withheld from being dropped to see further supporting evidence.  


Now that some feature selection analysis is done and the issue of multicollinearity addressed, the data set was prepped for modeling by first being split into train and test in a stratified fashion with a 70-30% ratio.  Next, the training dataset minority class was upsampled from about 5% to 20% using SMOTE, an oversampling technique that generates synthetic samples from the minority class to obtain class-balanced training dataset.  

With the training data upsampled, it was ready to start modeling. For modeling, I implemented API formula method for model interpretability, utilized Logistic Regression with GridSearch to find best hyperparameters for my linear model and Random Forest for my non-linear model to pick up any non-linear relation and associations missed by linear model.  

API formula method 

Statsmodels API logit model was used for model interpretability.  From the model summary, ‘bmi’ feature had an insignificant effect on the log odds of getting stroke indicated by z value greater than 0.05.  This further supported the earlier finding of ‘bmi’ having a high VIF value which indicates multicollinearity.  Thus the ‘bmi’ feature was dropped.  From here on, 8 features were used for predictive modeling to classify the target variable of stroke.  

Logistic Regression 

To find the optimal hyperparameters, GridSearch with KFold cross-validation was used.  The best parameters were chosen as {‘C’: 4.2813, ‘penalty’: ‘l2’} with the following scores:

linearmodelresult 342001 zKPOnN5I |

 The following shows the Logistic Regression with Ridge coefficients: 

logregridgecoef 309207 cpaRfQI3 |

Random Forest 

To capture any non-linear dynamic and relation of the features with the target variable, Random Forest was used with Randomized Grid Search to yield the following best hyperparameters and scores:

rfbesthyperparameters 405409 r0iwFYaN |randomforestresult 458119 EaERz1NO |

Also, Feature Importance was extracted from the Random Forest model to show which features were the most explanatory in predicting stroke:

rffeatureimportance 820294 VQkiSlLk |


From the two types of models,  Random Forest performed best with the following mean accuracy scores (it also performed better in terms of ‘roc_auc’ score):  

modelcomparison 622233 jK8wqXkH |

Finally, it was seen from both models that compared to all of the other features, ‘age’ and ‘average glucose level’ were the most important predictors of stroke, respectively, together accounting for more than 80% of the variance in the risk of stroke.

Lastly, utilizing the API formula method from statsmodels, the following was interpreted from the model summary:

  • for every year a person gets older, the odds of experiencing a stroke increases by a factor of 1.08
  • for every unit increase in a person’s average glucose level, the odds of experiencing a stroke increases by a factor of 1.01
  • for people who have hypertension, the odds of experiencing stroke increases by a factor of 0.61 on average
  • for people who smoke or have smoked, the odds of experiencing stroke increases by a factor of 0.59 on average
  • for people who have been married, the odds of experiencing stroke increases by a factor of 0.52 on average
  • for people who have heart disease, the odds of experiencing stroke increases by a factor of 0.45 on average
  • for men, the odds of experiencing stroke increases by a factor of 0.44 on average compared to women
  • for people who live in an urban setting, the odds of experiencing stroke increases by a factor of 0.41 on average




Source link

Spread the Word!