age sex cp trestbps chol fbs restecg thalach exang oldpeak slope ca thal
1 52 1 0 125 212 0 1 168 0 1.0 2 2 3
2 53 1 0 140 203 1 0 155 1 3.1 0 0 3
3 70 1 0 145 174 0 1 125 1 2.6 0 0 3
4 61 1 0 148 203 0 1 161 0 0.0 2 1 3
5 62 0 0 138 294 1 1 106 0 1.9 1 3 2
6 58 0 0 100 248 0 0 122 0 1.0 1 0 2
target
1 0
2 0
3 0
4 0
5 0
6 1
Predicting Maximum Heart Rate
Cross-Sectional Analysis of Heart Health Data
Introduction
Heart health can be influenced by many different factors, including age, blood pressure, cholesterol, and a person’s response to exercise. Understanding the relationships between these characteristics can help us better understand cardiovascular health.
For this project, we analyze a cross-sectional heart health dataset. Each observation represents a patient, and the dataset contains both quantitative and qualitative variables related to cardiovascular health.
Our main research question is:
What factors are associated with a patient’s maximum heart rate during exercise?
Our dependent variable, or Y variable, is thalach, which represents the maximum heart rate achieved by a patient.
Maximum heart rate is useful to study because it reflects how a patient’s cardiovascular system responds during exercise. Understanding which patient characteristics are associated with maximum heart rate can help us better describe differences in exercise response across patients.
We will investigate whether characteristics such as age, heart disease status, sex, chest pain type, exercise-induced angina, and ST depression can help explain differences in maximum heart rate.
Setup
First, we load the packages that will be used throughout our analysis.
The tidyverse package is used for data cleaning and visualization. The knitr package is used to create cleaner tables, and stargazer is used to present the three regression specifications together in a professional regression table.
Importing the Data
We begin by importing the original heart.csv file.
We can view the first six observations to make sure the dataset imported correctly.
Next, we check the dimensions of the dataset.
[1] 1025 14
The first number represents the number of observations, while the second number represents the number of variables.
Understanding the Data
We can examine the structure of the original dataset using str().
'data.frame': 1025 obs. of 14 variables:
$ age : int 52 53 70 61 62 58 58 55 46 54 ...
$ sex : int 1 1 1 1 0 0 1 1 1 1 ...
$ cp : int 0 0 0 0 0 0 0 0 0 0 ...
$ trestbps: int 125 140 145 148 138 100 114 160 120 122 ...
$ chol : int 212 203 174 203 294 248 318 289 249 286 ...
$ fbs : int 0 1 0 0 1 0 0 0 0 0 ...
$ restecg : int 1 0 1 1 1 0 2 0 0 0 ...
$ thalach : int 168 155 125 161 106 122 140 145 144 116 ...
$ exang : int 0 1 1 0 0 0 0 1 0 1 ...
$ oldpeak : num 1 3.1 2.6 0 1.9 1 4.4 0.8 0.8 3.2 ...
$ slope : int 2 0 0 2 1 1 0 1 2 1 ...
$ ca : int 2 0 0 1 3 0 3 1 0 2 ...
$ thal : int 3 3 3 3 2 2 1 3 3 2 ...
$ target : int 0 0 0 0 0 1 0 0 0 0 ...
The dataset contains the following variables:
age: Age of the patient in yearssex: Sexcp: Chest pain typetrestbps: Resting blood pressurechol: Serum cholesterolfbs: Fasting blood sugar categoryrestecg: Resting ECG resultthalach: Maximum heart rate achievedexang: Exercise-induced anginaoldpeak: ST depression induced by exerciseslope: Slope of the peak exercise ST segmentca: Number of major vesselsthal: Thalassemia categorytarget: Heart disease status
Quantitative Variables
Our dataset contains several quantitative variables, including:
age— age in yearstrestbps— resting blood pressurechol— cholesterolthalach— maximum heart rateoldpeak— ST depression
This gives us at least four quantitative variables as required by the project.
Qualitative Variables
Several variables are represented by numbers in the raw dataset but actually represent categories.
These include:
sexcpfbsrestecgexangslopethaltarget
This gives us at least four qualitative variables as required by the project.
Data Source, Unit of Observation, and Measurement Levels
Data Source
The raw file used in this project is heart.csv.
Before submitting, replace this sentence with the exact source from which your group obtained the file (for example, the course page, Kaggle page, or another repository) and include the source citation/link in the Appendix. The source is not stated in the materials currently available, so it should not be guessed.
Unit of Observation
The unit of observation is one patient. Each row contains characteristics and heart-health measurements for an individual patient.
Variable Types and Levels of Measurement
The table below identifies the major variables, whether they are quantitative or qualitative, and how they are treated in this analysis.
| Variable | Description | Type | Measurement Level |
|---|---|---|---|
| age | Age in years | Quantitative | Ratio |
| trestbps | Resting blood pressure | Quantitative | Ratio |
| chol | Serum cholesterol | Quantitative | Ratio |
| thalach | Maximum heart rate achieved | Quantitative | Ratio |
| oldpeak | ST depression induced by exercise | Quantitative | Continuous |
| sex | Sex category | Qualitative | Nominal |
| cp | Chest pain type | Qualitative | Nominal |
| fbs | Fasting blood sugar category | Qualitative | Nominal |
| restecg | Resting ECG category | Qualitative | Nominal |
| exang | Exercise-induced angina | Qualitative | Nominal |
| slope | Slope of peak exercise ST segment | Qualitative | Ordinal category |
| thal | Thalassemia category | Qualitative | Nominal |
| target | Heart disease status | Qualitative | Nominal |
Data Cleaning
The rubric requires us to preserve the original imported data and create a separate cleaned dataset. Therefore, heart_raw remains unchanged and all cleaning is performed on a new object called heart_clean.
Checking Missing Values
age sex cp trestbps chol fbs restecg thalach
0 0 0 0 0 0 0 0
exang oldpeak slope ca thal target
0 0 0 0 0 0
Checking for Duplicates
[1] 723
Creating the Cleaned Dataset
[1] 302 14
'data.frame': 302 obs. of 14 variables:
$ age : int 52 53 70 61 62 58 58 55 46 54 ...
$ sex : Factor w/ 2 levels "0","1": 2 2 2 2 1 1 2 2 2 2 ...
$ cp : Factor w/ 4 levels "0","1","2","3": 1 1 1 1 1 1 1 1 1 1 ...
$ trestbps: int 125 140 145 148 138 100 114 160 120 122 ...
$ chol : int 212 203 174 203 294 248 318 289 249 286 ...
$ fbs : Factor w/ 2 levels "0","1": 1 2 1 1 2 1 1 1 1 1 ...
$ restecg : Factor w/ 3 levels "0","1","2": 2 1 2 2 2 1 3 1 1 1 ...
$ thalach : int 168 155 125 161 106 122 140 145 144 116 ...
$ exang : Factor w/ 2 levels "0","1": 1 2 2 1 1 1 1 2 1 2 ...
$ oldpeak : num 1 3.1 2.6 0 1.9 1 4.4 0.8 0.8 3.2 ...
$ slope : Factor w/ 3 levels "0","1","2": 3 1 1 3 2 2 1 2 3 2 ...
$ ca : int 2 0 0 1 3 0 3 1 0 2 ...
$ thal : Factor w/ 4 levels "0","1","2","3": 4 4 4 4 3 3 2 4 4 3 ...
$ target : Factor w/ 2 levels "0","1": 1 1 1 1 1 2 1 1 1 1 ...
This approach preserves the original raw data while creating a separate dataset that is ready for summary statistics, visualization, and regression.
Summary Statistics
Before creating our regression model, we examine summary statistics for the quantitative variables.
| Variable | Mean | Median | SD | Minimum | Maximum |
|---|---|---|---|---|---|
| Age | 54.42 | 55.5 | 9.05 | 29 | 77.0 |
| Resting Blood Pressure | 131.60 | 130.0 | 17.56 | 94 | 200.0 |
| Cholesterol | 246.50 | 240.5 | 51.75 | 126 | 564.0 |
| Maximum Heart Rate | 149.57 | 152.5 | 22.90 | 71 | 202.0 |
| Oldpeak | 1.04 | 0.8 | 1.16 | 0 | 6.2 |
The table reports the mean, median, standard deviation, minimum, and maximum for each quantitative variable.
Summary Statistics for Qualitative Variables
For qualitative variables, useful summary statistics are the number and percentage of observations in each category.
| Variable | Category | Count | Percent |
|---|---|---|---|
| cp | 0 | 143 | 47.4 |
| cp | 1 | 50 | 16.6 |
| cp | 2 | 86 | 28.5 |
| cp | 3 | 23 | 7.6 |
| exang | 0 | 203 | 67.2 |
| exang | 1 | 99 | 32.8 |
| fbs | 0 | 257 | 85.1 |
| fbs | 1 | 45 | 14.9 |
| restecg | 0 | 147 | 48.7 |
| restecg | 1 | 151 | 50.0 |
| restecg | 2 | 4 | 1.3 |
| sex | 0 | 96 | 31.8 |
| sex | 1 | 206 | 68.2 |
| slope | 0 | 21 | 7.0 |
| slope | 1 | 140 | 46.4 |
| slope | 2 | 141 | 46.7 |
| target | 0 | 138 | 45.7 |
| target | 1 | 164 | 54.3 |
| thal | 0 | 2 | 0.7 |
| thal | 1 | 18 | 6.0 |
| thal | 2 | 165 | 54.6 |
| thal | 3 | 117 | 38.7 |
Together, the quantitative and qualitative tables summarize all of the main variables used in our dataset.
We can also examine a basic summary of every variable.
age sex cp trestbps chol fbs
Min. :29.00 0: 96 0:143 Min. : 94.0 Min. :126.0 0:257
1st Qu.:48.00 1:206 1: 50 1st Qu.:120.0 1st Qu.:211.0 1: 45
Median :55.50 2: 86 Median :130.0 Median :240.5
Mean :54.42 3: 23 Mean :131.6 Mean :246.5
3rd Qu.:61.00 3rd Qu.:140.0 3rd Qu.:274.8
Max. :77.00 Max. :200.0 Max. :564.0
restecg thalach exang oldpeak slope ca
0:147 Min. : 71.0 0:203 Min. :0.000 0: 21 Min. :0.0000
1:151 1st Qu.:133.2 1: 99 1st Qu.:0.000 1:140 1st Qu.:0.0000
2: 4 Median :152.5 Median :0.800 2:141 Median :0.0000
Mean :149.6 Mean :1.043 Mean :0.7185
3rd Qu.:166.0 3rd Qu.:1.600 3rd Qu.:1.0000
Max. :202.0 Max. :6.200 Max. :4.0000
thal target
0: 2 0:138
1: 18 1:164
2:165
3:117
Visualizing Quantitative Variables
We now visualize each of our main quantitative variables.
Age
This graph shows the age distribution of patients in our sample.
Resting Blood Pressure
Cholesterol
Maximum Heart Rate
Maximum heart rate is particularly important because it is the Y variable that we will attempt to predict with our regression model.
Oldpeak
Visualizing Qualitative Variables
For qualitative variables, bar charts allow us to compare the number of observations in each category.
Sex
Chest Pain Type
Fasting Blood Sugar
Resting ECG
Exercise-Induced Angina
ST Slope
Number of Major Vessels
Although ca is stored numerically, it only takes a small number of discrete values. A bar chart makes the distribution easy to interpret.
Thalassemia Category
Heart Disease Status
Exploring Maximum Heart Rate
Now that we have examined each variable individually, we look more closely at variables that may help explain our Y variable, maximum heart rate.
Age vs. Maximum Heart Rate
The fitted line shows a negative relationship between age and maximum heart rate. In general, older patients in this sample tend to achieve lower maximum heart rates. This pattern is also supported by our regression model, where age has a negative and statistically significant coefficient.
Heart Disease Status vs. Maximum Heart Rate
The boxplots allow us to compare the distribution of maximum heart rate between patients in the two heart disease categories. The regression model later shows that heart disease status is statistically associated with maximum heart rate after controlling for the other explanatory variables.
Exercise-Induced Angina vs. Maximum Heart Rate
Chest Pain Type vs. Maximum Heart Rate
Dependent Variable and Estimating Equation
Our dependent variable is:
Y = thalach (Maximum Heart Rate Achieved)
We estimate increasingly detailed versions of the following relationship:
[ Thalach_i = _0 + _1 Age_i + _2 Sex_i + _3 Target_i + _4 CP_i + _5 Exang_i + _6 Oldpeak_i + _i ]
where (i) represents a patient, (_0) is the intercept, the () coefficients describe estimated relationships between the explanatory variables and maximum heart rate, and (_i) represents other factors affecting maximum heart rate that are not captured by the model.
Because sex, target, cp, and exang are factors, R represents their non-reference categories with indicator variables. Their coefficients are interpreted relative to the omitted reference category.
Three Regression Specifications
We begin with a simple model and then add relevant controls. This allows us to see whether the estimated relationship between age and maximum heart rate changes as additional patient characteristics are included.
Model 1: Simple Age Model
Call:
lm(formula = thalach ~ age, data = heart_clean)
Residuals:
Min 1Q Median 3Q Max
-65.984 -11.985 4.009 16.004 45.010
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 204.0160 7.4058 27.548 < 2e-16 ***
age -1.0005 0.1342 -7.452 9.86e-13 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 21.07 on 300 degrees of freedom
Multiple R-squared: 0.1562, Adjusted R-squared: 0.1534
F-statistic: 55.54 on 1 and 300 DF, p-value: 9.858e-13
Model 1 provides the baseline relationship between age and maximum heart rate without additional controls.
Model 2: Add Patient Characteristics
Call:
lm(formula = thalach ~ age + sex + target, data = heart_clean)
Residuals:
Min 1Q Median 3Q Max
-60.061 -11.818 2.484 12.726 53.618
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 183.0154 8.1707 22.399 < 2e-16 ***
age -0.7939 0.1301 -6.103 3.23e-09 ***
sex1 1.2379 2.5660 0.482 0.63
target1 16.4164 2.4486 6.704 1.01e-10 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 19.63 on 298 degrees of freedom
Multiple R-squared: 0.273, Adjusted R-squared: 0.2657
F-statistic: 37.3 on 3 and 298 DF, p-value: < 2.2e-16
Model 2 adds sex and heart disease status. Comparing Model 2 with Model 1 shows whether the age coefficient changes after accounting for these characteristics.
Model 3: Full Model
Call:
lm(formula = thalach ~ age + sex + target + cp + exang + oldpeak,
data = heart_clean)
Residuals:
Min 1Q Median 3Q Max
-65.241 -11.189 2.319 12.487 41.435
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 188.4373 8.1034 23.254 < 2e-16 ***
age -0.7532 0.1257 -5.992 6.08e-09 ***
sex1 0.7259 2.4751 0.293 0.7695
target1 7.1626 2.8895 2.479 0.0137 *
cp1 7.8258 3.5514 2.204 0.0283 *
cp2 4.4549 2.9868 1.492 0.1369
cp3 9.0015 4.4793 2.010 0.0454 *
exang1 -8.9980 2.7072 -3.324 0.0010 **
oldpeak -2.4568 1.0687 -2.299 0.0222 *
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 18.73 on 293 degrees of freedom
Multiple R-squared: 0.3492, Adjusted R-squared: 0.3314
F-statistic: 19.65 on 8 and 293 DF, p-value: < 2.2e-16
Model 3 is the full specification and adds chest pain type, exercise-induced angina, and oldpeak.
Regression Results Table
The three specifications are displayed together below. This makes it easier to compare coefficient estimates, statistical significance, sample size, and model fit across specifications.
| Dependent variable: | |||
| Maximum Heart Rate (thalach) | |||
| Model 1 | Model 2 | Model 3 | |
| age | -1.000*** | -0.794*** | -0.753*** |
| (0.134) | (0.130) | (0.126) | |
| sex1 | 1.238 | 0.726 | |
| (2.566) | (2.475) | ||
| target1 | 16.416*** | 7.163** | |
| (2.449) | (2.890) | ||
| cp1 | 7.826** | ||
| (3.551) | |||
| cp2 | 4.455 | ||
| (2.987) | |||
| cp3 | 9.001** | ||
| (4.479) | |||
| exang1 | -8.998*** | ||
| (2.707) | |||
| oldpeak | -2.457** | ||
| (1.069) | |||
| Constant | 204.016*** | 183.015*** | 188.437*** |
| (7.406) | (8.171) | (8.103) | |
| Observations | 302 | 302 | 302 |
| R2 | 0.156 | 0.273 | 0.349 |
| Adjusted R2 | 0.153 | 0.266 | 0.331 |
| F Statistic | 55.539*** (df = 1; 300) | 37.298*** (df = 3; 298) | 19.650*** (df = 8; 293) |
| Note: | p<0.1; p<0.05; p<0.01 | ||
Interpreting and Comparing the Models
When interpreting the table, we focus on three questions:
- Does the estimated age coefficient remain negative as controls are added?
- Which additional explanatory variables are statistically significant in the fuller specifications?
- How does model fit, especially R-squared, change as additional explanatory variables are included?
The exact Model 1 and Model 2 coefficient values should be discussed from the regression table produced when this file is rendered. We do not insert unverified values into the written report.
For Model 3, based on the verified regression output, age has a coefficient of approximately -0.753, exercise-induced angina has a coefficient of approximately -8.998, and oldpeak has a coefficient of approximately -2.457. These relationships are statistically significant at the 0.05 level. Heart disease status and chest pain categories 1 and 3 are also statistically significant, while sex and chest pain category 2 are not statistically significant in the full specification.
Model 3 has an R-squared of approximately 0.349, meaning that the full set of explanatory variables accounts for about 34.9% of the observed variation in maximum heart rate in this sample.
Statistical and Practical Significance
Statistical significance tells us whether the data provide evidence of an association at our chosen significance level. We use a significance level of 0.05.
Practical significance focuses on the size of an estimated relationship. For example, the Model 3 estimate for exercise-induced angina is approximately 9 BPM lower relative to the reference category, which is a much larger estimated difference than a very small fraction of one BPM. We describe this as potentially meaningful in practical terms, but we do not claim a specific clinical threshold because this project does not establish one.
The regression results describe associations, not causal effects.
Regression Diagnostics
Linear regression relies on several assumptions.
We can examine diagnostic plots to determine whether our model appears reasonable.
Residuals vs. Fitted Values
Ideally, the residuals should appear randomly scattered around zero without a strong curved pattern.
Normal Q-Q Plot
If the residuals are approximately normally distributed, most of the points should be reasonably close to the diagonal line.
Actual vs. Predicted Maximum Heart Rate
Our regression model can generate a predicted maximum heart rate for each patient.
First, we add the predictions to our dataset.
We can then compare the model’s predictions with the actual maximum heart rates.
If our model predicts maximum heart rate well, we should see a positive relationship between the predicted and actual values.
Key Findings
Our analysis produced several important findings.
Age was one of the strongest predictors of maximum heart rate. Each additional year of age was associated with approximately a 0.75 BPM decrease in maximum heart rate, holding the other variables constant.
Exercise-induced angina was associated with a lower maximum heart rate. Patients in the exercise-induced angina category had predicted maximum heart rates about 9 BPM lower than the reference group.
Heart disease status was statistically significant. Category 1 was associated with a predicted maximum heart rate approximately 7.16 BPM higher than the reference category.
Chest pain type mattered for some categories. Chest pain types 1 and 3 were statistically significant, while chest pain type 2 was not significant at the 0.05 level.
Oldpeak had a significant negative relationship with maximum heart rate. A one-unit increase in oldpeak was associated with approximately a 2.46 BPM decrease in maximum heart rate.
Sex was not statistically significant after controlling for the other variables in the model.
The model’s R-squared was 0.3492, meaning the model explained approximately 34.9% of the observed variation in maximum heart rate.
Practical Conclusions and Recommendations
The analysis suggests that age, exercise-induced angina, oldpeak, heart disease status, and some chest pain categories contain useful information for explaining differences in maximum heart rate within this dataset.
For analysts or organizations using similar heart-health data, a practical recommendation is to avoid relying on a single characteristic such as age when describing maximum heart rate. The fuller regression specification considers several patient characteristics simultaneously and provides a more complete statistical description.
The model still leaves a substantial amount of variation unexplained. Future analysis should consider additional relevant variables when available and should test whether the results hold in other patient samples.
These recommendations concern data analysis and model building. Because the dataset is observational and this project does not establish clinical thresholds, the results should not be used on their own to make individual medical decisions.
Limitations
Our analysis has several limitations.
First, the dataset is cross-sectional and observational. Therefore, the regression results show associations between variables, but they do not necessarily establish cause and effect.
Second, maximum heart rate can be affected by factors that are not included in this dataset.
Third, our results depend on the patients included in this particular dataset, so they may not perfectly represent every population.
Finally, linear regression makes assumptions about the relationships between the variables. Our diagnostic plots help us evaluate whether these assumptions are reasonable.
# Conclusion
The purpose of this project was to investigate which patient characteristics are associated with maximum heart rate during exercise.
We preserved the raw data, created a separate cleaned dataset, summarized and visualized the major variables, and estimated three increasingly detailed regression specifications. The three-model approach allows us to compare a simple relationship with models that include additional controls.
In the full specification, age, heart disease status, chest pain categories 1 and 3, exercise-induced angina, and oldpeak are statistically significant at the 0.05 level. Sex and chest pain category 2 are not statistically significant in the full model. Model 3 has an R-squared of approximately 0.349, meaning that it explains about 34.9% of the observed variation in maximum heart rate.
Overall, the analysis demonstrates how cross-sectional data and multiple regression can be used to investigate associations between a quantitative outcome and several explanatory variables. Because the data are observational, the results should not be interpreted as causal.
AI Disclosure
Our group used ChatGPT to assist with organizing the Quarto report, generating and revising portions of R code, debugging, and explaining statistical output. We ran the code in R, inspected the resulting tables and visualizations, compared the written interpretations with the actual R output, and remained responsible for the final analysis. Group members reviewed the code so that they could explain the steps used in the project.
Appendix: Sources and Code Assistance
Data Source
Complete before submission: Insert the exact source of heart.csv here, including the page or course source from which the group obtained the raw file.
AI Assistance
OpenAI ChatGPT was used as an aid for code organization, debugging, regression-table formatting, and report structure. AI-generated suggestions were tested in R and revised based on the resulting output.
R Packages Used
tidyversefor data manipulation and visualizationknitrfor formatted tablesstargazerfor the side-by-side regression-results table
If any additional code is adapted from a website, textbook, class example, or other source, add that source to this Appendix before submission.