Heart Failure Survival Analysis

UTS Survival Model

Email         :
RPubs        : https://rpubs.com/putriangelinaw/
GitHub      : https://github.com/putriangelinaw/
Jurusan     : Statistika Bisnis
Address    : ARA Center, Matana University Tower
                      Jl. CBD Barat Kav, RT.1, Curug Sangereng, Kelapa Dua, Tangerang, Banten 15810.



Nama Kelompok

Kefas Ronaldo Immanuel - 20194920004

Putri Angelina Windjaya - 20194920010

Deskripsi Data

Berikut ini beberapa penjelasan terhadap variabel yang ada.

Variabel Deskripsi
Age Umur Pasien
Anaemia Penurunan sel darah merah atau hemoglobin (boolean)
Creatinine_phosphokinase Tipe chest pain, 1: typical angina, 2: atypical angina, 3: non-anginal pain, 4: asymptomatic
Diabetes Jika pasien menderita diabetes (boolean)
Ejection_fraction Persentase darah yang meninggalkan jantung pada setiap kontraksi (persentase)
high_blood_pressure Jika pasien memiliki hipertensi (boolean)
platelets Trombosit dalam darah (kiloplatelets / mL)
serum_creatinine Tingkat kreatinin serum dalam darah (mg / dL)
serum_sodium Tingkat natrium serum dalam darah (mEq / L)
sex Wanita atau pria
smoking Jika pasien merokok atau tidak (boolean)
time Periode tindak lanjut (hari)
DEATH_EVENT Jika pasien meninggal selama masa tindak lanjut (boolean)

About the Dataset

Penyakit kardiovaskular (CVD) adalah penyebab kematian nomor 1 secara global, merenggut nyawa sekitar 17,9 juta jiwa setiap tahun, yang menyumbang 31% dari semua kematian secara global. Gagal jantung adalah peristiwa umum yang disebabkan oleh CVD dan dataset ini berisi 12 fitur yang dapat digunakan untuk memprediksi kematian akibat gagal jantung.

Sebagian besar penyakit kardiovaskular dapat dicegah dengan mengatasi faktor risiko perilaku seperti penggunaan tembakau, diet dan obesitas yang tidak sehat, aktivitas fisik dan penggunaan alkohol yang berbahaya menggunakan strategi di seluruh populasi.

Orang dengan penyakit kardiovaskular atau yang berisiko kardiovaskular tinggi (karena adanya satu atau lebih faktor risiko seperti hipertensi, diabetes, hiperlipidaemia atau penyakit yang sudah mapan) memerlukan deteksi dan manajemen dini di mana model pembelajaran machine learning dapat sangat membantu.

Pemasukkan Data

Pertama, kami mengimport data yang kami gunakan pada survival analisis ini. Kami menggunakan data heart_failure

data <- read.csv("heart.csv")
datatable(data)

Pembersihan Data

Selanjutnya, kami melakukan Pembersihan data. Pembersihan data yang pertama adalah kami memeriksa struktur data dari ketiga belas variabel yang ada, dengan function str. Dengan memeriksa struktur data ini, maka kami mendapatkan jenis data dari setiap variabel.

str(data)
## 'data.frame':    299 obs. of  13 variables:
##  $ age                     : num  75 55 65 50 65 90 75 60 65 80 ...
##  $ anaemia                 : int  0 0 0 1 1 1 1 1 0 1 ...
##  $ creatinine_phosphokinase: int  582 7861 146 111 160 47 246 315 157 123 ...
##  $ diabetes                : int  0 0 0 0 1 0 0 1 0 0 ...
##  $ ejection_fraction       : int  20 38 20 20 20 40 15 60 65 35 ...
##  $ high_blood_pressure     : int  1 0 0 0 0 1 0 0 0 1 ...
##  $ platelets               : num  265000 263358 162000 210000 327000 ...
##  $ serum_creatinine        : num  1.9 1.1 1.3 1.9 2.7 2.1 1.2 1.1 1.5 9.4 ...
##  $ serum_sodium            : int  130 136 129 137 116 132 137 131 138 133 ...
##  $ sex                     : int  1 1 1 1 0 1 1 1 0 1 ...
##  $ smoking                 : int  0 0 1 0 0 1 0 1 0 1 ...
##  $ time                    : int  4 6 7 7 8 8 10 10 10 10 ...
##  $ DEATH_EVENT             : int  1 1 1 1 1 1 1 1 1 1 ...

