Introduction

Prediktor mortalitas di rumah sakit untuk pasien gagal jantung yang dirawat di unit perawatan intensif (ICU) masih kurang diketahui. Tujuan dari pembuatan model ini adalah untuk mengembangkan dan memvalidasi model prediksi untuk mortalitas seluruh penyebab di rumah sakit pada pasien gagal jantung yang dirawat di ICU.

Data karakteristik demografis, tanda vital, dan laboratorium yang digunakan diekstraksi dari tabel-tabel berikut dalam dataset MIMIC III menggunakan Structured Query Language (SQL) queries (PostgreSQL, versi 9.6): ADMISSIONS, PATIENTS, ICUSTAYS, D_ICD DIAGNOSIS, DIAGNOSIS_ICD, LABEVENTS, D_LABIEVENTS, CHARTEVENTS, D_ITEMS, NOTEEVENTS, dan OUTPUTEVENTS. Dan sudah dimuat dalam situs Kaggle https://www.kaggle.com/datasets/saurabhshahane/in-hospital-mortality-prediction

Dataset mencakup data berikut:

  • karakteristik demografis (usia pada saat masuk rumah sakit, jenis kelamin, bmi);
  • tanda vital (denyut jantung, tekanan darah sistolik, tekanan darah diastolik, tekanan darah rata-rata, laju pernapasan, suhu tubuh, saturasi oksigen pulsa [SPO2], output urin [24 jam pertama]);
  • komorbiditas (hipertensi, Atrial fibrillation, penyakit jantung iskemik, diabetes, depresi, anemia, hiperlipidemia, penyakit ginjal, dan penyakit paru obstruktif kronis [COPD]);
  • dan variabel laboratorium (hematokrit, sel darah merah, hemoglobin korpuskular rata-rata [MCH], konsentrasi hemoglobin korpuskular rata-rata [MCHC], volume korpuskular rata-rata [MCV], lebar distribusi sel darah merah [RDW], jumlah trombosit, sel darah putih, neutrofil, basofil, limfosit, waktu protrombin [PT], rasio normalisasi internasional [INR], NT-proBNP, creatine kinase, kreatinin, nitrogen urea darah [BUN] glukosa, kalium, natrium, kalsium, klorida, magnesium, celah anion, bikarbonat, laktat, konsentrasi ion hidrogen [pH], tekanan parsial CO2 dalam darah arteri, dan LVEF)

Karakteristik demografis dan tanda vital dicatat selama 24 jam pertama dari setiap masuk rumah sakit dan variabel laboratorium diukur selama seluruh pasien tinggal di ICU. Komorbiditas diidentifikasi menggunakan kode ICD-9. Untuk data variabel dengan beberapa pengukuran, nilai yang digunakan merupakan rata-rata hitung dan dimasukkan untuk analisis. Hasil utama dari penelitian ini adalah mortalitas di rumah sakit, yang didefinisikan sebagai status vital pada saat keluar dari rumah sakit pada pasien yang selamat dan yang tidak selamat.

Dataset ini dapat digunakan untuk membangun model prediksi yang dapat membantu dokter dan tenaga medis dalam mengevaluasi risiko gagal jantung pada pasien dan memberikan perawatan yang lebih baik dan lebih personal.

Objektif:

  • Faktor apa saja yang meningkatkan mortalitas pasien gagal jantung.
  • Membandingkan model logistic regression dengan k-NN.
  • Mencari model terbaik.

Data Preperation

Read data / importing data

Sebelum menganalisa dataset, kita akan memanggil dataset “in-hospital-mortality-prediction” dari diamond.csv dan disimpan kedalam object bernama dia, kemudian akan dilakukan Exploratory Data Analyst terhadap dataset tersebut.

heart <- read.csv("data01.csv")

Import Library

Pertama kita akan memanggil library yang dibutuhkan, karena kita akan melakukan sedikit visualisasi data dan membuat model logistic regression, maka kita akan menggunkan library sebagai berikut.

library(dplyr)
library(gtools)
library(car)
library(GGally)
library(caret)
library(class)
library(corrplot)
library(DMwR)
library(mice)
library(ROSE)
library(ggplot2)

Inspeksi Data

Selanjutnya kita akan melihat dataset yang sudah kita panggil, gunakan head untuk melihat 6 baris pertama.

head(heart)

Kita juga dapat melihat isi dataset dengan menggunakan str

str(heart)
#> 'data.frame':    1177 obs. of  51 variables:
#>  $ group                   : int  1 1 1 1 1 1 1 1 1 1 ...
#>  $ ID                      : int  125047 139812 109787 130587 138290 154653 194420 153461 113076 147252 ...
#>  $ outcome                 : int  0 0 0 0 0 0 0 0 0 0 ...
#>  $ age                     : int  72 75 83 43 75 76 72 83 61 67 ...
#>  $ gendera                 : int  1 2 2 2 2 1 1 2 2 1 ...
#>  $ BMI                     : num  37.6 NA 26.6 83.3 31.8 ...
#>  $ hypertensive            : int  0 0 0 0 1 1 1 1 1 1 ...
#>  $ atrialfibrillation      : int  0 0 0 0 0 1 0 1 1 0 ...
#>  $ CHD.with.no.MI          : int  0 0 0 0 0 0 0 0 0 0 ...
#>  $ diabetes                : int  1 0 0 0 0 0 0 1 1 1 ...
#>  $ deficiencyanemias       : int  1 1 1 0 1 1 0 1 0 0 ...
#>  $ depression              : int  0 0 0 0 0 0 0 0 0 0 ...
#>  $ Hyperlipemia            : int  1 0 0 0 0 1 1 0 0 0 ...
#>  $ Renal.failure           : int  1 0 1 0 1 1 1 0 1 0 ...
#>  $ COPD                    : int  0 1 0 0 1 1 1 0 0 0 ...
#>  $ heart.rate              : num  68.8 101.4 72.3 94.5 67.9 ...
#>  $ Systolic.blood.pressure : num  156 140 135 126 157 ...
#>  $ Diastolic.blood.pressure: num  68.3 65 61.4 73.2 58.1 ...
#>  $ Respiratory.rate        : num  16.6 20.9 23.6 21.9 21.4 ...
#>  $ temperature             : num  36.7 36.7 36.5 36.3 36.8 ...
#>  $ SP.O2                   : num  98.4 96.9 95.3 93.8 99.3 ...
#>  $ Urine.output            : num  2155 1425 2425 8760 4455 ...
#>  $ hematocrit              : num  26.3 30.8 27.7 36.6 29.9 ...
#>  $ RBC                     : num  2.96 3.14 2.62 4.28 3.29 ...
#>  $ MCH                     : num  28.2 31.1 34.3 26.1 30.7 ...
#>  $ MCHC                    : num  31.5 31.7 31.3 30.4 33.7 ...
#>  $ MCV                     : num  89.9 98.2 109.8 85.6 91 ...
#>  $ RDW                     : num  16.2 14.3 23.8 17 16.3 ...
#>  $ Leucocyte               : num  7.65 12.74 5.48 8.22 8.83 ...
#>  $ Platelets               : num  305 246 204 216 251 ...
#>  $ Neutrophils             : num  74.7 NA 68.1 81.8 NA ...
#>  $ Basophils               : num  0.4 NA 0.55 0.15 NA 0.3 0.2 NA 0.55 NA ...
#>  $ Lymphocyte              : num  13.3 NA 24.5 14.5 NA ...
#>  $ PT                      : num  10.6 NA 11.3 27.1 NA ...
#>  $ INR                     : num  1 NA 0.95 2.67 NA ...
#>  $ NT.proBNP               : num  1956 2384 4081 668 30802 ...
#>  $ Creatine.kinase         : num  148 60.6 16 85 111.7 ...
#>  $ Creatinine              : num  1.958 1.122 1.871 0.586 1.95 ...
#>  $ Urea.nitrogen           : num  50 20.3 33.9 15.3 43 ...
#>  $ glucose                 : num  115 148 149 128 146 ...
#>  $ Blood.potassium         : num  4.82 4.45 5.83 4.39 4.78 ...
#>  $ Blood.sodium            : num  139 139 141 138 137 ...
#>  $ Blood.calcium           : num  7.46 8.16 8.27 9.48 8.73 ...
#>  $ Chloride                : num  109.2 98.4 105.9 92.1 104.5 ...
#>  $ Anion.gap               : num  13.2 11.4 10 12.4 15.2 ...
#>  $ Magnesium.ion           : num  2.62 1.89 2.16 1.94 1.65 ...
#>  $ PH                      : num  7.23 7.22 7.27 7.37 7.25 ...
#>  $ Bicarbonate             : num  21.2 33.4 30.6 38.6 22 ...
#>  $ Lactic.acid             : num  0.5 0.5 0.5 0.6 0.6 ...
#>  $ PCO2                    : num  40 78 71.5 75 50 ...
#>  $ EF                      : int  55 55 35 55 55 35 55 75 50 55 ...

Dari hasil tinjauan dataset di atas, ternyata dataset terdiri dari 1170 baris dan 51 kolom. Beberapa kolom ada yang bertipe integer dan numerik.

Deskripsi Data

