Heart Failure Clinical Records

Author

Yalda Azamee

Heart Failure Clinical Records

Introduction

This assignment uses the Heart Failure Clinical Records dataset from the UCI Machine Learning Repository, which contains medical records for 299 patients with heart failure collected during their follow-up period. The associated study by Chicco and Jurman (2020) investigated whether clinical characteristics could be used to predict patient survival and found that serum creatinine and ejection fraction were particularly important predictors. The goal of this assignment is to load the dataset into R, select meaningful variables, and transform the data into a clear and usable data frame for further analysis.

Approach

In this assignment, I selected a dataset from UCI Machine Learning Repository. The research looked at patients who already had heart failure and investigated whether clinical characteristics could help predict survival/death during the follow-up period. The dataset contains 12 features and 299 patients. The variables include age, diabetes, blood pressure, ejection fraction, serum creatinine, smoking, follow-up time, and death event. I chose this dataset because it includes a clear outcome variable, death event which indicates whether a patient died during the follow-up period and can be used for future analysis.

I loaded the data into R and selected a smaller set of meaningful variables that provide useful information about the patients and their outcomes.

To make the data easier to understand, I renamed variables that were not immediately intuitive and converted binary variables coded as 0 and 1 into descriptive labels such as ‘Yes’ and ‘No.’ I also included the death_event variable as the target variable. Finally, I checked the resulting data frame to make sure the selected variables had appropriate names, values, and data types.

Data Source

https://archive.ics.uci.edu/dataset/519/heart+failure+clinical+records

Research Article

Chicco, D., & Jurman, G. (2020). Machine learning can predict survival of patients with heart failure from serum creatinine and ejection fraction alone.

Research Article

Research Question

Among people who already have heart failure, can information about their health and clinical measurements help us understand or predict who is more likely to survive?

Load Required Packages

I loaded the tidyverse package to access functions for importing, exploring, and transforming the data.

library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.2.1     ✔ readr     2.2.0
✔ forcats   1.0.1     ✔ stringr   1.6.0
✔ ggplot2   4.0.3     ✔ tibble    3.3.1
✔ lubridate 1.9.5     ✔ tidyr     1.3.2
✔ purrr     1.2.2     
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors

Importing the Data

The dataset is imported directly from the UCI Machine Learning Repository using an online URL. Loading the data directly from an online source makes the analysis more reproducible because another user can run the code without needing the original file stored on my computer.

Importing the data using read_csv code

heart_failure <- read_csv(
  "https://archive.ics.uci.edu/ml/machine-learning-databases/00519/heart_failure_clinical_records_dataset.csv"
)
Rows: 299 Columns: 13
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
dbl (13): age, anaemia, creatinine_phosphokinase, diabetes, ejection_fractio...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Explore the Original Data

Before transforming the data, I examined the dataset to understand its structure and contents.

head(heart_failure)
# A tibble: 6 × 13
    age anaemia creatinine_phosphokinase diabetes ejection_fraction
  <dbl>   <dbl>                    <dbl>    <dbl>             <dbl>
1    75       0                      582        0                20
2    55       0                     7861        0                38
3    65       0                      146        0                20
4    50       1                      111        0                20
5    65       1                      160        1                20
6    90       1                       47        0                40
# ℹ 8 more variables: high_blood_pressure <dbl>, platelets <dbl>,
#   serum_creatinine <dbl>, serum_sodium <dbl>, sex <dbl>, smoking <dbl>,
#   time <dbl>, DEATH_EVENT <dbl>
dim(heart_failure)
[1] 299  13
names(heart_failure)
 [1] "age"                      "anaemia"                 
 [3] "creatinine_phosphokinase" "diabetes"                
 [5] "ejection_fraction"        "high_blood_pressure"     
 [7] "platelets"                "serum_creatinine"        
 [9] "serum_sodium"             "sex"                     