Memeriksa data hilang

Lalu, dari data yang kami gunakan, kami akan memeriksa data hilang di dalamnya dengan function sebagai berikut.

sum(is.na(data))
## [1] 0

Didapatkan bahwa pemeriksaan data hilang memiliki hasil nol. Hal ini berarti tidak adanya data yang hilang.

Memeriksa data duplikat

Langkah selanjutnya, kami memeriksa data duplikat. Terkadang di suatu data, terdapat jumlah data yang duplikat. Oleh karena itu, kami akan melakukan pemeriksaan data duplikat dengan function sebagai berikut.

check.duplicate <- data.frame(
                   row_of_data        = data %>% nrow (),
                   row_of_unique.data = data %>% distinct() %>% nrow())
check.duplicate
##   row_of_data row_of_unique.data
## 1         299                299

Hasil dari pemeriksaan data duplikat adalah pada bagian row_of_data dan row_of_unique.data memiliki hasil yang sama, yaitu 299. Hal ini berarti tidak adanya data yang duplikat.

Eksplorasi Data

Setelah melakukan pembersihan data, kami melakukan eksplorasi data menggunakan visualisasi supaya dapat melihat lebih jelas bentuk datanya seperti apa.

pl_age <- ggplot(data, aes(x=age)) + geom_histogram(alpha = 0.5, fill = "orange", colour = "black")

pl_platelets <-  ggplot(data, aes(x=platelets)) + 
                 geom_histogram(alpha = 0.5, fill = "orange", colour = "black")

pl_anaemia <- data %>%
                  mutate(anaemia = factor(ifelse(anaemia == 1, "anaemic", "non-anaemic"))) %>%
                  group_by(anaemia) %>%
                  tally(name = "count") %>%
                  ggplot(aes(x = anaemia, y = count)) + 
                  geom_bar(stat = "Identity", fill = "orange", width = 0.2, colour = "black")

pl_creatinine <- ggplot(data, aes(x=creatinine_phosphokinase)) +
                 geom_histogram(alpha = 0.5, fill = "orange", colour = "black")

pl_serum_creatinine <- ggplot(data, aes(x=serum_creatinine)) +
                       geom_histogram(alpha = 0.5, fill = "orange", colour = "black")

pl_serum_sodium <- ggplot(data, aes(x=serum_sodium)) +
                   geom_histogram(alpha = 0.5, fill = "orange", colour = "black")

pl_ejection_fraction <- ggplot(data, aes(x=ejection_fraction)) +
                 geom_histogram(alpha = 0.5, fill = "orange", colour = "black")

pl_high_blood_pressure <-  data %>%
                  mutate(HBP = factor(ifelse(high_blood_pressure == 1, "high-bp", "non-high-bp"))) %>%
                  group_by(HBP) %>%
                  tally(name = "count") %>%
                  ggplot(aes(x = HBP, y = count)) + 
                  geom_bar(stat = "Identity", fill = "orange", width = 0.2, colour = "black")

pl_sex <- data %>%
                  mutate(Gender = factor(ifelse(sex == 0, "female", "male"))) %>%
                  group_by(Gender) %>%
                  tally(name = "count") %>%
                  ggplot(aes(x = Gender, y = count)) + 
                  geom_bar(stat = "Identity", fill = "orange", width = 0.2, colour = "black")

pl_smoking <- data %>%
                  mutate(Smoking = factor(ifelse(smoking == 0, "non-smoker", "smoker"))) %>%
                  group_by(Smoking) %>%
                  tally(name = "count") %>%
                  ggplot(aes(x = Smoking, y = count)) + 
                  geom_bar(stat = "Identity", fill = "orange", width = 0.2, colour = "black")

pl_diabetes <- data %>%
                  mutate(Diabetes = factor(ifelse(diabetes == 1, "diabetic", "non-diabetic"))) %>%
                  group_by(Diabetes) %>%
                  tally(name = "count") %>%
                  ggplot(aes(x = Diabetes, y = count)) + 
                  geom_bar(stat = "Identity", fill = "orange", width = 0.2, colour = "black")