Dari inspeksi data yang dilakukan terdapat beberapa kolom yang memiliki deskripsi sebagai berikut:

  • group: grup
  • ID: id pasien
  • outcome: Meninggal akibat gagal jantung atau tidak. (0 = Hidup, 1 = Meninggal)
  • age: Usia pasien pada saat masuk rumah sakit
  • gendera: jenis kelamin pasien (1 = Female, 2 = Male)
  • BMI: Indeks Massa Tubuh adalah ukuran lemak tubuh seseorang berdasarkan berat dan tinggi badannya. IMT dihitung dengan membagi berat badan seseorang dalam kilogram dengan kuadrat tinggi badannya dalam meter.
  • hypertensive: Apakah pasien menderita tekanan darah tinggi? (0 = tidak, 1 = iya)
  • atrialfibrillation: Apakah pasien menderita atrial fibrillation? (0 = tidak, 1 = iya)
  • CHD.with.no.MI: Apakah pasien mengalami penyakit jantung koroner tanpa serangan jantung? (0 = tidak, 1 = iya)
  • diabetes: Apakah pasien menderita diabetes? (0 = tidak, 1 = iya)
  • deficiencyanemias: Apakah pasien menderita Defisiensi anemia? (0 = tidak, 1 = iya)
  • depression: Apakah pasien menderita depresi? (0 = tidak, 1 = iya)
  • Hyperlipemia: Apakah pasien menderita Hyperlipemia? (0 = tidak, 1 = iya)
  • Renal_failure: Apakah pasien menderita Gagal ginjal? (0 = tidak, 1 = iya)
  • COPD: Apakah pasien menderita Chronic Obstructive Pulmonary Disease? (0 = tidak, 1 = iya)
  • Heart.rate: Heart rate adalah jumlah detak jantung seseorang dalam satu menit. Ini adalah indikator kesehatan kardiovaskular individu.
  • Systolic.blood pressure: Tekanan darah sistolik adalah tekanan di arteri saat jantung berkontraksi dan memompa darah keluar.
  • Diastolic.blood pressure: Tekanan darah diastolik adalah tekanan di arteri saat jantung rileks antara detak.
  • Respiratory.rate: Respiratory rate adalah jumlah napas yang diambil seseorang dalam satu menit. Ini adalah indikator fungsi paru-paru dan dapat digunakan untuk memantau pernapasan pasien. -Temperature: Suhu adalah derajat kepanasan atau kedinginan tubuh seseorang. Ini dapat diukur dalam derajat Fahrenheit atau Celsius.
  • SP.O2: SP.O2, atau pulse oximetry, adalah ukuran saturasi oksigen dalam darah seseorang. Ini adalah indikator penting fungsi pernapasan.
  • Urine.output: Urine output adalah jumlah urine yang diproduksi seseorang dalam periode waktu tertentu. Ini adalah indikator fungsi ginjal.
  • Hematocrit: Hematokrit adalah persentase volume sel darah merah dalam darah. Ini adalah ukuran kemampuan darah untuk membawa oksigen.
  • RBC: Sel darah merah (RBC) adalah jenis sel darah yang paling umum dan membawa oksigen dari paru-paru ke seluruh tubuh.
  • MCH: Mean corpuscular hemoglobin (MCH) adalah rata-rata jumlah hemoglobin dalam satu sel darah merah.
  • MCHC: Mean corpuscular hemoglobin concentration (MCHC) adalah rata-rata konsentrasi hemoglobin dalam volume sel darah merah yang diberikan.
  • MCV: Mean corpuscular volume (MCV) adalah rata-rata volume satu sel darah merah.
  • RDW: Red cell distribution width (RDW) adalah ukuran variasi ukuran sel darah merah.
  • Leucocyte: Leukosit, atau sel darah putih, adalah jenis sel darah yang berperan dalam sistem kekebalan tubuh.
  • Platelets: Platelet adalah fragmen sel kecil yang membantu dalam pembekuan darah dan mencegah pendarahan berlebihan.
  • Neutrophils: Neutrofil adalah jenis sel darah putih yang membantu melawan infeksi.
  • Basophils: Basofil adalah jenis sel darah putih yang berperan dalam respons kekebalan tubuh.
  • Lymphocyte: Limfosit adalah jenis sel darah putih yang berperan dalam sistem kekebalan tubuh.
  • PT: Prothrombin time (PT) adalah tes darah yang mengukur waktu pembekuan darah.
  • INR: International normalized ratio (INR) adalah perhitungan yang digunakan untuk standarisasi hasil tes prothrombin time (PT).
  • NT.proBNP: N-terminal pro b-type natriuretic peptide (NT.proBNP) adalah protein yang dilepaskan sebagai respons terhadap gagal jantung.
  • Creatine.kinase: Creatinekinase (CK) adalah enzim yang terdapat dalam otot rangka dan jantung yang digunakan sebagai indikator kerusakan otot.
  • Creatinine: Creatinine adalah zat buangan yang dihasilkan dari otot dan diekskresikan melalui ginjal. Kadar kreatinin dalam darah dapat digunakan sebagai indikator fungsi ginjal.
  • Urea.nitrogen: Urea nitrogen (BUN) adalah zat buangan yang dihasilkan dari metabolisme protein dan diekskresikan melalui ginjal. Kadar BUN dalam darah juga dapat digunakan sebagai indikator fungsi ginjal.
  • Glucose: Glukosa adalah jenis gula sederhana yang digunakan sebagai sumber energi oleh sel-sel tubuh. Kadar glukosa dalam darah dapat digunakan sebagai indikator diabetes dan masalah kesehatan lainnya.
  • Blood.potassium: Kadar kalium dalam darah dapat mempengaruhi fungsi otot dan jantung.
  • Blood.sodium: Kadar natrium dalam darah dapat mempengaruhi keseimbangan cairan dalam tubuh.
  • Blood.calcium: Kadar kalsium dalam darah penting untuk fungsi saraf, otot, dan tulang.
  • Chloride: Kadar klorida dalam darah dapat mempengaruhi keseimbangan elektrolit dalam tubuh.
  • Anion.gap: Anion gap adalah selisih antara kation dan anion dalam plasma darah dan dapat digunakan sebagai indikator masalah metabolik.
  • Magnesium.ion: Kadar magnesium dalam darah penting untuk fungsi saraf dan otot.
  • PH: PH adalah ukuran keasaman atau kebasaan dalam larutan. Kadar pH dalam darah dapat digunakan sebagai indikator masalah kesehatan tertentu.
  • Bicarbonate: Bicarbonate adalah zat yang membantu mempertahankan keseimbangan asam-basa dalam tubuh.
  • Lactic.acid: Asam laktat adalah produk sampingan dari metabolisme anaerobik yang dapat menyebabkan kelelahan dan masalah kesehatan lainnya.
  • PCO2: PCO2, atau tekanan parsial karbon dioksida, adalah ukuran jumlah karbon dioksida dalam darah.
  • EF: Ejection fraction (EF) adalah persentase volume darah yang dipompa oleh ventrikel kiri jantung selama satu kontraksi. Ini adalah indikator kesehatan jantung individu.

Data Wrangling

Cek Nilai Unique

Mengecek nilai unik di setiap kolom untuk membantu dalam penentuan tipe data terutama tipe data kategorik/factor. Karena ingin mengecek semua kolomnya sekaligus maka digunakan perintah lapply().

lengths(lapply(heart, unique))
#>                    group                       ID                  outcome 
#>                        2                     1177                        3 
#>                      age                  gendera                      BMI 
#>                       68                        2                      934 
#>             hypertensive       atrialfibrillation           CHD.with.no.MI 
#>                        2                        2                        2 
#>                 diabetes        deficiencyanemias               depression 
#>                        2                        2                        2 
#>             Hyperlipemia            Renal.failure                     COPD 
#>                        2                        2                        2 
#>               heart.rate  Systolic.blood.pressure Diastolic.blood.pressure 
#>                     1095                     1103                     1078 
#>         Respiratory.rate              temperature                    SP.O2 
#>                     1005                      776                      867 
#>             Urine.output               hematocrit                      RBC 
#>                      811                     1056                     1045 
#>                      MCH                     MCHC                      MCV 
#>                      926                      803                      601 
#>                      RDW                Leucocyte                Platelets 
#>                      836                      983                     1085 
#>              Neutrophils                Basophils               Lymphocyte 
#>                      636                       74                      542 
#>                       PT                      INR                NT.proBNP 
#>                      784                      426                     1147 
#>          Creatine.kinase               Creatinine            Urea.nitrogen 
#>                      692                      729                      925 
#>                  glucose          Blood.potassium             Blood.sodium 
#>                      803                      645                      600 
#>            Blood.calcium                 Chloride                Anion.gap 
#>                      588                      675                      486 
#>            Magnesium.ion                       PH              Bicarbonate 
#>                      447                      414                      657 
#>              Lactic.acid                     PCO2                       EF 
#>                      302                      465                       14

Selanjutnya kita bisa mengubah tipe data di setiap kolom berdasarkan informasi diatas

Cek Tipe Data

Melakukan inspeksi tipe data untuk memastikan tipe data dari setiap kolomnya sudah sesuai.

