Cardiovascular disease kills 17.9 million people annually — 32% of all global deaths (WHO, 2023). This notebook performs a deep, statistically validated EDA on the UCI Cleveland dataset to discover which clinical markers most strongly predict coronary artery disease (CAD), forming the analytical foundation for a robust ML pipeline.
Data Foundation
1 · Environment Setup
2 · Data Ingestion & Schema
3 · Data Quality Audit
Univariate Exploration
4 · Continuous Feature Distributions
5 · Categorical Feature Frequencies
6 · Target Class Balance
Bivariate & Statistical
7 · Continuous vs Target (Mann-Whitney U)
8 · Categorical vs Target (Chi-Square)
Multivariate & Advanced
9 · Correlation & Multicollinearity
10 · Outlier & Skewness Analysis
11 · Feature Engineering Preview
12 · Clinical Conclusions
Environment Setup
#FFFFFF)
provides excellent contrast for the jade/emerald accent colours without causing eye strain.
Libraries imported | Jade theme active | Dark mode on NumPy 1.26.4 | Pandas 3.0.3 | Seaborn 0.13.2
Data Ingestion & Schema
cp = 0,1,2,3) for a continuous variable leads to incorrect statistical analyses and misleading visualisations.
Dataset shape : 303 rows x 14 columns Memory usage : 33.3 KB
| age | sex | cp | trestbps | chol | fbs | restecg | thalach | exang | oldpeak | slope | ca | thal | target | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 63 | 1 | 3 | 145 | 233 | 1 | 0 | 150 | 0 | 2.3 | 0 | 0 | 1 | 1 |
| 1 | 37 | 1 | 2 | 130 | 250 | 0 | 1 | 187 | 0 | 3.5 | 0 | 0 | 2 | 1 |
| 2 | 41 | 0 | 1 | 130 | 204 | 0 | 0 | 172 | 0 | 1.4 | 2 | 0 | 2 | 1 |
| 3 | 56 | 1 | 1 | 120 | 236 | 0 | 1 | 178 | 0 | 0.8 | 2 | 0 | 2 | 1 |
| 4 | 57 | 0 | 0 | 120 | 354 | 0 | 1 | 163 | 1 | 0.6 | 2 | 0 | 2 | 1 |
| 5 | 57 | 1 | 0 | 140 | 192 | 0 | 1 | 148 | 0 | 0.4 | 1 | 0 | 1 | 1 |
| 6 | 56 | 0 | 1 | 140 | 294 | 0 | 0 | 153 | 0 | 1.3 | 1 | 0 | 2 | 1 |
| 7 | 44 | 1 | 1 | 120 | 263 | 0 | 1 | 173 | 0 | 0.0 | 2 | 0 | 3 | 1 |
| Semantic Type | Clinical Description | |
|---|---|---|
| Feature | ||
| age | Continuous | Patient age in years |
| sex | Binary | 1 = Male, 0 = Female |
| cp | Nominal | Chest-pain type: 0=typical angina, 1=atypical,... |
| trestbps | Continuous | Resting blood pressure at admission (mm Hg) |
| chol | Continuous | Serum cholesterol (mg/dl) |
| fbs | Binary | Fasting blood sugar > 120 mg/dl (1 = True) |
| restecg | Nominal | Resting ECG result (0=normal, 1=ST-T abnormali... |
| thalach | Continuous | Maximum heart rate achieved in stress test (bpm) |
| exang | Binary | Exercise-induced angina (1 = Yes) |
| oldpeak | Continuous | ST depression induced by exercise relative to ... |
| slope | Ordinal | Slope of peak-exercise ST segment (0=up, 1=fla... |
| ca | Ordinal | Number of major vessels coloured by fluoroscop... |
| thal | Nominal | Thallium stress test result (0=normal, 1=fixed... |
| target | Binary | Heart disease present (1) or absent (0) — pred... |
Data Quality Audit
WARNING: 1 duplicate row(s) found and removed.
Total missing cells: 0 | All columns complete! Feature Min Max Low_viol Hi_viol Status ---------------------------------------------------------------- age 29.00 77.00 0 0 OK trestbps 94.00 200.00 0 0 OK chol 126.00 564.00 0 0 OK thalach 71.00 202.00 0 0 OK oldpeak 0.00 6.20 0 0 OK
Continuous Feature Distributions
- Histogram + KDE — shows shape, mean (amber), median (white), shaded ±1σ region, and a stats annotation box
- Q-Q Plot — tests normality; points on the reference line = Gaussian, deviations = skew/heavy tails
| Mean | Median | Std | Min | Max | Skewness | Kurtosis | CV (%) | |
|---|---|---|---|---|---|---|---|---|
| Feature | ||||||||
| age | 54.42 | 55.50 | 9.05 | 29.00 | 77.00 | -0.20 | -0.54 | 16.60 |
| trestbps | 131.60 | 130.00 | 17.56 | 94.00 | 200.00 | 0.72 | 0.89 | 13.30 |
| chol | 246.50 | 240.50 | 51.75 | 126.00 | 564.00 | 1.15 | 4.45 | 21.00 |
| thalach | 149.57 | 152.50 | 22.90 | 71.00 | 202.00 | -0.53 | -0.08 | 15.30 |
| oldpeak | 1.04 | 0.80 | 1.16 | 0.00 | 6.20 | 1.27 | 1.52 | 111.40 |
- age: Nearly symmetric — StandardScaler is appropriate
- trestbps: Right-skewed (hypertensive tail) — Yeo-Johnson recommended
- chol: Heavily right-skewed with extreme outliers >400 mg/dl — Box-Cox/log transform essential
- thalach: Slightly left-skewed — StandardScaler acceptable
- oldpeak: Strongly right-skewed (most patients = 0) — Yeo-Johnson required (handles zeros)
Categorical Feature Frequencies
Target Class Balance
Class 1 (Heart Disease ): 164 samples (54.3%) Class 0 (No Disease ): 138 samples (45.7%) Balance ratio: 0.841 | Well balanced - no resampling needed.
Continuous Features vs Target — Mann-Whitney U
Since several features (especially
oldpeak, chol) are non-normally distributed (confirmed by Q-Q plots), Student's t-test assumptions are violated. Mann-Whitney U is a non-parametric rank-based test that makes no distributional assumptions — the statistically correct choice here.
The violin + KDE comparison design simultaneously shows distribution shape and summary statistics — significantly more informative than a plain box-plot.
Mann-Whitney U Test Results:
U-stat p-value Significance Effect Size (d) Disease Mean No-Disease Mean
Feature
age 14394.0 4.63e-05 p<0.001 *** 0.444 52.59 56.60
trestbps 12931.0 3.22e-02 p<0.05 * 0.293 129.25 134.40
chol 12850.5 4.24e-02 p<0.05 * 0.163 242.64 251.09
thalach 5725.0 1.40e-13 p<0.001 *** 0.842 158.38 139.10
oldpeak 16722.5 3.35e-13 p<0.001 *** 0.860 0.59 1.59
Categorical Features vs Target — Chi-Square
Stacked bars normalised to 100% allow direct visual comparison of disease proportions regardless of group size. Cramer's V measures practical significance beyond the raw p-value.
Chi-Square Test Results:
Chi2 df p-value Cramer's V Sig
Feature
thal 84.61 3 3.15e-18 0.529 ***
cp 80.98 3 1.89e-17 0.518 ***
ca 73.69 4 3.77e-15 0.494 ***
exang 55.46 1 9.56e-14 0.429 ***
slope 46.89 2 6.58e-11 0.394 ***
sex 23.08 1 1.55e-06 0.276 ***
restecg 9.73 2 7.71e-03 0.179 **
fbs 0.09 1 7.61e-01 0.017 ns
Correlation & Multicollinearity
High inter-feature correlations (|r| > 0.5): oldpeak vs slope r = -0.576
Outlier & Skewness Analysis
Feature Q1 Q3 IQR Lo_Fence Hi_Fence #Out Pct% --------------------------------------------------------------------------- age 48.00 61.00 13.00 28.50 80.50 0 0.0% trestbps 120.00 140.00 20.00 90.00 170.00 9 3.0% chol 211.00 274.75 63.75 115.38 370.38 5 1.7% thalach 133.25 166.00 32.75 84.12 215.12 1 0.3% oldpeak 0.00 1.60 1.60 -2.40 4.00 5 1.7%
Feature Engineering Preview
hr_reserve_pct— percentage of age-predicted max HR achieved (lower = impaired cardiac response)ischaemia_load— oldpeak x (1 + exang): combined ischaemic burden scorechol_age_ratio— age-adjusted cholesterol burden
Feature-Target Correlation (engineered features highlighted):
[NEW] ischaemia_load |r| = 0.481
oldpeak |r| = 0.429
thalach |r| = 0.420
[NEW] hr_reserve_pct |r| = 0.363
age |r| = 0.221
trestbps |r| = 0.146
[NEW] chol_age_ratio |r| = 0.092
chol |r| = 0.081
Clinical Conclusions & Modelling Recommendations
- Zero missing values in any column
- No clinically implausible range violations
- Near-perfect class balance (54.6% / 45.4%)
- 1 duplicate row removed
- Small dataset (302 rows) — high variance risk
- 3 features are right-skewed — need transforms
- Outliers in chol/trestbps — robust scaling
- fbs is NOT a significant predictor
Nominal: cp, restecg, thal --> OneHotEncoder(drop='first')
Binary: sex, fbs, exang --> PassThrough
Ordinal: slope, ca --> PassThrough
Engineered: hr_reserve_pct, ischaemia_load --> StandardScaler
fbs EXCLUDED: chi-square p=0.76, Cramer's V = 0.02
Evaluation: Stratified 5-Fold CV · Primary = Recall (Class 1) · Secondary = F1-macro · Threshold tuning via PR curve
This EDA establishes a statistically rigorous, clinically grounded foundation for building a high-performance heart disease prediction model.
All feature decisions, transformations and model choices are evidence-driven — not arbitrary.
Authored as part of a professional data science portfolio — Kaggle & Upwork.