R/heartdisease.R
heartdisease.RdA 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")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, in years.
sex, integer-coded: 1 = male, 0 = female.
chest pain type: 1 = typical angina, 2 = atypical
angina, 3 = non-anginal pain, 4 = asymptomatic.
resting blood pressure (mm Hg on admission to hospital).
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.
fasting blood sugar > 120 mg/dl: 1 = true, 0 = false.
resting electrocardiographic results: 0 = normal,
1 = ST-T wave abnormality, 2 = probable or definite left
ventricular hypertrophy (Estes' criteria).
maximum heart rate achieved.
exercise-induced angina: 1 = yes, 0 = no.
ST depression induced by exercise relative to rest.
slope of the peak exercise ST segment: 1 = upsloping,
2 = flat, 3 = downsloping.
number of major vessels (0–3) coloured by fluoroscopy.
thallium stress-test result: 3 = normal, 6 = fixed
defect, 7 = reversible defect.
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).
the collecting site, a factor with levels "cleveland",
"hungarian", "switzerland" and "va".
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).
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.
Datanovia tutorial: Logistic Regression in R: Model a Binary Outcome.
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
#>