glimpse(heart)
#> Rows: 1,177
#> Columns: 51
#> $ group                    <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
#> $ ID                       <int> 125047, 139812, 109787, 130587, 138290, 15465…
#> $ outcome                  <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
#> $ age                      <int> 72, 75, 83, 43, 75, 76, 72, 83, 61, 67, 70, 8…
#> $ gendera                  <int> 1, 2, 2, 2, 2, 1, 1, 2, 2, 1, 2, 2, 2, 1, 2, …
#> $ BMI                      <dbl> 37.58818, NA, 26.57263, 83.26463, 31.82484, 2…
#> $ hypertensive             <int> 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
#> $ atrialfibrillation       <int> 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, …
#> $ CHD.with.no.MI           <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
#> $ diabetes                 <int> 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, …
#> $ deficiencyanemias        <int> 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, …
#> $ depression               <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
#> $ Hyperlipemia             <int> 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, …
#> $ Renal.failure            <int> 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, …
#> $ COPD                     <int> 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, …
#> $ heart.rate               <dbl> 68.83784, 101.37037, 72.31818, 94.50000, 67.9…
#> $ Systolic.blood.pressure  <dbl> 155.86667, 140.00000, 135.33333, 126.40000, 1…
#> $ Diastolic.blood.pressure <dbl> 68.33333, 65.00000, 61.37500, 73.20000, 58.12…
#> $ Respiratory.rate         <dbl> 16.62162, 20.85185, 23.64000, 21.85714, 21.36…
#> $ temperature              <dbl> 36.71429, 36.68254, 36.45370, 36.28704, 36.76…
#> $ SP.O2                    <dbl> 98.39474, 96.92308, 95.29167, 93.84615, 99.28…
#> $ Urine.output             <dbl> 2155, 1425, 2425, 8760, 4455, 1840, 2450, 303…
#> $ hematocrit               <dbl> 26.27273, 30.78000, 27.70000, 36.63750, 29.93…
#> $ RBC                      <dbl> 2.960000, 3.138000, 2.620000, 4.277500, 3.286…
#> $ MCH                      <dbl> 28.25000, 31.06000, 34.32000, 26.06250, 30.66…
#> $ MCHC                     <dbl> 31.52000, 31.66000, 31.30000, 30.41250, 33.66…
#> $ MCV                      <dbl> 89.90000, 98.20000, 109.80000, 85.62500, 91.0…
#> $ RDW                      <dbl> 16.22000, 14.26000, 23.82000, 17.03750, 16.26…
#> $ Leucocyte                <dbl> 7.6500000, 12.7400000, 5.4800000, 8.2250000, …
#> $ Platelets                <dbl> 305.10000, 246.40000, 204.20000, 216.37500, 2…
#> $ Neutrophils              <dbl> 74.65000, NA, 68.10000, 81.80000, NA, 85.4000…
#> $ Basophils                <dbl> 0.40, NA, 0.55, 0.15, NA, 0.30, 0.20, NA, 0.5…
#> $ Lymphocyte               <dbl> 13.300000, NA, 24.500000, 14.500000, NA, 9.30…
#> $ PT                       <dbl> 10.60000, NA, 11.27500, 27.06667, NA, 18.7833…
#> $ INR                      <dbl> 1.000000, NA, 0.950000, 2.666667, NA, 1.70000…
#> $ NT.proBNP                <dbl> 1956.0, 2384.0, 4081.0, 668.0, 30802.0, 34183…
#> $ Creatine.kinase          <dbl> 148.00000, 60.60000, 16.00000, 85.00000, 111.…
#> $ Creatinine               <dbl> 1.9583333, 1.1222222, 1.8714286, 0.5857143, 1…
#> $ Urea.nitrogen            <dbl> 50.00000, 20.33333, 33.85714, 15.28571, 43.00…
#> $ glucose                  <dbl> 114.63636, 147.50000, 149.00000, 128.25000, 1…
#> $ Blood.potassium          <dbl> 4.816667, 4.450000, 5.825000, 4.386667, 4.783…
#> $ Blood.sodium             <dbl> 138.7500, 138.8889, 140.7143, 138.5000, 136.6…
#> $ Blood.calcium            <dbl> 7.463636, 8.162500, 8.266667, 9.476923, 8.733…
#> $ Chloride                 <dbl> 109.16667, 98.44444, 105.85714, 92.07143, 104…
#> $ Anion.gap                <dbl> 13.166667, 11.444444, 10.000000, 12.357143, 1…
#> $ Magnesium.ion            <dbl> 2.618182, 1.887500, 2.157143, 1.942857, 1.650…
#> $ PH                       <dbl> 7.230000, 7.225000, 7.268000, 7.370000, 7.250…
#> $ Bicarbonate              <dbl> 21.16667, 33.44444, 30.57143, 38.57143, 22.00…
#> $ Lactic.acid              <dbl> 0.5000000, 0.5000000, 0.5000000, 0.6000000, 0…
#> $ PCO2                     <dbl> 40.00000, 78.00000, 71.50000, 75.00000, 50.00…
#> $ EF                       <int> 55, 55, 35, 55, 55, 35, 55, 75, 50, 55, 75, 5…

Kolom yang tipe datanya akan diubah: - group, outcome, gendera, hypertensive, atrialfibrillation, CHD.with.no.MI, diabetes, deficiencyanemias, depression, Hyperlipemia, Renal.failure, COPD -> Factor

Kolom yang dibuang: - group dan ID

Mengubah sekaligus beberapa tipe data dengan menggunakan perintah mutate_at

heart1 <- heart %>% 
  select(-c(group,ID)) %>% 
  mutate_at(vars(outcome, gendera, hypertensive, atrialfibrillation, CHD.with.no.MI, diabetes, deficiencyanemias, depression, Hyperlipemia, Renal.failure, COPD), as.factor)

Mengecek kembali tipe data:

# Cek kembali struktur data
glimpse(heart1)
#> Rows: 1,177
#> Columns: 49
#> $ outcome                  <fct> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
#> $ age                      <int> 72, 75, 83, 43, 75, 76, 72, 83, 61, 67, 70, 8…
#> $ gendera                  <fct> 1, 2, 2, 2, 2, 1, 1, 2, 2, 1, 2, 2, 2, 1, 2, …
#> $ BMI                      <dbl> 37.58818, NA, 26.57263, 83.26463, 31.82484, 2…
#> $ hypertensive             <fct> 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
#> $ atrialfibrillation       <fct> 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, …
#> $ CHD.with.no.MI           <fct> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
#> $ diabetes                 <fct> 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, …
#> $ deficiencyanemias        <fct> 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, …
#> $ depression               <fct> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
#> $ Hyperlipemia             <fct> 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, …
#> $ Renal.failure            <fct> 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, …
#> $ COPD                     <fct> 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, …
#> $ heart.rate               <dbl> 68.83784, 101.37037, 72.31818, 94.50000, 67.9…
#> $ Systolic.blood.pressure  <dbl> 155.86667, 140.00000, 135.33333, 126.40000, 1…
#> $ Diastolic.blood.pressure <dbl> 68.33333, 65.00000, 61.37500, 73.20000, 58.12…
#> $ Respiratory.rate         <dbl> 16.62162, 20.85185, 23.64000, 21.85714, 21.36…
#> $ temperature              <dbl> 36.71429, 36.68254, 36.45370, 36.28704, 36.76…
#> $ SP.O2                    <dbl> 98.39474, 96.92308, 95.29167, 93.84615, 99.28…
#> $ Urine.output             <dbl> 2155, 1425, 2425, 8760, 4455, 1840, 2450, 303…
#> $ hematocrit               <dbl> 26.27273, 30.78000, 27.70000, 36.63750, 29.93…
#> $ RBC                      <dbl> 2.960000, 3.138000, 2.620000, 4.277500, 3.286…
#> $ MCH                      <dbl> 28.25000, 31.06000, 34.32000, 26.06250, 30.66…
#> $ MCHC                     <dbl> 31.52000, 31.66000, 31.30000, 30.41250, 33.66…
#> $ MCV                      <dbl> 89.90000, 98.20000, 109.80000, 85.62500, 91.0…
#> $ RDW                      <dbl> 16.22000, 14.26000, 23.82000, 17.03750, 16.26…
#> $ Leucocyte                <dbl> 7.6500000, 12.7400000, 5.4800000, 8.2250000, …
#> $ Platelets                <dbl> 305.10000, 246.40000, 204.20000, 216.37500, 2…
#> $ Neutrophils              <dbl> 74.65000, NA, 68.10000, 81.80000, NA, 85.4000…
#> $ Basophils                <dbl> 0.40, NA, 0.55, 0.15, NA, 0.30, 0.20, NA, 0.5…
#> $ Lymphocyte               <dbl> 13.300000, NA, 24.500000, 14.500000, NA, 9.30…
#> $ PT                       <dbl> 10.60000, NA, 11.27500, 27.06667, NA, 18.7833…
#> $ INR                      <dbl> 1.000000, NA, 0.950000, 2.666667, NA, 1.70000…
#> $ NT.proBNP                <dbl> 1956.0, 2384.0, 4081.0, 668.0, 30802.0, 34183…
#> $ Creatine.kinase          <dbl> 148.00000, 60.60000, 16.00000, 85.00000, 111.…
#> $ Creatinine               <dbl> 1.9583333, 1.1222222, 1.8714286, 0.5857143, 1…
#> $ Urea.nitrogen            <dbl> 50.00000, 20.33333, 33.85714, 15.28571, 43.00…
#> $ glucose                  <dbl> 114.63636, 147.50000, 149.00000, 128.25000, 1…
#> $ Blood.potassium          <dbl> 4.816667, 4.450000, 5.825000, 4.386667, 4.783…
#> $ Blood.sodium             <dbl> 138.7500, 138.8889, 140.7143, 138.5000, 136.6…
#> $ Blood.calcium            <dbl> 7.463636, 8.162500, 8.266667, 9.476923, 8.733…
#> $ Chloride                 <dbl> 109.16667, 98.44444, 105.85714, 92.07143, 104…
#> $ Anion.gap                <dbl> 13.166667, 11.444444, 10.000000, 12.357143, 1…
#> $ Magnesium.ion            <dbl> 2.618182, 1.887500, 2.157143, 1.942857, 1.650…
#> $ PH                       <dbl> 7.230000, 7.225000, 7.268000, 7.370000, 7.250…
#> $ Bicarbonate              <dbl> 21.16667, 33.44444, 30.57143, 38.57143, 22.00…
#> $ Lactic.acid              <dbl> 0.5000000, 0.5000000, 0.5000000, 0.6000000, 0…
#> $ PCO2                     <dbl> 40.00000, 78.00000, 71.50000, 75.00000, 50.00…
#> $ EF                       <int> 55, 55, 35, 55, 55, 35, 55, 75, 50, 55, 75, 5…

Tampak tipe data setiap kolomnya sudah sesuai.

Cek Duplikat

Mengecek apakah terdapat data yang memiliki kesamaan nilai atau duplikat.

#cek duplicate
sum(duplicated(heart1))
#> [1] 0

Ternyata tidak ada data yang berisi duplikat value, selanjutnya cek apakah terdapat missing values.