pl_deathevent <- data %>%
                  mutate(DeathEvent = factor(ifelse(DEATH_EVENT == 1, "death", "censored"))) %>%
                  group_by(DeathEvent) %>%
                  tally(name = "count") %>%
                  ggplot(aes(x = DeathEvent, y = count)) + 
                  geom_bar(stat = "Identity", fill = "orange", width = 0.2, colour = "black")
figure_plot <- ggarrange(pl_age, pl_creatinine, pl_ejection_fraction, pl_platelets, pl_serum_sodium, pl_serum_creatinine, pl_anaemia, pl_deathevent, pl_diabetes, pl_high_blood_pressure, pl_sex, pl_smoking,
                    ncol = 3, nrow = 2)

figure_plot
## $`1`

## 
## $`2`

## 
## attr(,"class")
## [1] "list"      "ggarrange"

Pada diagram-diagram di atas menunjukkan bahwa variabel yang numerik sudah memenuhi pendekatan normal/ distribusi normal. Lalu, untuk diagram-diagram variabel kategorik hanya menampilkan jumlah dari setiap elemen kategori nya.

Dapat dilihat bahwa ada variabel DeathEvent, yang akan digunakan untuk mengetahui apakah pasien itu sensor atau meninggal. Berikut ini merupakan Time-to-Event chart dari 10 pasien acak.

Time to Event chart

set.seed(456)
plot_censoring <- data %>% group_by(DEATH_EVENT) %>% sample_n(5) %>% ungroup() %>% select(time, DEATH_EVENT)

plot_censoring %>%
    mutate(
        time_start = 0, 
        pasient = factor(c(1:nrow(plot_censoring))),
        death_event = factor(ifelse(DEATH_EVENT == 1, "death", "censored"))
    ) %>%
    pivot_longer(
        cols = c(time, time_start),
        names_to = "source",
        values_to = "time"
    ) %>%
    ggplot(aes(x = time, y = pasient, group = factor(pasient))) + 
    geom_bar(stat = "Identity", aes(fill = death_event), colour = "black", width = 0.3) +
    ggtitle("Kasus sampel dari dataset- Waktu hingga death_event")

Plot di atas menunjukkan 10 pasien acak, dengan 5 pasien meninggal dan 5 pasien sensor (dikeluarkan dari penelitian sebelum kematian dapat diamati). Fakta bahwa beberapa pasien sensor tidak berarti bahwa data mereka tidak ada. Kita masih tahu bahwa mereka tidak meninggal, setidaknya sampai saat mereka sensor.

Tujuan dilakukan analisis ini adalah untuk mengetahui variabel manakah yang signifikan memengaruhi peristiwa pada data ini, yaitu dari waktu hingga meninggalnya pasien gagal jantung.

Kaplan-Meier Model

Pada analisis ini akan digunakan Model Kaplan-Meier. Kaplan-Meier Analysis adalah uji statistik yang memberikan perkiraan fungsi survival sebenarnya dari suatu populasi, perkiraan menjadi lebih baik dengan peningkatan ukuran sampel. Analisis ini dapat menangani sensor dengan kuat, dan dapat berasal dari hazard function menggunakan Estimasi likelihood Maksimum. Analisis ini dapat digunakan untuk perbandingan sederhana tingkat survival antar kelompok (Misalnya, tingkat survival antara perokok dan non-perokok).

Kaplan-Meier curve based on death event

Model Kaplan-Meier menyediakan tabel probabilitas survival kumulatif berdasarkan waktu atau bisa disebut juga Life Table.

set.seed(456)
km_model <- survfit(Surv(time, DEATH_EVENT) ~ 1, data = data)
summary(km_model, times = seq(from = 0, to = 290, by = 30))
## Call: survfit(formula = Surv(time, DEATH_EVENT) ~ 1, data = data)
## 
##  time n.risk n.event survival std.err lower 95% CI upper 95% CI
##     0    299       0    1.000  0.0000        1.000        1.000
##    30    264      35    0.882  0.0187        0.846        0.920
##    60    239      19    0.817  0.0225        0.774        0.863
##    90    189      15    0.763  0.0250        0.715        0.813
##   120    145       7    0.730  0.0268        0.680        0.785
##   150    118       5    0.703  0.0285        0.649        0.761
##   180    106       8    0.654  0.0313        0.596        0.719
##   210     62       4    0.622  0.0337        0.559        0.692
##   240     34       2    0.594  0.0378        0.524        0.673
##   270      6       1    0.576  0.0407        0.501        0.661
ggsurvplot(km_model, data = data, risk.table = T,
           break.time.by = 50, size = 0.3, tables.height = 0.4, ggtheme = theme_bw())

