A real, deliberately messy clinical dataset: 920 patients assessed for coronary artery disease at four institutions (Cleveland, Hungary, Switzerland and the Long Beach VA). Unlike the simulated teaching sets in datarium, it ships close to raw — integer-coded categorical variables, substantial and uneven missingness across sites, and a multi-level outcome — so it can be used to teach the "clean the data before you analyse it" step ahead of logistic regression, chi-square tests and group comparisons. The values are the original UCI codes and are not relabelled; see the data-raw/heartdisease/heart-disease.names codebook.

For a worked tutorial on this analysis, see the Datanovia lesson “Logistic Regression in R: Model a Binary Outcome” (https://www.datanovia.com/learn/biostatistics/regression/logistic-regression-in-r).

data("heartdisease")

Format

A data frame with 920 rows and 15 columns. The missing marker "?" in the source has been converted to NA; missingness is heavy and very uneven across sites (see colSums(is.na(heartdisease))).

age

age, in years.

sex

sex, integer-coded: 1 = male, 0 = female.

cp

chest pain type: 1 = typical angina, 2 = atypical angina, 3 = non-anginal pain, 4 = asymptomatic.

trestbps

resting blood pressure (mm Hg on admission to hospital).

chol

serum cholesterol (mg/dl). Note: 172 patients are recorded with 0 — all 123 of the Switzerland site's patients and a further 49 at the Long Beach VA site — where 0 means "not measured" rather than a true value: a real missing-data trap to handle before analysis.

fbs

fasting blood sugar > 120 mg/dl: 1 = true, 0 = false.

restecg

resting electrocardiographic results: 0 = normal, 1 = ST-T wave abnormality, 2 = probable or definite left ventricular hypertrophy (Estes' criteria).

thalach

maximum heart rate achieved.

exang

exercise-induced angina: 1 = yes, 0 = no.

oldpeak

ST depression induced by exercise relative to rest.

slope

slope of the peak exercise ST segment: 1 = upsloping, 2 = flat, 3 = downsloping.

ca

number of major vessels (0–3) coloured by fluoroscopy.

thal

thallium stress-test result: 3 = normal, 6 = fixed defect, 7 = reversible defect.

num

diagnosis of heart disease (angiographic disease status): 0 = < 50% diameter narrowing (no disease); 1–4 = > 50% narrowing (disease present). It is commonly binarised to absence (0) vs presence (> 0).

dataset

the collecting site, a factor with levels "cleveland", "hungarian", "switzerland" and "va".

Source

Heart Disease, UCI Machine Learning Repository (doi:10.24432/C52P4X ). Real patient data collected by the Hungarian Institute of Cardiology, Budapest; University Hospital, Zurich; University Hospital, Basel; and the V.A. Medical Center, Long Beach, and shared by the Cleveland Clinic Foundation. This dataset combines the four processed.<site>.data files (the 14 commonly-used attributes of the original 76), converting the "?" marker to NA and keeping the raw values otherwise unchanged; the source files and codebook are in data-raw/heartdisease/. Distributed under the Creative Commons Attribution 4.0 International (CC BY 4.0) licence; when using the data please cite Janosi et al. (1989) (see references).

References

Janosi, A., Steinbrunn, W., Pfisterer, M., & Detrano, R. (1989). Heart Disease [Dataset]. UCI Machine Learning Repository. doi:10.24432/C52P4X .

Detrano, R., Janosi, A., Steinbrunn, W., Pfisterer, M., Schmid, J. J., Sandhu, S., Guppy, K. H., Lee, S., & Froelicher, V. (1989). International application of a new probability algorithm for the diagnosis of coronary artery disease. The American Journal of Cardiology, 64(5), 304–310.

See also

Examples

data("heartdisease")

# Real data is messy: missingness is heavy and very uneven across sites
colSums(is.na(heartdisease))
#>      age      sex       cp trestbps     chol      fbs  restecg  thalach 
#>        0        0        0       59       30       90        2       55 
#>    exang  oldpeak    slope       ca     thal      num  dataset 
#>       55       62      309      611      486        0        0 
table(heartdisease$dataset)
#> 
#>   cleveland   hungarian switzerland          va 
#>         303         294         123         200 

# The Cleveland site is the most complete; use it for a first model
cleveland <- subset(heartdisease, dataset == "cleveland")

# Binarise the 0-4 angiographic outcome into disease present/absent
cleveland$disease <- as.integer(cleveland$num > 0)

# Logistic regression of disease on age, sex and maximum heart rate
fit <- glm(disease ~ age + sex + thalach, family = binomial, data = cleveland)
summary(fit)
#> 
#> Call:
#> glm(formula = disease ~ age + sex + thalach, family = binomial, 
#>     data = cleveland)
#> 
#> Coefficients:
#>              Estimate Std. Error z value Pr(>|z|)    
#> (Intercept)  3.111610   1.607466   1.936   0.0529 .  
#> age          0.031886   0.016440   1.940   0.0524 .  
#> sex          1.491902   0.307193   4.857 1.19e-06 ***
#> thalach     -0.040541   0.007073  -5.732 9.93e-09 ***
#> ---
#> Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
#> 
#> (Dispersion parameter for binomial family taken to be 1)
#> 
#>     Null deviance: 417.98  on 302  degrees of freedom
#> Residual deviance: 332.85  on 299  degrees of freedom
#> AIC: 340.85
#> 
#> Number of Fisher Scoring iterations: 4
#> 

# Chi-square test: is disease associated with sex (all sites)?
heartdisease$disease <- as.integer(heartdisease$num > 0)
chisq.test(table(heartdisease$sex, heartdisease$disease))
#> 
#> 	Pearson's Chi-squared test with Yates' continuity correction
#> 
#> data:  table(heartdisease$sex, heartdisease$disease)
#> X-squared = 85.361, df = 1, p-value < 2.2e-16
#>