Cek Missing Values

colSums(is.na(heart1))
#>                  outcome                      age                  gendera 
#>                        1                        0                        0 
#>                      BMI             hypertensive       atrialfibrillation 
#>                      215                        0                        0 
#>           CHD.with.no.MI                 diabetes        deficiencyanemias 
#>                        0                        0                        0 
#>               depression             Hyperlipemia            Renal.failure 
#>                        0                        0                        0 
#>                     COPD               heart.rate  Systolic.blood.pressure 
#>                        0                       13                       16 
#> Diastolic.blood.pressure         Respiratory.rate              temperature 
#>                       16                       13                       19 
#>                    SP.O2             Urine.output               hematocrit 
#>                       13                       36                        0 
#>                      RBC                      MCH                     MCHC 
#>                        0                        0                        0 
#>                      MCV                      RDW                Leucocyte 
#>                        0                        0                        0 
#>                Platelets              Neutrophils                Basophils 
#>                        0                      144                      259 
#>               Lymphocyte                       PT                      INR 
#>                      145                       20                       20 
#>                NT.proBNP          Creatine.kinase               Creatinine 
#>                        0                      165                        0 
#>            Urea.nitrogen                  glucose          Blood.potassium 
#>                        0                       18                        0 
#>             Blood.sodium            Blood.calcium                 Chloride 
#>                        0                        1                        0 
#>                Anion.gap            Magnesium.ion                       PH 
#>                        0                        0                      292 
#>              Bicarbonate              Lactic.acid                     PCO2 
#>                        0                      229                      294 
#>                       EF 
#>                        0

Ternyata terdapat banyak kolom yang mengandung missing values. Kita akan menangani kolom yang mengandung missing values dengan cara berikut.

Pertama kita akan melihat ada berapa baris yang tidak mengandung missing values

sum(!complete.cases(heart))/nrow(heart1)
#> [1] 0.6363636

Ternyata sekitar 63,6% data tidak mengandung missing values

Kita bisa melihat distribusi dari missing values dari dataframe kita

library(VIM)
aggr_plot <- aggr(heart1, col=c('navyblue','red'), numbers=TRUE, sortVars=TRUE, labels=names(heart), cex.axis=.7, gap=3, ylab=c("Histogram of missing data","Pattern"))

#> 
#>  Variables sorted by number of missings: 
#>                  Variable        Count
#>               Bicarbonate 0.2497875956
#>                 Anion.gap 0.2480883602
#>                 Platelets 0.2200509771
#>                        PH 0.1945624469
#>                       age 0.1826677995
#>                       INR 0.1401869159
#>               Neutrophils 0.1231945624
#>                 Leucocyte 0.1223449448
#>               temperature 0.0305862362
#>                 Basophils 0.0169923534
#>                Lymphocyte 0.0169923534
#>  Diastolic.blood.pressure 0.0161427358
#>                Creatinine 0.0152931181
#>                      COPD 0.0135938828
#>                heart.rate 0.0135938828
#>             Renal.failure 0.0110450297
#>   Systolic.blood.pressure 0.0110450297
#>          Respiratory.rate 0.0110450297
#>                     group 0.0008496177
#>           Blood.potassium 0.0008496177
#>                        ID 0.0000000000
#>                   outcome 0.0000000000
#>                   gendera 0.0000000000
#>                       BMI 0.0000000000
#>              hypertensive 0.0000000000
#>        atrialfibrillation 0.0000000000
#>            CHD.with.no.MI 0.0000000000
#>                  diabetes 0.0000000000
#>         deficiencyanemias 0.0000000000
#>                depression 0.0000000000
#>              Hyperlipemia 0.0000000000
#>                     SP.O2 0.0000000000
#>              Urine.output 0.0000000000
#>                hematocrit 0.0000000000
#>                       RBC 0.0000000000
#>                       MCH 0.0000000000
#>                      MCHC 0.0000000000
#>                       MCV 0.0000000000
#>                       RDW 0.0000000000
#>                        PT 0.0000000000
#>                 NT.proBNP 0.0000000000
#>           Creatine.kinase 0.0000000000
#>             Urea.nitrogen 0.0000000000
#>                   glucose 0.0000000000
#>              Blood.sodium 0.0000000000
#>             Blood.calcium 0.0000000000
#>                  Chloride 0.0000000000
#>             Magnesium.ion 0.0000000000
#>               Lactic.acid 0.0000000000

Berdasarkan dari hasil dataframe, PCO2 dan PH mendominasi missing values yakni hampir 25% dari total data. Kita asumsikan data missing values disini karena datanya tidak diinput oleh petugas atau tidak melakukan uji lab di variabel tersebut.

Untuk menangani missing values, kita akan menggunakan salah satu metode yaitu dengan MICE (Multivariate Imputation via Chained Equations). Untuk menggunakan MICE kita membutuhkan missing values yang tersebar acak atau MCAR dan MAR, metode MICE tidak cocok untuk variabel yang memiliki korelasi kuat dengan variabel lain. Untuk memahaminya bisa akses https://dept.stat.lsa.umich.edu/~jerrick/courses/stat701/notes/mi.html

Berdasarkan beberapa penelitian, kebanyakan missing values di kasus epidemiologi klinik itu bertipe MAR dan MCAR seperti data tidak diinput, kerusakan alat tes lab dan adanya kesalahan dalam pengambilan sampel, maka kita asumsikan missing values bertipe MCAR atau MAR, maka kita bisa menggunakan MICE.

Selanjutnya kita akan mengatasi missing valuesnya dengan menggunakan metode MICE.

# Menggunakan MICE untuk mengatasi missing values
set.seed(123)

imp <- mice(heart1, m=5, maxit=20, seed=500)

# Menyimpan hasil imputasi dalam bentuk DataFrame
heart_clean <- complete(imp)

# Cek kembali missing values pada hasil imputasi
colSums(is.na(heart_clean))

Disarankan tidak menggunakan banyak m danmaxit karena akan berpengaruuh ke durasi komputasinya.

Kita akan melihat metode apa yang dipakai dalam mengisi missing values di masing-masing kolom dengan summary

summary(imp)
#> Class: mids
#> Number of multiple imputations:  5 
#> Imputation methods:
#>                  outcome                      age                  gendera 
#>                 "logreg"                       ""                       "" 
#>                      BMI             hypertensive       atrialfibrillation 
#>                    "pmm"                       ""                       "" 
#>           CHD.with.no.MI                 diabetes        deficiencyanemias 
#>                       ""                       ""                       "" 
#>               depression             Hyperlipemia            Renal.failure 
#>                       ""                       ""                       "" 
#>                     COPD               heart.rate  Systolic.blood.pressure 
#>                       ""                    "pmm"                    "pmm" 
#> Diastolic.blood.pressure         Respiratory.rate              temperature 
#>                    "pmm"                    "pmm"                    "pmm" 
#>                    SP.O2             Urine.output               hematocrit 
#>                    "pmm"                    "pmm"                       "" 
#>                      RBC                      MCH                     MCHC 
#>                       ""                       ""                       "" 
#>                      MCV                      RDW                Leucocyte 
#>                       ""                       ""                       "" 
#>                Platelets              Neutrophils                Basophils 
#>                       ""                    "pmm"                    "pmm" 
#>               Lymphocyte                       PT                      INR 
#>                    "pmm"                    "pmm"                    "pmm" 
#>                NT.proBNP          Creatine.kinase               Creatinine 
#>                       ""                    "pmm"                       "" 
#>            Urea.nitrogen                  glucose          Blood.potassium 
#>                       ""                    "pmm"                       "" 
#>             Blood.sodium            Blood.calcium                 Chloride 
#>                       ""                    "pmm"                       "" 
#>                Anion.gap            Magnesium.ion                       PH 
#>                       ""                       ""                    "pmm" 
#>              Bicarbonate              Lactic.acid                     PCO2 
#>                       ""                    "pmm"                    "pmm" 
#>                       EF 
#>                       "" 
#> PredictorMatrix:
#>                    outcome age gendera BMI hypertensive atrialfibrillation
#> outcome                  0   1       1   1            1                  1
#> age                      1   0       1   1            1                  1
#> gendera                  1   1       0   1            1                  1
#> BMI                      1   1       1   0            1                  1
#> hypertensive             1   1       1   1            0                  1
#> atrialfibrillation       1   1       1   1            1                  0
#>                    CHD.with.no.MI diabetes deficiencyanemias depression
#> outcome                         1        1                 1          1
#> age                             1        1                 1          1
#> gendera                         1        1                 1          1
#> BMI                             1        1                 1          1
#> hypertensive                    1        1                 1          1
#> atrialfibrillation              1        1                 1          1
#>                    Hyperlipemia Renal.failure COPD heart.rate
#> outcome                       1             1    1          1
#> age                           1             1    1          1
#> gendera                       1             1    1          1
#> BMI                           1             1    1          1
#> hypertensive                  1             1    1          1
#> atrialfibrillation            1             1    1          1
#>                    Systolic.blood.pressure Diastolic.blood.pressure
#> outcome                                  1                        1
#> age                                      1                        1
#> gendera                                  1                        1
#> BMI                                      1                        1
#> hypertensive                             1                        1
#> atrialfibrillation                       1                        1
#>                    Respiratory.rate temperature SP.O2 Urine.output hematocrit
#> outcome                           1           1     1            1          1
#> age                               1           1     1            1          1
#> gendera                           1           1     1            1          1
#> BMI                               1           1     1            1          1
#> hypertensive                      1           1     1            1          1
#> atrialfibrillation                1           1     1            1          1
#>                    RBC MCH MCHC MCV RDW Leucocyte Platelets Neutrophils
#> outcome              1   1    1   1   1         1         1           1
#> age                  1   1    1   1   1         1         1           1
#> gendera              1   1    1   1   1         1         1           1
#> BMI                  1   1    1   1   1         1         1           1
#> hypertensive         1   1    1   1   1         1         1           1
#> atrialfibrillation   1   1    1   1   1         1         1           1
#>                    Basophils Lymphocyte PT INR NT.proBNP Creatine.kinase
#> outcome                    1          1  1   1         1               1
#> age                        1          1  1   1         1               1
#> gendera                    1          1  1   1         1               1
#> BMI                        1          1  1   1         1               1
#> hypertensive               1          1  1   1         1               1
#> atrialfibrillation         1          1  1   1         1               1
#>                    Creatinine Urea.nitrogen glucose Blood.potassium
#> outcome                     1             1       1               1
#> age                         1             1       1               1
#> gendera                     1             1       1               1
#> BMI                         1             1       1               1
#> hypertensive                1             1       1               1
#> atrialfibrillation          1             1       1               1
#>                    Blood.sodium Blood.calcium Chloride Anion.gap Magnesium.ion
#> outcome                       1             1        1         1             1
#> age                           1             1        1         1             1
#> gendera                       1             1        1         1             1
#> BMI                           1             1        1         1             1
#> hypertensive                  1             1        1         1             1
#> atrialfibrillation            1             1        1         1             1
#>                    PH Bicarbonate Lactic.acid PCO2 EF
#> outcome             1           1           1    1  1
#> age                 1           1           1    1  1
#> gendera             1           1           1    1  1
#> BMI                 1           1           1    1  1
#> hypertensive        1           1           1    1  1
#> atrialfibrillation  1           1           1    1  1