Pada kurva Kaplan-Meier di atas menunjukkan survival probability secara keseluruhan tanpa memikirkan kategori tertentu.Pada kurva, peristiwa penyensoran dilambangkan dengan tanda plus “+”. Dapat dilihat bahwa pada hari ke-0 survival probabilitynya adalah 1 karena belum terjadi peristiwa meninggal. Lalu survival probability terus turun seiring berjalannya waktu menjadi 0.576 (dilihat dari Life Table).

Apabila ingin melihat kurva Kaplan-Meier dengan memperhatikan beberapa kategori, berikut ada beberapa kurva Kaplan-Meier yang menampilkan hal tersebut.

Kaplan-Meier curve based on high blood pressure

# Kaplan-Meier curve based on high blood pressure
km_model <- data %>%
    mutate(
        high_blood_pressure =  factor(ifelse(high_blood_pressure == 1, "high-bp", "non-high-bp"))
    ) %>%
    survfit(Surv(time, DEATH_EVENT) ~ high_blood_pressure, data = .)
summary(km_model, times = seq(from = 0, to = 290, by = 30))
## Call: survfit(formula = Surv(time, DEATH_EVENT) ~ high_blood_pressure, 
##     data = .)
## 
##                 high_blood_pressure=high-bp 
##  time n.risk n.event survival std.err lower 95% CI upper 95% CI
##     0    105       0    1.000  0.0000        1.000        1.000
##    30     88      16    0.846  0.0355        0.779        0.918
##    60     75      13    0.718  0.0444        0.636        0.811
##    90     57       2    0.696  0.0458        0.612        0.792
##   120     39       3    0.651  0.0496        0.561        0.756
##   150     32       1    0.633  0.0514        0.540        0.742
##   180     29       2    0.592  0.0557        0.492        0.712
##   210     11       2    0.529  0.0652        0.416        0.674
##   240      3       0    0.529  0.0652        0.416        0.674
##   270      1       0    0.529  0.0652        0.416        0.674
## 
##                 high_blood_pressure=non-high-bp 
##  time n.risk n.event survival std.err lower 95% CI upper 95% CI
##     0    194       0    1.000  0.0000        1.000        1.000
##    30    176      19    0.902  0.0214        0.861        0.945
##    60    164       6    0.870  0.0242        0.824        0.919
##    90    132      13    0.798  0.0294        0.743        0.858
##   120    106       4    0.771  0.0313        0.712        0.835
##   150     86       4    0.739  0.0338        0.676        0.809
##   180     77       6    0.687  0.0376        0.617        0.765
##   210     51       2    0.665  0.0396        0.592        0.747
##   240     31       2    0.630  0.0444        0.549        0.724
##   270      5       1    0.609  0.0476        0.523        0.710
ggsurvplot(km_model, data = data, risk.table = T, pval = T,
           break.time.by = 50, size = 0.3, tables.height = 0.4, ggtheme = theme_bw())

Kurva Kaplan-Meier berdasarkan tekanan darah tinggi (high blood pressure) menunjukkan bahwa kurva survival pasien dengan non-tekanan darah tinggi berada di atas kurva survival pasien dengan tekanan darah tinggi, atau pasien non-tekanan darah tinggi lebih survive dibanding pasien dengan tekanan darah tinggi. Dengan melihat Life Table, survival probability non tekanan darah tinggi mencapai 0.609, sedangkan survival probability tekanan darah tinggi mencapai 0.529. Kurva di atas juga menunjukkan bahwa p-value = 0.036.

Kaplan-Meier curve based on diabetes

# Kaplan-Meier curve based on diabetes
km_model <- data %>%
    mutate(
        diabetes = factor(ifelse(diabetes == 1, "diabetic", "non-diabetic"))
    ) %>%
    survfit(Surv(time, DEATH_EVENT) ~ diabetes, data = .)