[11] "smoking"                  "time"                    
[13] "DEATH_EVENT"             
glimpse(heart_failure)
Rows: 299
Columns: 13
$ age                      <dbl> 75, 55, 65, 50, 65, 90, 75, 60, 65, 80, 75, 6…
$ anaemia                  <dbl> 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, …
$ creatinine_phosphokinase <dbl> 582, 7861, 146, 111, 160, 47, 246, 315, 157, …
$ diabetes                 <dbl> 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, …
$ ejection_fraction        <dbl> 20, 38, 20, 20, 20, 40, 15, 60, 65, 35, 38, 2…
$ high_blood_pressure      <dbl> 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, …
$ platelets                <dbl> 265000, 263358, 162000, 210000, 327000, 20400…
$ serum_creatinine         <dbl> 1.90, 1.10, 1.30, 1.90, 2.70, 2.10, 1.20, 1.1…
$ serum_sodium             <dbl> 130, 136, 129, 137, 116, 132, 137, 131, 138, …
$ sex                      <dbl> 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, …
$ smoking                  <dbl> 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, …
$ time                     <dbl> 4, 6, 7, 7, 8, 8, 10, 10, 10, 10, 10, 10, 11,…
$ DEATH_EVENT              <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, …
summary(heart_failure)
      age           anaemia       creatinine_phosphokinase    diabetes     
 Min.   :40.00   Min.   :0.0000   Min.   :  23.0           Min.   :0.0000  
 1st Qu.:51.00   1st Qu.:0.0000   1st Qu.: 116.5           1st Qu.:0.0000  
 Median :60.00   Median :0.0000   Median : 250.0           Median :0.0000  
 Mean   :60.83   Mean   :0.4314   Mean   : 581.8           Mean   :0.4181  
 3rd Qu.:70.00   3rd Qu.:1.0000   3rd Qu.: 582.0           3rd Qu.:1.0000  
 Max.   :95.00   Max.   :1.0000   Max.   :7861.0           Max.   :1.0000  
 ejection_fraction high_blood_pressure   platelets      serum_creatinine
 Min.   :14.00     Min.   :0.0000      Min.   : 25100   Min.   :0.500   
 1st Qu.:30.00     1st Qu.:0.0000      1st Qu.:212500   1st Qu.:0.900   
 Median :38.00     Median :0.0000      Median :262000   Median :1.100   
 Mean   :38.08     Mean   :0.3512      Mean   :263358   Mean   :1.394   
 3rd Qu.:45.00     3rd Qu.:1.0000      3rd Qu.:303500   3rd Qu.:1.400   
 Max.   :80.00     Max.   :1.0000      Max.   :850000   Max.   :9.400   
  serum_sodium        sex            smoking            time      
 Min.   :113.0   Min.   :0.0000   Min.   :0.0000   Min.   :  4.0  
 1st Qu.:134.0   1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.: 73.0  
 Median :137.0   Median :1.0000   Median :0.0000   Median :115.0  
 Mean   :136.6   Mean   :0.6488   Mean   :0.3211   Mean   :130.3  
 3rd Qu.:140.0   3rd Qu.:1.0000   3rd Qu.:1.0000   3rd Qu.:203.0  
 Max.   :148.0   Max.   :1.0000   Max.   :1.0000   Max.   :285.0  
  DEATH_EVENT    
 Min.   :0.0000  
 1st Qu.:0.0000  
 Median :0.0000  
 Mean   :0.3211  
 3rd Qu.:1.0000  
 Max.   :1.0000  
heart_failure_final <- heart_failure %>%
  select(
    age,
    sex,
    diabetes,
    high_blood_pressure,
    ejection_fraction,
    serum_creatinine,
    smoking,
    time,
    DEATH_EVENT
  )

Data Transformation

The original dataset contains several demographic, clinical, and follow-up variables. For this assignment, I selected a smaller group of variables that are relevant to the research question and include the death_event target variable. I also renamed selected variables to make their meanings clearer and converted several binary variables from numeric codes into descriptive labels such as “Yes,” “No,” “Died,” and “Survived.”

heart_failure_final <- heart_failure_final %>%
  rename(
    hypertension = high_blood_pressure,
    ejection_fraction_percent = ejection_fraction,
    follow_up_days = time,
    death_event = DEATH_EVENT
  ) %>%
  mutate(
    diabetes = if_else(diabetes == 1, "Yes", "No"),
    hypertension = if_else(hypertension == 1, "Yes", "No"),
    smoking = if_else(smoking == 1, "Yes", "No"),
    death_event = if_else(death_event == 1, "Died", "Survived")
  )

Final Data Frame

The final data frame contains 299 patient records and 9 selected variables.

dim(heart_failure_final)
[1] 299   9
names(heart_failure_final)
[1] "age"                       "sex"                      
[3] "diabetes"                  "hypertension"             
[5] "ejection_fraction_percent" "serum_creatinine"         
[7] "smoking"                   "follow_up_days"           
[9] "death_event"              
head(heart_failure_final)
# A tibble: 6 × 9
    age   sex diabetes hypertension ejection_fraction_percent serum_creatinine
  <dbl> <dbl> <chr>    <chr>                            <dbl>            <dbl>
1    75     1 No       Yes                                 20              1.9
2    55     1 No       No                                  38              1.1
3    65     1 No       No                                  20              1.3
4    50     1 No       No                                  20              1.9
5    65     0 Yes      No                                  20              2.7
6    90     1 No       Yes                                 40              2.1
# ℹ 3 more variables: smoking <chr>, follow_up_days <dbl>, death_event <chr>

Findings and Recommendations

The data preparation process produced a smaller and more readable data frame containing demographic information, clinical measurements, follow-up time, and the patient survival outcome. The selected variables include serum creatinine and ejection fraction, which are particularly important in the research article by Chicco and Jurman. The transformation also makes several binary variables easier to interpret by replacing numeric codes with descriptive labels.

The next step would be to examine the relationships between the selected clinical variables and the death_event outcome. In particular, I would explore whether serum creatinine and ejection fraction show different patterns between patients who survived and those who died during the follow-up period.

To extend the work from the original article, I could compare the results using additional variables from the original dataset and determine whether serum creatinine and ejection fraction remain the strongest predictors. I could also create visualizations and statistical analyses to further examine these relationships. A predictive model could be developed in a future assignment to evaluate how accurately the selected variables predict survival.

AI Use

I used ChatGPT (OpenAI) as a learning and coding support tool during this assignment. I used it to help me understand the assignment requirements, learn and interpret R and tidyverse code, troubleshoot coding errors, improve the organization and wording of my QMD document, and clarify concepts that I found difficult. I also used it to review my code and explain errors when my code did not work as expected.