Ternyata dengan menggunakan MICE, missing values diisi dengan method “pmm” untuk kolom numerik dan method “logreg” untuk kolom kategorik secara otomatis.

Untuk melihat apa saja method yang bisa digunakan bisa akses link berikut https://search.r-project.org/CRAN/refmans/mice/html/mice.html

Selanjutnya, mari kita cek ulang kolom missing valuesnya

colSums(is.na(heart_clean))
#>                  outcome                      age                  gendera 
#>                        0                        0                        0 
#>                      BMI             hypertensive       atrialfibrillation 
#>                        0                        0                        0 
#>           CHD.with.no.MI                 diabetes        deficiencyanemias 
#>                        0                        0                        0 
#>               depression             Hyperlipemia            Renal.failure 
#>                        0                        0                        0 
#>                     COPD               heart.rate  Systolic.blood.pressure 
#>                        0                        0                        0 
#> Diastolic.blood.pressure         Respiratory.rate              temperature 
#>                        0                        0                        0 
#>                    SP.O2             Urine.output               hematocrit 
#>                        0                        0                        0 
#>                      RBC                      MCH                     MCHC 
#>                        0                        0                        0 
#>                      MCV                      RDW                Leucocyte 
#>                        0                        0                        0 
#>                Platelets              Neutrophils                Basophils 
#>                        0                        0                        0 
#>               Lymphocyte                       PT                      INR 
#>                        0                        0                        0 
#>                NT.proBNP          Creatine.kinase               Creatinine 
#>                        0                        0                        0 
#>            Urea.nitrogen                  glucose          Blood.potassium 
#>                        0                        0                        0 
#>             Blood.sodium            Blood.calcium                 Chloride 
#>                        0                        0                        0 
#>                Anion.gap            Magnesium.ion                       PH 
#>                        0                        0                        0 
#>              Bicarbonate              Lactic.acid                     PCO2 
#>                        0                        0                        0 
#>                       EF 
#>                        0

Sekarang kita dapat memeriksa distribusi data asli dan data yang diisi oleh MICE:

Sebagai contoh kita menggunakan Bicarbonate dan PCO2 tadi

marginplot(heart1[c("PCO2","Bicarbonate")])

xyplot(imp,Bicarbonate ~ PCO2,pch=18,cex=1)

Tampak beberapa data yang berwarna biru muda yang tersebar acak telah masuk ke dataframe kita.

Karena data kita sudah bersih, kita bisa lannjut ke proses EDA.

Exploratory Data Analysis

Mendefinisikan Business Problem

Dalam kasus kali ini, kita akan memprediksi kolom target outcome berdasarkan beberapa variabel prediktor yang dipilih. Kita akan menentukan:

  • variable target (y): outcome.
  • variable prediktor (x): beberapa variabel prediktor yang akan dipilih selain variable outcome.

Berdasarkan informasi dari basic knowledge dari seorang expert di bidang yang terkait dengan dataset ini, variabel-variabel penting yang menyebabkan pengaruh terhadap mortalitas gagal jantung yaitu: Age, gendera, BMI, hypertensive, atrialfibrillation, CHD.with.no.MI, diabetes, Hyperlipemia, Renal.failure, heart.rate, Systolic.blood.pressure, Diastolic.blood.pressure, Respiratory.rate, temperature, SP.O2, Urine.output, RBC, Platelets, PT, NT.proBNP, Creatine.kinase, Creatinine, glucose, Blood.potassium, EF

Maka dari itu kita akan memilih kolom-kolom berdasarkan informasi tersebut.

heart_new <- heart_clean %>% 
  select(c(outcome,age,gendera,BMI,hypertensive,atrialfibrillation,CHD.with.no.MI,diabetes,Hyperlipemia,Renal.failure,heart.rate,Systolic.blood.pressure,Diastolic.blood.pressure,Respiratory.rate,temperature,SP.O2,Urine.output,RBC,Platelets,PT,NT.proBNP,Creatine.kinase,Creatinine,glucose,Blood.potassium,EF))

Selanjutnya kita akan cek apakah ada ketidaknormalan pada setiap kolom dari dataframe heart_new. Kita bisa mengeceknya dengan menggunakan summary.

summary(heart_new)
#>  outcome       age        gendera      BMI         hypertensive
#>  0:1017   Min.   :19.00   1:559   Min.   : 13.35   0:332       
#>  1: 160   1st Qu.:65.00   2:618   1st Qu.: 24.30   1:845       
#>           Median :77.00           Median : 28.23               
#>           Mean   :74.06           Mean   : 29.98               
#>           3rd Qu.:85.00           3rd Qu.: 33.34               
#>           Max.   :99.00           Max.   :104.97               
#>  atrialfibrillation CHD.with.no.MI diabetes Hyperlipemia Renal.failure
#>  0:646              0:1076         0:681    0:730        0:747        
#>  1:531              1: 101         1:496    1:447        1:430        
#>                                                                       
#>                                                                       
#>                                                                       
#>                                                                       
#>    heart.rate     Systolic.blood.pressure Diastolic.blood.pressure
#>  Min.   : 36.00   Min.   : 75.0           Min.   : 24.74          
#>  1st Qu.: 72.38   1st Qu.:105.4           1st Qu.: 52.05          
#>  Median : 83.61   Median :116.0           Median : 58.46          
#>  Mean   : 84.57   Mean   :117.9           Mean   : 59.48          
#>  3rd Qu.: 95.95   3rd Qu.:128.5           3rd Qu.: 65.43          
#>  Max.   :135.71   Max.   :203.0           Max.   :107.00          
#>  Respiratory.rate  temperature        SP.O2         Urine.output 
#>  Min.   :11.14    Min.   :33.25   Min.   : 75.92   Min.   :   0  
#>  1st Qu.:17.92    1st Qu.:36.29   1st Qu.: 95.00   1st Qu.: 958  
#>  Median :20.36    Median :36.65   Median : 96.45   Median :1660  
#>  Mean   :20.80    Mean   :36.67   Mean   : 96.27   Mean   :1888  
#>  3rd Qu.:23.40    3rd Qu.:37.02   3rd Qu.: 97.92   3rd Qu.:2495  
#>  Max.   :40.90    Max.   :39.13   Max.   :100.00   Max.   :8820  
#>       RBC          Platelets              PT          NT.proBNP     
#>  Min.   :2.030   Min.   :   9.571   Min.   :10.10   Min.   :    50  
#>  1st Qu.:3.120   1st Qu.: 168.909   1st Qu.:13.16   1st Qu.:  2251  
#>  Median :3.490   Median : 222.667   Median :14.61   Median :  5840  
#>  Mean   :3.575   Mean   : 241.504   Mean   :17.48   Mean   : 11014  
#>  3rd Qu.:3.900   3rd Qu.: 304.250   3rd Qu.:18.80   3rd Qu.: 14968  
#>  Max.   :6.575   Max.   :1028.200   Max.   :71.27   Max.   :118928  
#>  Creatine.kinase     Creatinine         glucose       Blood.potassium
#>  Min.   :    8.0   Min.   : 0.2667   Min.   : 66.67   Min.   :3.000  
#>  1st Qu.:   46.0   1st Qu.: 0.9400   1st Qu.:113.50   1st Qu.:3.900  
#>  Median :   90.0   Median : 1.2875   Median :136.55   Median :4.115  
#>  Mean   :  246.2   Mean   : 1.6428   Mean   :148.66   Mean   :4.177  
#>  3rd Qu.:  188.0   3rd Qu.: 1.9000   3rd Qu.:169.33   3rd Qu.:4.400  
#>  Max.   :42987.5   Max.   :15.5273   Max.   :414.10   Max.   :6.567  
#>        EF       
#>  Min.   :15.00  
#>  1st Qu.:40.00  
#>  Median :55.00  
#>  Mean   :48.72  
#>  3rd Qu.:55.00  
#>  Max.   :75.00

Tampak ada keanehan pada nilai maksimum pada variabel Creatine.kinase yakni mencapai nilai 42987.5 dan ini bisa dikategorikan outlier. Akan tetapi sebagai info, CK adalah enzim yang ditemukan di jantung, otak, dan otot rangka, dan kisaran normalnya adalah 20 hingga 380. Sebagian besar CK dalam darah berasal dari otot, dan levelnya naik karena olahraga atau cedera, dan dalam beberapa kasus naik menjadi 10K hingga 200K dalam kasus rhabdomyolysis, kelainan ginjal atau lisis diafragma (Laporan kasus). Oleh karena itu, outlier ini tidak dihapus.