summary(km_model, times = seq(from = 0, to = 290, by = 30))
## Call: survfit(formula = Surv(time, DEATH_EVENT) ~ diabetes, data = .)
## 
##                 diabetes=diabetic 
##  time n.risk n.event survival std.err lower 95% CI upper 95% CI
##     0    125       0    1.000  0.0000        1.000        1.000
##    30    112      15    0.879  0.0293        0.823        0.938
##    60     97      10    0.796  0.0364        0.728        0.871
##    90     78       4    0.762  0.0386        0.690        0.842
##   120     63       1    0.752  0.0395        0.678        0.833
##   150     53       5    0.690  0.0449        0.607        0.784
##   180     46       3    0.650  0.0478        0.563        0.751
##   210     32       1    0.633  0.0497        0.542        0.738
##   240     18       1    0.602  0.0557        0.503        0.722
##   270      3       0    0.602  0.0557        0.503        0.722
## 
##                 diabetes=non-diabetic 
##  time n.risk n.event survival std.err lower 95% CI upper 95% CI
##     0    174       0    1.000  0.0000        1.000        1.000
##    30    152      20    0.885  0.0243        0.838        0.933
##    60    142       9    0.832  0.0285        0.778        0.890
##    90    111      11    0.763  0.0329        0.701        0.830
##   120     82       6    0.715  0.0362        0.648        0.790
##   150     65       0    0.715  0.0362        0.648        0.790
##   180     60       5    0.659  0.0411        0.584        0.745
##   210     30       3    0.615  0.0457        0.531        0.711
##   240     16       1    0.591  0.0497        0.501        0.697
##   270      3       1    0.552  0.0600        0.446        0.683
ggsurvplot(km_model, data = data, risk.table = T, pval = T,
           break.time.by = 50, size = 0.3, tables.height = 0.4, ggtheme = theme_bw())

Kurva Kaplan-Meier berdasarkan diabetes menunjukkan bahwa kurva survival pasien dengan diabetes berada di atas kurva survival pasien dengan non-diabetes, atau pasien dengan diabetes lebih survive dibanding pasien non-diabetes. Dengan melihat Life Table, survival probability diabetes mencapai 0.602, sedangkan survival probability non-diabetes mencapai 0.552. Kurva di atas juga menunjukkan bahwa p-value = 0.84.

Kaplan-Meier curve based on gender

# Kaplan-Meier curve based on gender
km_model <- data %>%
    mutate(
        sex = factor(ifelse(sex == 0, "female", "male"))
    ) %>%
    survfit(Surv(time, DEATH_EVENT) ~ sex, data = .)
summary(km_model, times = seq(from = 0, to = 290, by = 30))
## Call: survfit(formula = Surv(time, DEATH_EVENT) ~ sex, data = .)
## 
##                 sex=female 
##  time n.risk n.event survival std.err lower 95% CI upper 95% CI
##     0    105       0    1.000  0.0000        1.000        1.000
##    30     94      10    0.903  0.0291        0.848        0.962
##    60     85       8    0.825  0.0375        0.754        0.902
##    90     69       6    0.762  0.0426        0.683        0.850
##   120     50       3    0.723  0.0461        0.638        0.819
##   150     43       2    0.693  0.0488        0.603        0.795
##   180     38       2    0.660  0.0516        0.567        0.770
##   210     23       3    0.594  0.0590        0.489        0.722
##   240     13       0    0.594  0.0590        0.489        0.722
##   270      2       0    0.594  0.0590        0.489        0.722
## 
##                 sex=male 
##  time n.risk n.event survival std.err lower 95% CI upper 95% CI
##     0    194       0    1.000  0.0000        1.000        1.000
##    30    170      25    0.871  0.0241        0.825        0.919
##    60    154      11    0.813  0.0281        0.760        0.870
##    90    120       9    0.763  0.0310        0.705        0.826
##   120     95       4    0.735  0.0329        0.673        0.802
##   150     75       3    0.708  0.0351        0.643        0.780
##   180     68       6    0.650  0.0394        0.577        0.732
##   210     39       1    0.638  0.0406        0.563        0.722
##   240     21       2    0.592  0.0494        0.502        0.697
##   270      4       1    0.562  0.0551        0.464        0.681
ggsurvplot(km_model, data = data, risk.table = T, pval = T,
           break.time.by = 50, size = 0.3, tables.height = 0.4, ggtheme = theme_bw())