Untuk variabel lain yang memiliki nilai maksimum yang tinggi kita mengasumsikan kalau nilainya adalah kasus khusus.

Cek class-imbalance

Kita akan mengecek keseimbangan data dari variabel target

prop.table(table(heart_new$outcome))
#> 
#>         0         1 
#> 0.8640612 0.1359388

Kita akan menangani ketidak-seimbangan data target ini ketika sudah membagi data menjadi train dan test agar tidak terjadi leakage pada saat prediksi berjalan.

Cross Validation

RNGkind(sample.kind = "Rounding") 
set.seed(29) #mengunci kerendoman

# index sampling
index <- sample(x = nrow(heart_new), size = nrow(heart_new)*0.8)

# splitting
heart_train <- heart_new[index,]
heart_test <- heart_new[-index,]

Kita akan mengecek hasil pembagian datanya

nrow(heart_train)
#> [1] 941
nrow(heart_test)
#> [1] 236

Ada sebanyak 941 data yang akan digunkana sebagai train dan 236 data yang akan ditest

table(heart_train$outcome)
#> 
#>   0   1 
#> 813 128

Ternyata data target sangat tidak seimbang.

Subsamping dengan SMOTE

Untuk menyeimbangkan data targetnya kita bisa menggunakan salah satu metode dalam mengatasi kelas target yang tidak seimbang yakni menambah data dengan metode SMOTE, SMOTE dapat digunakan ketika kelas minoritas terlalu sedikit dibandingkan kelas mayoritas tanpa kehilangan informasi penting pada data.

Proporsi kelas yang balance penting untuk data train karena kita akan melatih model menggunakan data train.

#untuk menginstal DMwR karena DMwR sudah tidak tersedia.
#remotes::install_github("cran/DMwR")
set.seed(123)
heart_train <- SMOTE(outcome ~ ., heart_train, perc.over = 500, k=5, perc.under=120)
prop.table(table(heart_train$outcome))
#> 
#>   0   1 
#> 0.5 0.5

Build Model

model_all <- glm(outcome ~., heart_train, family = "binomial", control = list(trace = F))

summary(model_all)
#> 
#> Call:
#> glm(formula = outcome ~ ., family = "binomial", data = heart_train, 
#>     control = list(trace = F))
#> 
#> Deviance Residuals: 
#>     Min       1Q   Median       3Q      Max  
#> -2.4710  -0.8720  -0.0637   0.8739   2.3598  
#> 
#> Coefficients:
#>                              Estimate   Std. Error z value      Pr(>|z|)    
#> (Intercept)              13.085144000  5.535488427   2.364      0.018085 *  
#> age                       0.018617985  0.006445415   2.889      0.003870 ** 
#> gendera2                 -0.324763322  0.127635124  -2.544      0.010944 *  
#> BMI                       0.013454980  0.008934424   1.506      0.132075    
#> hypertensive1            -0.513788110  0.135342674  -3.796      0.000147 ***
#> atrialfibrillation1       0.277867742  0.128488741   2.163      0.030573 *  
#> CHD.with.no.MI1           0.605189099  0.199346767   3.036      0.002398 ** 
#> diabetes1                 0.218265016  0.131921224   1.655      0.098024 .  
#> Hyperlipemia1            -0.076552028  0.129586746  -0.591      0.554695    
#> Renal.failure1           -0.501319107  0.145198093  -3.453      0.000555 ***
#> heart.rate                0.030336583  0.005225444   5.806 0.00000000642 ***
#> Systolic.blood.pressure  -0.003896122  0.004799798  -0.812      0.416949    
#> Diastolic.blood.pressure -0.041188168  0.009139221  -4.507 0.00000658287 ***
#> Respiratory.rate          0.081940666  0.017499855   4.682 0.00000283587 ***
#> temperature              -0.266773327  0.123875870  -2.154      0.031275 *  
#> SP.O2                    -0.091057622  0.027220386  -3.345      0.000822 ***
#> Urine.output             -0.000359301  0.000068774  -5.224 0.00000017473 ***
#> RBC                      -0.234666416  0.118009639  -1.989      0.046752 *  
#> Platelets                -0.002941575  0.000626689  -4.694 0.00000268133 ***
#> PT                        0.019908183  0.009441425   2.109      0.034979 *  
#> NT.proBNP                 0.000027686  0.000005432   5.097 0.00000034570 ***
#> Creatine.kinase           0.000570280  0.000160831   3.546      0.000391 ***
#> Creatinine                0.244632106  0.083320411   2.936      0.003324 ** 
#> glucose                   0.005364854  0.001336696   4.014 0.00005982058 ***
#> Blood.potassium           0.623495454  0.177845891   3.506      0.000455 ***
#> EF                       -0.000753860  0.005624311  -0.134      0.893374    
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#> 
#> (Dispersion parameter for binomial family taken to be 1)
#> 
#>     Null deviance: 2129.3  on 1535  degrees of freedom
#> Residual deviance: 1613.2  on 1510  degrees of freedom
#> AIC: 1665.2
#> 
#> Number of Fisher Scoring iterations: 6

Kemudian kita akan melakukan feature selection / tuning menggunakan stepwise tipe backward (menghilangkan predictor satu persatu sampai didapat nilai AIC paling rendah)

model_step <- step(object = model_all,
                   direction = "backward",
                   trace = FALSE)
summary(model_step)
#> 
#> Call:
#> glm(formula = outcome ~ age + gendera + BMI + hypertensive + 
#>     atrialfibrillation + CHD.with.no.MI + diabetes + Renal.failure + 
#>     heart.rate + Diastolic.blood.pressure + Respiratory.rate + 
#>     temperature + SP.O2 + Urine.output + RBC + Platelets + PT + 
#>     NT.proBNP + Creatine.kinase + Creatinine + glucose + Blood.potassium, 
#>     family = "binomial", data = heart_train, control = list(trace = F))
#> 
#> Deviance Residuals: 
#>      Min        1Q    Median        3Q       Max  
#> -2.47125  -0.87372  -0.06518   0.86987   2.39123  
#> 
#> Coefficients:
#>                              Estimate   Std. Error z value       Pr(>|z|)    
#> (Intercept)              12.930591246  5.514762912   2.345       0.019041 *  
#> age                       0.017657101  0.006383979   2.766       0.005678 ** 
#> gendera2                 -0.329503816  0.125544096  -2.625       0.008675 ** 
#> BMI                       0.013162394  0.008918464   1.476       0.139982    
#> hypertensive1            -0.530092765  0.134119651  -3.952 0.000077375471 ***
#> atrialfibrillation1       0.284237830  0.128071712   2.219       0.026462 *  
#> CHD.with.no.MI1           0.618627111  0.197796810   3.128       0.001762 ** 
#> diabetes1                 0.209176348  0.131568572   1.590       0.111865    
#> Renal.failure1           -0.498149911  0.142745532  -3.490       0.000483 ***
#> heart.rate                0.031438092  0.005034520   6.245 0.000000000425 ***
#> Diastolic.blood.pressure -0.044426855  0.008077267  -5.500 0.000000037929 ***
#> Respiratory.rate          0.083550777  0.017362937   4.812 0.000001494134 ***
#> temperature              -0.274062325  0.123112652  -2.226       0.026007 *  
#> SP.O2                    -0.091203412  0.027071155  -3.369       0.000754 ***
#> Urine.output             -0.000368658  0.000067488  -5.463 0.000000046922 ***
#> RBC                      -0.216630361  0.115041704  -1.883       0.059692 .  
#> Platelets                -0.003020391  0.000612601  -4.930 0.000000820464 ***
#> PT                        0.021292242  0.009289158   2.292       0.021896 *  
#> NT.proBNP                 0.000028031  0.000005226   5.364 0.000000081413 ***
#> Creatine.kinase           0.000585548  0.000158519   3.694       0.000221 ***
#> Creatinine                0.236647779  0.081193704   2.915       0.003561 ** 
#> glucose                   0.005294937  0.001316758   4.021 0.000057904483 ***
#> Blood.potassium           0.631122990  0.176565355   3.574       0.000351 ***
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#> 
#> (Dispersion parameter for binomial family taken to be 1)
#> 
#>     Null deviance: 2129.3  on 1535  degrees of freedom
#> Residual deviance: 1614.3  on 1513  degrees of freedom
#> AIC: 1660.3
#> 
#> Number of Fisher Scoring iterations: 6

Karena AIC nya lebih kecil yaitu 1641.8 diabnding sebelumnya 1647.1, maka kita gunakan model_step

  • Variable yang meningkatkan peluang: age, atrialfibrillation1, CHD.with.no.MI1, diabetes, heart.rate, Respiratory.rate, PT, NT.proBNP, Creatine.kinase, glucose, Blood.potassium.
  • Variable yang menurunkan peluang: gendera2, hypertensive1, Hyperlipemia1, Renal.failure1, Diastolic.blood.pressure, temperature, SP.O2, Urine.output, Platelets
  • Signifikansi Variable: age, gendera2, hypertensive1, atrialfibrillation1, CHD.with.no.MI1, diabetes, Renal.failure1, heart.rate, Diastolic.blood.pressure, Respiratory.rate, SP.O2, Urine.output, Platelets, PT, NT.proBNP, Creatine.kinase, glucose, Blood.potassium.

Interpretasi Koefisien: Karena hasil dari model menampilkan koefisien dalam bentuk log of odds maka kita akan mengubah log of odds ke nilai odds

exp(model_step$coefficient)
#>              (Intercept)                      age                 gendera2 
#>           412747.4758638                1.0178139                0.7192805 
#>                      BMI            hypertensive1      atrialfibrillation1 
#>                1.0132494                0.5885504                1.3287489 
#>          CHD.with.no.MI1                diabetes1           Renal.failure1 
#>                1.8563777                1.2326624                0.6076538 
#>               heart.rate Diastolic.blood.pressure         Respiratory.rate 
#>                1.0319375                0.9565456                1.0871404 
#>              temperature                    SP.O2             Urine.output 
#>                0.7602847                0.9128320                0.9996314 
#>                      RBC                Platelets                       PT 
#>                0.8052276                0.9969842                1.0215205 
#>                NT.proBNP          Creatine.kinase               Creatinine 
#>                1.0000280                1.0005857                1.2669948 
#>                  glucose          Blood.potassium 
#>                1.0053090                1.8797203

Berikut hasil interpretasi untuk beberapa variabel prediktor,

  • Age: 1.0144513 Odds ratio untuk usia adalah 1.0144513. Ini menunjukkan bahwa setiap peningkatan 1 tahun usia pasien, maka kemungkinan meninggal akibat gagal jantung akan meningkat sebesar 1.01 kali, ketika variabel prediktor lainnya diatur pada nilai yang sama.

  • Gendera2: 0.6294582 Odds ratio untuk gendera2 adalah 0.6294582. Ini menunjukkan bahwa pasien dengan gender male memiliki kemungkinan 0.63 kali lebih rendah untuk meninggal akibat gagal jantung dibandingkan dengan pasien dengan gender female, ketika variabel prediktor lainnya diatur pada nilai yang sama.

  • Atrialfibrillation1: 1.3320582 Odds ratio untuk atrialfibrillation1 adalah 1.3320582. Ini menunjukkan bahwa pasien dengan fibrilasi atrium memiliki kemungkinan 1.3 kali lebih tinggi untuk meninggal akibat gagal jantung dibandingkan dengan pasien tanpa fibrilasi atrium, ketika variabel prediktor lainnya diatur pada nilai yang sama.

  • Heart.rate: 1.0247106 Odds ratio untuk heart.rate adalah 1.0247106. Ini menunjukkan bahwa setiap peningkatan 1 denyut jantung dalam satu menit, maka kemungkinan meninggal akibat gagal jantung akan meningkat sebesar 1.02 kali, ketika variabel prediktor lainnya diatur pada nilai yang sama.

  • Diastolic.blood.pressure: 0.9510547 Odds ratio untuk Diastolic.blood.pressure adalah 0.9510547. Ini menunjukkan bahwa setiap peningkatan 1 mmHg tekanan darah diastolik, maka kemungkinan meninggal akibat gagal jantung akan menurun sebesar 0.95 kali, ketika variabel prediktor

  • Temperature: 0.8203311 Odds ratio untuk temperature adalah 0.8203311. Ini menunjukkan bahwa setiap peningkatan 1 derajat Celsius suhu tubuh, maka kemungkinan meninggal akibat gagal jantung akan menurun sebesar 0.82 kali, ketika variabel prediktor lainnya diatur pada nilai yang sama.

  • SP.O2: 0.8945223 Odds ratio untuk SP.O2 adalah 0.8945223. Ini menunjukkan bahwa setiap peningkatan 1 persen saturasi oksigen dalam darah, maka kemungkinan meninggal akibat gagal jantung akan menurun sebesar 0.89 kali, ketika variabel prediktor lainnya diatur pada nilai yang sama.

  • Urine.output: 0.9996536 Odds ratio untuk urine.output adalah 0.9996536. Ini menunjukkan bahwa setiap peningkatan 1 ml urine output, maka kemungkinan meninggal akibat gagal jantung akan menurun sangat sedikit (kurang dari 1%), ketika variabel prediktor lainnya diatur pada nilai yang sama.

  • Platelets: 0.9969780 Odds ratio untuk platelets adalah 0.9969780. Ini menunjukkan bahwa setiap peningkatan 1 (1000, dalam unit ribuan) sel trombosit per mikroliter darah, maka kemungkinan meninggal akibat gagal jantung akan menurun sedikit (kurang dari 1%), ketika variabel prediktor lainnya diatur pada nilai yang sama.

  • NT.proBNP: 1.0000303 Odds ratio untuk NT.proBNP adalah 1.0000303. Ini menunjukkan bahwa setiap peningkatan 1 pg/mL kadar NT.proBNP dalam darah, maka kemungkinan meninggal akibat gagal jantung akan meningkat sebesar 1.0 kali, ketika variabel prediktor lainnya diatur pada nilai yang sama.

  • Blood.potassium: 2.5134246 Odds ratio untuk blood.potassium adalah 2.5134246. Ini menunjukkan bahwa pasien dengan kadar potassium darah yang tinggi memiliki kemungkinan 2.51 kali lebih tinggi untuk meninggal akibat gagal jantung dibandingkan dengan pasien dengan kadar potassium darah normal, ketika variabel prediktor lainnya diatur pada nilai yang sama.

Selanjutnya, karena dalam model regresi logistik kita tidak menginginkan adanya multikolinearitas, sehingga kita akan mengecek apakah ada indikasi multikolinearitas pada variabel di model yang telah dibuat.

Cek Multikolinearitas

vif(model_step)
#>                      age                  gendera                      BMI 
#>                 1.520861                 1.064437                 1.424701 
#>             hypertensive       atrialfibrillation           CHD.with.no.MI 
#>                 1.084321                 1.108062                 1.019068 
#>                 diabetes            Renal.failure               heart.rate 
#>                 1.136273                 1.287954                 1.337829 
#> Diastolic.blood.pressure         Respiratory.rate              temperature 
#>                 1.357476                 1.239541                 1.165543 
#>                    SP.O2             Urine.output                      RBC 
#>                 1.107445                 1.328313                 1.222002 
#>                Platelets                       PT                NT.proBNP 
#>                 1.135694                 1.077485                 1.300593 
#>          Creatine.kinase               Creatinine                  glucose 
#>                 1.119810                 1.674034                 1.140015 
#>          Blood.potassium 
#>                 1.292129

Tampak tidak adanya nilai vif > 10, artinya tidak ada multikolinearitas pada model ini.

Predict

Selanjutnya kita akan memprediksi probability outcome untuk data heart_test dan disimpan pada kolom baru bernama pred_out.

heart_test$pred_out <- predict(object = model_step,
                newdata = heart_test,
                type = "response")

heart_test

Kemudian akan kita klasifikasikan data heart_test berdasarkan pred_out dan selanjutnya hasilnya di simpan pada kolom baru bernama pred_Label, kita akan gunakan threshold 0.5.

heart_test$pred_Label <- ifelse(heart_test$pred_out < 0.5, 0, 1) %>% 
  as.factor()
heart_test

Kita akan mengecek hasil prediksi dan data aktualnya

heart_test %>% 
  select(pred_out, pred_Label, outcome)

Model Evaluation

confusionMatrix(
  data = heart_test$pred_Label, #hasil prediksi kita
  reference = heart_test$outcome, #data aslinya/aktual
  positive = "1"
)
#> Confusion Matrix and Statistics
#> 
#>           Reference
#> Prediction   0   1
#>          0 147   8
#>          1  57  24
#>                                           
#>                Accuracy : 0.7246          
#>                  95% CI : (0.6629, 0.7805)
#>     No Information Rate : 0.8644          
#>     P-Value [Acc > NIR] : 1               
#>                                           
#>                   Kappa : 0.286           
#>                                           
#>  Mcnemar's Test P-Value : 0.000000002622  
#>                                           
#>             Sensitivity : 0.7500          
#>             Specificity : 0.7206          
#>          Pos Pred Value : 0.2963          
#>          Neg Pred Value : 0.9484          
#>              Prevalence : 0.1356          
#>          Detection Rate : 0.1017          
#>    Detection Prevalence : 0.3432          
#>       Balanced Accuracy : 0.7353          
#>                                           
#>        'Positive' Class : 1               
#> 

Dari hasil di atas diperoleh informasi:

  • Accuracy : 0.7288, artinya ada 72.88% data yang diklasifikasikan dengan benar.
  • Sensitivity : 0.7812, artinya 78.12% kelas positif diklasifikasikan dengan benar dari data aktualnya.
  • Pos Pred Value : 0.3049, artinya tingkat presisi model memprediksi kelas positif sebesar 30.49%

Selanjutnya kita akan mengevaluasi model sesuai dengan business case-nya

  • Target variabel = meninggal atau hidup pada pasien gagal jantung
  • Kelas positif = meninggal FN - diprediksi hidup ternyata meninggal FP - diprediksi meninggal ternyata hidup

Karena kita ingin mengurangi kesalahan prediksi pasien hidup ternyata meninggal, maka metrik yang digunakan yakni * Metrics = Recall/FN

Setelah menentukan metrik yang digunakan, kita akan melakukan tuning model dengan salah satu cara tuning yaitu mengubah treshold prediction (note: cara ini tidak terlalu dianjurkan karena sangat tergantung pada konteks bisnis)

Tuning Model

# treshold diganti jadi 0.4 (direndahkan untuk meningkatkan recall)
heart_test$pred_Label_tune <- ifelse(heart_test$pred_out < 0.4,
                                     yes = 0,
                                     no = 1)

# confusion matrix
confusionMatrix(
  data = as.factor(heart_test$pred_Label_tune),
  reference = heart_test$outcome,
  positive = "1"
)
#> Confusion Matrix and Statistics
#> 
#>           Reference
#> Prediction   0   1
#>          0 134   5
#>          1  70  27
#>                                             
#>                Accuracy : 0.6822            
#>                  95% CI : (0.6187, 0.7411)  
#>     No Information Rate : 0.8644            
#>     P-Value [Acc > NIR] : 1                 
#>                                             
#>                   Kappa : 0.2697            
#>                                             
#>  Mcnemar's Test P-Value : 0.0000000000001467
#>                                             
#>             Sensitivity : 0.8438            
#>             Specificity : 0.6569            
#>          Pos Pred Value : 0.2784            
#>          Neg Pred Value : 0.9640            
#>              Prevalence : 0.1356            
#>          Detection Rate : 0.1144            
#>    Detection Prevalence : 0.4110            
#>       Balanced Accuracy : 0.7503            
#>                                             
#>        'Positive' Class : 1                 
#> 