Kurva Kaplan-Meier berdasarkan jenis kelamin menunjukkan bahwa kurva survival pasien wanita berada di atas kurva survival pasien pria, atau pasien wanita lebih survive dibanding pasien pria. Dengan melihat Life Table, survival probability wanita mencapai 0.594, sedangkan survival probability pria mencapai 0.562. Kurva di atas juga menunjukkan bahwa p-value = 0.95.

Kaplan-Meier curve based on presence/absence of smoking

# Kaplan-Meier curve based on presence/absence of smoking
km_model <- data %>%
    mutate(
        smoking = factor(ifelse(smoking == 0, "non-smoker", "smoker"))
    ) %>%
    survfit(Surv(time, DEATH_EVENT) ~ smoking, data = .)
summary(km_model, times = seq(from = 0, to = 290, by = 30))
## Call: survfit(formula = Surv(time, DEATH_EVENT) ~ smoking, data = .)
## 
##                 smoking=non-smoker 
##  time n.risk n.event survival std.err lower 95% CI upper 95% CI
##     0    203       0    1.000  0.0000        1.000        1.000
##    30    178      25    0.876  0.0233        0.831        0.923
##    60    163      11    0.820  0.0272        0.768        0.875
##    90    131       8    0.777  0.0297        0.721        0.838
##   120     99       6    0.737  0.0325        0.676        0.803
##   150     84       4    0.705  0.0347        0.641        0.777
##   180     75       6    0.654  0.0380        0.583        0.733
##   210     44       4    0.608  0.0416        0.532        0.696
##   240     22       2    0.569  0.0478        0.482        0.670
##   270      2       0    0.569  0.0478        0.482        0.670
## 
##                 smoking=smoker 
##  time n.risk n.event survival std.err lower 95% CI upper 95% CI
##     0     96       0    1.000  0.0000        1.000        1.000
##    30     86      10    0.896  0.0312        0.837        0.959
##    60     76       8    0.812  0.0399        0.737        0.894
##    90     58       7    0.731  0.0462        0.646        0.828
##   120     46       1    0.717  0.0475        0.630        0.816
##   150     34       1    0.696  0.0506        0.604        0.802
##   180     31       2    0.654  0.0556        0.553        0.772
##   210     18       0    0.654  0.0556        0.553        0.772
##   240     12       0    0.654  0.0556        0.553        0.772
##   270      4       1    0.594  0.0759        0.463        0.763
ggsurvplot(km_model, data = data, risk.table = T, pval = T,
           break.time.by = 50, size = 0.3, tables.height = 0.4, ggtheme = theme_bw())

Kurva Kaplan-Meier berdasarkan merokok menunjukkan bahwa kurva survival pasien yang merokok berada di atas kurva survival pasien yang tidak merokok, atau pasien yang merokok lebih survive dibanding pasien yang tidak merokok. Dengan melihat Life Table, survival probability merokok mencapai 0.594, sedangkan survival probability non-merokok mencapai 0.569. Kurva di atas juga menunjukkan bahwa p-value = 0.96.

Kesimpulan

Berdasarkan analisis yang telah dilakukan ada beberapa hasil yang cukup mengejutkan yaitu pada bagian kurva Kaplan-Meier diabetes dan merokok. Dikatakan bahwa pasien diabetes lebih survive dibanding pasien non-diabetes. Hal ini terjadi karena sebenarnya pasien non-diabetes memiliki kemungkinan bertahan hidup yang tinggi hanya diawal waktu, tetapi kelangsungan hidupnya cenderung rendah untuk jangka waktu yang lebih lama. Hal ini juga terjadi pada pasien non-merokok. Pasien non-merokok cenderung memiliki kemungkinan bertahan hidup yang lebih tinggi pada awalnya tetapi kelangsungan hidup yang lebih rendah untuk jangka waktu yang lebih lama, dibandingkan pasien merokok.

Dari hasil p-value setiap kurva Kaplan-Meier menunjukkan bahwa semua variabel tersebut signifikan, hanya saja yang paling signifikan memengaruhi pasien gagal jantung adalah pasien yang merokok atau tidak.