Perbandingan nilai yang diperoleh

  • Model sebelum tuning:
    • Accuracy : 0.7288
    • Sensitivity : 0.7812
  • Model seteleh tuning:
    • Accuracy : 0.661
    • Sensitivity : 0.8438

Ternyata model sebelum tuning menghasilkan accuracy lebih tinggi daripada model setelah tuning, akan tetapi sensitivity justru tinggi di model setelah tuning.

Membandingkan hasil predict model pada train dan test

heart_train$pred_out <- predict(object = model_step,
                newdata = heart_train,
                type = "response")

heart_train$pred_Label <- ifelse(heart_train$pred_out < 0.5, 0, 1) %>% 
  as.factor()

confusionMatrix(
  data = heart_train$pred_Label, #hasil prediksi kita
  reference = heart_train$outcome, #data aslinya/aktual
  positive = "1"
)
#> Confusion Matrix and Statistics
#> 
#>           Reference
#> Prediction   0   1
#>          0 574 201
#>          1 194 567
#>                                              
#>                Accuracy : 0.7428             
#>                  95% CI : (0.7202, 0.7645)   
#>     No Information Rate : 0.5                
#>     P-Value [Acc > NIR] : <0.0000000000000002
#>                                              
#>                   Kappa : 0.4857             
#>                                              
#>  Mcnemar's Test P-Value : 0.7627             
#>                                              
#>             Sensitivity : 0.7383             
#>             Specificity : 0.7474             
#>          Pos Pred Value : 0.7451             
#>          Neg Pred Value : 0.7406             
#>              Prevalence : 0.5000             
#>          Detection Rate : 0.3691             
#>    Detection Prevalence : 0.4954             
#>       Balanced Accuracy : 0.7428             
#>                                              
#>        'Positive' Class : 1                  
#> 
  • Model di data test:
    • Accuracy : 0.7288
    • Sensitivity : 0.7812
  • Model di data train:
    • Accuracy : 0.7454
    • Sensitivity : 0.7480

Tampak nilai accuracy di train lebih besar dibandingkan di test, hal ini mengindikasikan model overfitting, tapi selisihnya hanya 1.66%, bisa dikatakan model masih bisa diterima sebagai model bukan overfitting.

k-NN

Model selanjutnya yang akan dibuat adalah k-NN atau K-nearest neighboor yang mana cara kerja model ini akan mengklasifikasi data baru dengan membandingkan karakteristik data baru (data test) dengan data yang ada (data train). Kedekatan karakteristik tersebut diukur dengan Euclidean Distance hingga didapatkan jarak. Kemudian akan dipilih k tetangga terdekat dari data baru tersebut, kemudian ditentukan kelasnya menggunakan majority voting.

Hal yang perlu diperhatikan ketika membuat model k-NN yakni range di setiap variabelnya harus sama, karena k-NN mengklasifikasikan data dengan cara mengukur jarak, hal ini akan mempengaruhi hasil dari prediksi ketika range dari setiap variabel yang digunakan tidak di scaling terlebih dahulu.

Untuk k-NN, dipisahkan antara prediktor dan targetnya. Sebelum melakukan pemisahan, kita akan melakukan scaling pada data kita. Disini kita akan tetap memasukkan variabel kategorik karena dari data hanya terdiri dari 2 angka saja.

# mengubah prediktor kategorik menjadi numerik karena hanya terdapat dua nilai yaitu 0 dan 1
heart_train1 <- heart_train %>% 
  mutate_if(is.factor, ~ as.numeric(as.character(.x))) %>% 
  mutate(gendera = ifelse(gendera == 1, 0, 1))

heart_test1 <- heart_test %>% 
  mutate_if(is.factor, ~ as.numeric(as.character(.x))) %>% 
  mutate(gendera = ifelse(gendera == 1, 0, 1))

# prediktor 
heart_train_x1 <- select(heart_train1, -c(outcome, pred_out, pred_Label))
heart_test_x1 <- select(heart_test1, -c(outcome, pred_out, pred_Label, pred_Label_tune))
  
# target
heart_train_y1 <- heart_train1[, "outcome"]  
heart_test_y1 <- heart_test1[, "outcome"]

Data prediktor akan discaling menggunakan z-score standarization. Data test juga harus discaling menggunakan parameter dari data train (karena menganggap data test adalah unseen data).

heart_train_x1_scale <- scale(x = heart_train_x1)
heart_test_x1_scale <- scale(x = heart_test_x1,
                           center = attr(heart_train_x1_scale,"scaled:center"),
                           scale = attr(heart_train_x1_scale,"scaled:scale"))

karena kita menscaling data test yang mana harus mengandung informasi mean dan std dari train agar di model test nantinya bisa mengenal bahwa data train itu bekerja di mean dan std tersebut.

Selanjutnya kita akan mencari nilia k optimum dengan cara mencari akar dari jumlah data kita: sqrt(nrow(data))

# find optimum k
sqrt(nrow(heart_train1))
#> [1] 39.19184

karena target bernilai genap jadi k-nya ganjil

library(class) # package untuk fungsi `knn()`

heart_pred <- knn(train = heart_train_x1_scale, #data train yang sudah discale
                 test = heart_test_x1_scale, #data test yang sudah discale
                 cl = heart_train_y1, #target dari data train latihan
                 k = 39)

Model Evaluation

# confusion matrix
confusionMatrix(
  data = as.factor(heart_pred),
  reference = as.factor(heart_test_y1),
  positive = "1"
)
#> Confusion Matrix and Statistics
#> 
#>           Reference
#> Prediction   0   1
#>          0 136   8
#>          1  68  24
#>                                           
#>                Accuracy : 0.678           
#>                  95% CI : (0.6143, 0.7371)
#>     No Information Rate : 0.8644          
#>     P-Value [Acc > NIR] : 1               
#>                                           
#>                   Kappa : 0.2327          
#>                                           
#>  Mcnemar's Test P-Value : 0.00000000001308
#>                                           
#>             Sensitivity : 0.7500          
#>             Specificity : 0.6667          
#>          Pos Pred Value : 0.2609          
#>          Neg Pred Value : 0.9444          
#>              Prevalence : 0.1356          
#>          Detection Rate : 0.1017          
#>    Detection Prevalence : 0.3898          
#>       Balanced Accuracy : 0.7083          
#>                                           
#>        'Positive' Class : 1               
#> 

Dari hasil di atas diperoleh informasi:

  • Accuracy : 0.6695, artinya ada 66.95% data yang diklasifikasikan dengan benar.

  • Sensitivity : 0.71875, artinya 71.87% kelas positif diklasifikasikan dengan benar dari data aktualnya.

  • Pos Pred Value : 0.2500, artinya tingkat presisi model memprediksi kelas positif sebesar 25.00%

  • Target variabel = meninggal atau hidup pada pasien gagal jantung

  • Kelas positif = meninggal FN - diprediksi hidup ternyata meninggal FP - diprediksi meninggal ternyata hidup

  • Metrics = Recall/FN

Kesimpulan

  • Berdasarkan hasil model regresi logistik, ternyata ada beberapa faktor yang meningkatkan kemungkinan seorang akan meninggal ketika terkena gagal jantung seperti kandungan Blood.potassium, PT, NT.proBNP, Creatine.kinase, dan glucose yang tinggi pada pasien, tanda vital berupa Respiratory.rate dan heart rate yang tinggi dan juga beberapa penyakit bawaan yang diderita pasien seperti atrial fibrillation dan diabetes, dan jantung koroner tanpa serangan jantung.

  • Berdasarkan hasil dari ketiga model yang dibuat, diperoleh:

  • Model regresi logistik sebelum tuning:

    • Accuracy : 0.7288
    • Sensitivity : 0.7812
  • Model regresi logistik seteleh tuning:

    • Accuracy : 0.661
    • Sensitivity : 0.8438
  • Model k-NN

    • Accuracy : 0.6695
    • Sensitivity : 0.71875

Dari hasil 2 jenis model yang dilakukan, model regresi logistik memiliki nilai accuracy yang lebih tinggi dibanding dengan model k-NN. Untuk kasus ini, kita fokus untuk melihat nilai sensitivity karena kita ingin menurunkan salah tebak untuk kasus diprediksi hidup tapi ternyata meninggal. Maka berdasarkan nilai Sensitivity, untuk dataset model regresi logistik lebih cocok digunakan untuk melakukan prediksi pada dataset kali ini.

Dari perbandingan nilai akurasi di setiap model di atas, untuk kasus epidemiologi klinik seperti di dataset, nilai akurasinya belum bisa dikatakan baik, karena ketika kita membuat model untuk memprediksi nyawa seseorang, tingkat akurasi dan sensitivitas yang digunakan harus tinggi. Sehingga bisa disimpulkan model tidak bisa digunakan. Agar bisa digunakan perlu proses tuning lanjutan atau menambahkan data pada penelitian ini.

Reference

  1. Missing data and multiple imputation in clinical epidemiological research https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5358992/

  2. Principled Approaches to Missing Data in Epidemiologic Studies https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5860376/

  3. Heckman imputation models for binary or continuous MNAR outcomes and MAR predictors https://bmcmedresmethodol.biomedcentral.com/articles/10.1186/s12874-018-0547-1

  4. Exceptionally High Creatine Kinase (CK) Levels in Multicausal and Complicated Rhabdomyolysis: A Case Report https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5507674/