Cardiovascular Disease - Prediksi
Pengantar
Latar Belakang
Penyakit kardiovaskular merupakan penyakit yang tidak boleh dianggap remeh. Menurut data World Health Organization penyakit kardiovaskular dapat menyebabkan kematian 17,6 juta orang tiap tahunnya. Banyak faktor yang dapat menyebabkan seseorang terkena penyakit kardiovaskular, seperti pola makan tidak sehat, kebiasaan merokok, kebiasaan kurang gerak dan jarang berolahraga, konsumsi alkohol berlebihan, dsb.
Kita akan menggunakan dataset Cardiovascular Disease untuk mengetahui kemungkinan seseorang divonis penyakit kardiovaskular berdasarkan variabel yang ada dengan menggunakan model machine learning. Kita akan membuat model Logistic Regression dan K-NN dan membandingkan performa kedua model tersebut.
Tentang Dataset
Dataset Cardiovascular Disease merupakan data pasien yang diambil pada saat melakukan pemeriksaan kesehatan. Dataset memiliki 70.000 baris dan 13 kolom yang terdiri dari.
id
: Nomor ID age
: Umur dalam hari
gender
: Jenis kelamin, 1 = Perempuan 2 = Laki-laki
height
: Tinggi badan dalam cm
weight
: Berat badan dalam kg ap_hi
:
Tekanan darah sistolik ap_lo
: Tekanan darah
diastolik cholesterol
: Kadar kolesterol, 1 = Normal
2 = Di Atas Normal 3 = Jauh di Atas Normal gluc
:
Kadar gula darah, 1 = Normal 2 = Di Atas Normal 3 = Jauh di Atas Normal
smoke
: Apakah pasien merokok?, 1 = Ya 2 = Tidak
alco
: Apakah pasien peminum?, 1 = Ya 2 = Tidak
active
: Apakah pasien aktif bergerak?, 1 = Ya 2 = Tidak
cardio
: Penyakit kardiovaskular, 1 = Ya 2 =
Tidak
Set Up
Yang pertama kita lakukan adalah memanggil library yang dibutuhkan.
library(tidyverse)
library(GGally)
library(reactable)
library(car)
library(caret)
library(class)
Data Wrangling
Selanjutnya kita input dataset Cardiovascular
Disease menggunakan fungsi read.csv()
dan
menyimpannya ke dalam variabel cardio_raw
.
<- read.csv("cardio_train.csv")
cardio_raw
reactable(cardio_raw)
Variabel dan nilai pada dataset yang kita punya masih dalam bentuk
satu kesatuan. Kita perlu untuk memisahkan mereka menjadi 13 kolom
menggunakan fungsi separate()
.
<-
cardio %>%
cardio_raw separate(id.age.gender.height.weight.ap_hi.ap_lo.cholesterol.gluc.smoke.alco.active.cardio,
c("id", "age", "gender", "height", "weight", "decimal", "ap_hi", "ap_lo", "cholesterol", "gluc", "smoke", "alco", "active", "cardio")) %>%
select(-c(decimal, id)) %>%
head(200)
reactable(cardio)
Setelah itu kita melakukan glimpse()
untuk melihat
apakah tipe data sudah sesuai.
glimpse(cardio)
## Rows: 200
## Columns: 12
## $ age <chr> "18393", "20228", "18857", "17623", "17474", "21914", "221…
## $ gender <chr> "2", "1", "1", "2", "1", "1", "1", "2", "1", "1", "1", "2"…
## $ height <chr> "168", "156", "165", "169", "156", "151", "157", "178", "1…
## $ weight <chr> "62", "85", "64", "82", "56", "67", "93", "95", "71", "68"…
## $ ap_hi <chr> "110", "140", "130", "150", "100", "120", "130", "130", "1…
## $ ap_lo <chr> "80", "90", "70", "100", "60", "80", "80", "90", "70", "60…
## $ cholesterol <chr> "1", "3", "3", "1", "1", "2", "3", "3", "1", "1", "1", "1"…
## $ gluc <chr> "1", "1", "1", "1", "1", "2", "1", "3", "1", "1", "1", "1"…
## $ smoke <chr> "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"…
## $ alco <chr> "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"…
## $ active <chr> "1", "1", "0", "1", "0", "0", "1", "1", "1", "0", "1", "1"…
## $ cardio <chr> "0", "1", "1", "1", "0", "0", "0", "1", "0", "0", "0", "0"…
Terdapat beberapa variabel yang perlu untuk diubah tipe datanya.
Dalam hal ini kolom age
, height
,
weight
, ap_hi
, ap_lo
menjadi tipe
data numerik dan kolom gender
, cholesterol
,
gluc
, smoke
, alco
,
active
, cardio
menjadi factor.
<-
cardio %>%
cardio mutate(age = as.numeric(age),
height = as.numeric(height),
weight = as.numeric(weight),
ap_hi = as.numeric(ap_hi),
ap_lo = as.numeric(ap_lo),
gender = as.factor(gender),
cholesterol = as.factor(cholesterol),
gluc = as.factor(gluc),
smoke = as.factor(smoke),
alco = as.factor(alco),
active = as.factor(active),
cardio = as.factor(cardio))
glimpse(cardio)
## Rows: 200
## Columns: 12
## $ age <dbl> 18393, 20228, 18857, 17623, 17474, 21914, 22113, 22584, 17…
## $ gender <fct> 2, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 2, 1, 2, 2, 1, 1, 1, 2…
## $ height <dbl> 168, 156, 165, 169, 156, 151, 157, 178, 158, 164, 169, 173…
## $ weight <dbl> 62, 85, 64, 82, 56, 67, 93, 95, 71, 68, 80, 60, 60, 78, 95…
## $ ap_hi <dbl> 110, 140, 130, 150, 100, 120, 130, 130, 110, 110, 120, 120…
## $ ap_lo <dbl> 80, 90, 70, 100, 60, 80, 80, 90, 70, 60, 80, 80, 80, 70, 9…
## $ cholesterol <fct> 1, 3, 3, 1, 1, 2, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
## $ gluc <fct> 1, 1, 1, 1, 1, 2, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1…
## $ smoke <fct> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1…
## $ alco <fct> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0…
## $ active <fct> 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1…
## $ cardio <fct> 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0…
Setelah tipe data sudah sesuai selanjutnya kita melihat apakah
terdapat missing value menggunakan anyNA()
.
anyNA(cardio)
## [1] FALSE
Tidak terdapat missing value pada dataset Cardiovascular Disease.
Exploratory Data Analysis
Dalam tahap Exploratory Data Analysis yang pertama
kita lakukan adalah summary()
. Hal ini bertujuan untuk
melihat bagaimana persebaran dan karakteristik dataset yang kita
punya.
summary(cardio)
## age gender height weight ap_hi
## Min. :14321 1:118 Min. :148.0 Min. : 45.00 Min. : 90.0
## 1st Qu.:18081 2: 82 1st Qu.:158.0 1st Qu.: 63.75 1st Qu.:120.0
## Median :19660 Median :165.0 Median : 71.00 Median :120.0
## Mean :19542 Mean :165.2 Mean : 73.17 Mean :126.8
## 3rd Qu.:21756 3rd Qu.:170.0 3rd Qu.: 82.00 3rd Qu.:140.0
## Max. :23589 Max. :188.0 Max. :115.00 Max. :190.0
## ap_lo cholesterol gluc smoke alco active cardio
## Min. : 60.00 1:147 1:174 0:179 0:191 0: 46 0:100
## 1st Qu.: 80.00 2: 32 2: 15 1: 21 1: 9 1:154 1:100
## Median : 80.00 3: 21 3: 11
## Mean : 81.38
## 3rd Qu.: 90.00
## Max. :110.00
Kita juga perlu untuk melihat proporsi jumlah variabel target apakah seimbang atau tidak. Hal ini bertujuan agar memaksimalkan performa model dalam bekerja.
prop.table(table(cardio$cardio))
##
## 0 1
## 0.5 0.5
Proporsi jumlah variabel target sudah seimbang.
Untuk melihat korelasi antar variabel kita lakukan
ggcorr()
.
ggcorr(cardio, label = T)
Berdasarkan plot di atas korelasi signifikan positif terdapat pada
variabel ap_lo
dan ap_hi
. Sedangkan variabel
ap_hi
dan height
sama sekali tidak
menggambarkan korelasi. Untuk height
dan age
berkorelasi negatif tetapi tidak signifikan.
Cross Validation
Cross Validation adalah proses dimana kita membagi
dataset yang kita punya untuk melatih dan menguji model. Kita akan
mengambil sample Cardiovascular Disease secara random
untuk dimasukkan ke dalam variabel cardio_train
sebanyak
80% dan sisanya dimasukkan ke dalam cardio_test
.
RNGkind(sample.kind = "Rounding")
set.seed(417)
<- sample(x = nrow(cardio), size = nrow(cardio)*0.8)
index
<- cardio[index,]
cardio_train <- cardio[-index,] cardio_test
Modeling
Kita akan membuat beberapa model dan menguji performanya.
Tanpa Prediktor
Model yang pertama kita buat adalah model tanpa prediktor menggunakan
glm()
dan dimasukkan dalam variabel
model_1
.
<- glm(formula = cardio ~ 1,
model_1 data = cardio_train,
family = "binomial")
summary(model_1)
##
## Call:
## glm(formula = cardio ~ 1, family = "binomial", data = cardio_train)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -1.156 -1.156 -1.156 1.199 1.199
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -0.05001 0.15816 -0.316 0.752
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 221.71 on 159 degrees of freedom
## Residual deviance: 221.71 on 159 degrees of freedom
## AIC: 223.71
##
## Number of Fisher Scoring iterations: 3
Nilai (Intercept) pada model tanpa prediktor merupakan nilai log of odds dari variabel target 1 atau pasien yang divonis penyakit cardiovascular. Yang perlu kita perhatikan juga untuk model tanpa prediktor adalah nilai Null Deviance. Semakin kecil nilai Null Deviance semakin baik sebuah model. Yang terakhir adalah nilai AIC yang merupakan jumlah informasi yang hilang. Sama seperti Null Deviance semakin kecil nilai AIC semakin baik sebuah model.
Karena nilai (Intercept) tidak dapat
diinterpretasikan maka kita perlu mengubahnya ke odds menggunakan fungsi
exp()
.
exp(-0.05001)
## [1] 0.9512199
Dari nilai di atas kita dapat menginterpretasikan 0,95 kali lebih mungkin pasien divonis penyakit kardiovascular dibanding dengan yang tidak.
Prediktor Kategorik
Setelah membuat model tanpa prediktor kita akan membuat model dengan
prediktor kategorik. Seluruh variabel bertipe factor kita jadikan
prediktor dan menyimpannya ke dalam variabel model_cat
.
<- glm(formula = cardio ~ gender + cholesterol + gluc + smoke + alco + active,
model_cat data = cardio_train,
family = "binomial")
summary(model_cat)
##
## Call:
## glm(formula = cardio ~ gender + cholesterol + gluc + smoke +
## alco + active, family = "binomial", data = cardio_train)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -2.3889 -1.0386 -0.7144 1.2883 1.4002
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -0.50109 0.38319 -1.308 0.190975
## gender2 0.07872 0.37423 0.210 0.833400
## cholesterol2 -0.17417 0.55010 -0.317 0.751540
## cholesterol3 2.88660 0.87292 3.307 0.000944 ***
## gluc2 0.46248 0.68182 0.678 0.497584
## gluc3 -0.85663 0.94311 -0.908 0.363717
## smoke1 0.16431 0.62552 0.263 0.792794
## alco1 0.83047 0.96438 0.861 0.389161
## active1 0.16543 0.40221 0.411 0.680848
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 221.71 on 159 degrees of freedom
## Residual deviance: 200.30 on 151 degrees of freedom
## AIC: 218.3
##
## Number of Fisher Scoring iterations: 4
Karena kita membuat model dengan prediktor, nilai yang harus kita perhatikan adalah nilai Residual Deviance. Nilai tersebut lebih kecil dari model sebelumnya. Begitu juga dengan nilai AIC yang lebih kecil dari model sebelumnya. Ini mengindikasikan model semakin baik.
Berbeda dengan yang di atas kita perlu untuk mengambil satu contoh
variabel yang ingin kita interpretasikan. Kita memilih variabel
alco1
dengan nilai log of odds 0,83047.
exp(0.83047)
## [1] 2.294397
Berdasarkan hasil di atas kita dapat menginterpretasikan bahwa pasien yang merupakan seorang peminum 2,29 kali lebih mungkin divonis penyakit kardiovaskular dibandingkan dengan yang tidak.
Prediktor Numerik
Model ketiga adalah model dengan prediktor numerik. Sama seperti prediktor kategorik semua variabel bertipe data numerik kita jadikan prediktor.
<- glm(formula = cardio ~ weight + age + height + ap_hi + ap_lo,
model_num data = cardio_train,
family = "binomial")
summary(model_num)
##
## Call:
## glm(formula = cardio ~ weight + age + height + ap_hi + ap_lo,
## family = "binomial", data = cardio_train)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -2.4550 -0.9693 -0.4350 0.9559 2.0931
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -1.078e+01 4.334e+00 -2.487 0.0129 *
## weight 3.532e-03 1.468e-02 0.241 0.8098
## age 1.116e-04 7.618e-05 1.465 0.1429
## height -4.388e-03 2.329e-02 -0.188 0.8506
## ap_hi 4.167e-02 1.915e-02 2.176 0.0296 *
## ap_lo 4.653e-02 3.109e-02 1.497 0.1345
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 221.71 on 159 degrees of freedom
## Residual deviance: 183.28 on 154 degrees of freedom
## AIC: 195.28
##
## Number of Fisher Scoring iterations: 4
Dengan menggunakan prediktor numerik nilai Residual Deviance dan AIC lebih kecil dari model yang sebelumnya. Ini mengindikasikan model semakin baik.
Kita mengambil variabel age
dengan nilai log of odds
1,116e-04 untuk diinterpretasikan.
exp(1.116e-04)
## [1] 1.000112
Dari hasil di atas dapat diinterpretasikan bahwa dengan meningkatnya
satu point dari nilai variabel age
maka satu kali lebih
mungkin pasien divonis penyakit kardiovaskular.
Semua
Yang terakhir kita membuat model dengan variabel bertipe data kategorik dan numerik dijadikan sebagai prediktor.
<- glm(formula = cardio ~ .,
model_all data = cardio_train,
family = "binomial")
summary(model_all)
##
## Call:
## glm(formula = cardio ~ ., family = "binomial", data = cardio_train)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -2.2473 -0.8568 -0.4118 0.8944 2.3008
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -1.257e+01 5.153e+00 -2.438 0.0148 *
## age 1.298e-04 8.272e-05 1.569 0.1167
## gender2 -4.584e-02 4.818e-01 -0.095 0.9242
## height 9.173e-03 2.809e-02 0.326 0.7440
## weight -2.553e-03 1.641e-02 -0.156 0.8763
## ap_hi 2.961e-02 2.009e-02 1.474 0.1404
## ap_lo 5.720e-02 3.396e-02 1.684 0.0921 .
## cholesterol2 -5.428e-01 6.555e-01 -0.828 0.4076
## cholesterol3 2.335e+00 9.072e-01 2.573 0.0101 *
## gluc2 4.694e-01 8.226e-01 0.571 0.5682
## gluc3 -4.793e-01 9.956e-01 -0.481 0.6302
## smoke1 -1.071e-01 6.885e-01 -0.156 0.8763
## alco1 5.733e-01 1.072e+00 0.535 0.5926
## active1 1.749e-01 4.567e-01 0.383 0.7017
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 221.71 on 159 degrees of freedom
## Residual deviance: 171.09 on 146 degrees of freedom
## AIC: 199.09
##
## Number of Fisher Scoring iterations: 5
Kita dapat melihat nilai Residual Deviance dan nilai AIC adalah nilai terkecil diantara model-model sebelumnya. Kita dapat menginterpretasikan model tersebut adalah model yang terbaik.
Sebelum kita melakukan prediksi kita melakukan uji asumsi
Multicollinearity. Kita perlu mengetahui apakah antar
prediktor memiliki korelasi kuat hingga satu atau minus satu. Hal ini
untuk menghindari variabel redundan pada model. Kita dapat menggunakan
fungsi vif()
seperti pada chunk di bawah.
vif(model_all)
## GVIF Df GVIF^(1/(2*Df))
## age 1.146507 1 1.070751
## gender 1.637035 1 1.279467
## height 1.684248 1 1.297786
## weight 1.543854 1 1.242519
## ap_hi 2.151095 1 1.466661
## ap_lo 2.224869 1 1.491599
## cholesterol 2.282557 2 1.229152
## gluc 2.292236 2 1.230452
## smoke 1.300683 1 1.140475
## alco 1.120498 1 1.058536
## active 1.086204 1 1.042211
Berdasarkan hasil vif()
di atas tidak terdapat nilai
yang lebih besar dari 10. Maka bisa diasumsikan tidak ada
multicollinearity atau uji asumsi terpenuhi.
Prediction
Setelah membuat model kita melakukan prediksi.
Tanpa Prediktor
Pertama melakukan prediksi menggunakan model tanpa prediktor. Kita
menggunakan fungsi predict()
pada data baru
cardio_test
.
<- predict(object = model_1,
pred_prob newdata = cardio_test,
type = "response")
head(pred_prob)
## 11 15 29 43 46 47
## 0.4875 0.4875 0.4875 0.4875 0.4875 0.4875
Kita perlu mengklasifikasikan hasil prediksi untuk mengetahui jumlah
pasien yang kemungkinan divonis penyakit kardiovaskular. Kita
menggunakan fungsi ifelse()
dan menetapkan threshold
0,5.
<- ifelse(pred_prob > 0.5, yes = 1, no = 0)
pred_label
<- as.factor(pred_label)
pred_label
head(pred_label)
## 11 15 29 43 46 47
## 0 0 0 0 0 0
## Levels: 0
Pada enam data teratas hasil prediksi menunjukkan tidak terdapat pasien dengan kemungkinan divonis penyakit kardiovaskular.
Prediktor Kategorik
Yang perlu kita lakukan selanjutnya melakukan prediksi menggunakan model dengan prediktor kategorik.
<- predict(object = model_cat,
pred_prob2 newdata = cardio_test,
type = "response")
head(pred_prob2)
## 11 15 29 43 46 47
## 0.4168641 0.6765231 0.4361154 0.4361154 0.4168641 0.3752341
Sama dengan sebelumnya kita menggunakan threshold 0,5.
<- ifelse(pred_prob2 > 0.5, yes = 1, no = 0)
pred_label2
<- as.factor(pred_label2)
pred_label2
head(pred_label2)
## 11 15 29 43 46 47
## 0 1 0 0 0 0
## Levels: 0 1
Dengan menggunakan model dengan prediktor kategorik pada enam data teratas menunjukkan satu pasien yang kemungkinan divonis penyakit kardiovaskular.
Prediktor Numerik
Selanjutnya menggunakan model dengan prediktor numerik yaitu
model_num
.
<- predict(object = model_num,
pred_prob3 newdata = cardio_test,
type = "response")
head(pred_prob3)
## 11 15 29 43 46 47
## 0.4994445 0.4968867 0.2836613 0.7560348 0.6695294 0.7952308
Kita kembali mengklasifikasikan nilai hasil prediksi dan menyimpannya
dalam variabel pred_label3
.
<- ifelse(pred_prob3 > 0.5, yes = 1, no = 0)
pred_label3
<- as.factor(pred_label3)
pred_label3
head(pred_label3)
## 11 15 29 43 46 47
## 0 0 0 1 1 1
## Levels: 0 1
Meningkat dari sebelumnya pada enam data teratas terdapat tiga pasien yang kemungkinan divonis penyakit kardiovaskular.
Semua
Yang terakhir adalah model dengan semua variabel dijadikan prediktor.
<- predict(object = model_all,
pred_prob4 newdata = cardio_test,
type = "response")
head(pred_prob4)
## 11 15 29 43 46 47
## 0.5020859 0.5819560 0.2570082 0.7381329 0.6207697 0.5577139
Kita kembali melihat hasil klasifikasi nilai prediksi
pred_prob4
.
<- ifelse(pred_prob4 > 0.5, yes = 1, no = 0)
pred_label4
<- as.factor(pred_label4)
pred_label4
head(pred_label4)
## 11 15 29 43 46 47
## 1 1 0 1 1 1
## Levels: 0 1
Dengan model ini pada enam data teratas ada lima kemungkinan pasien yang divonis penyakit kardiovaskular.
Kita perlu melakukan evaluasi model menggunakan fungsi
confusionMatrix()
dari library caret. Kita akan
membandingkan hasil prediksi dengan referensi data yang kita punya.
confusionMatrix(data = pred_label4,
reference = cardio_test$cardio,
positive = "1")
## Confusion Matrix and Statistics
##
## Reference
## Prediction 0 1
## 0 13 7
## 1 5 15
##
## Accuracy : 0.7
## 95% CI : (0.5347, 0.8344)
## No Information Rate : 0.55
## P-Value [Acc > NIR] : 0.03859
##
## Kappa : 0.4
##
## Mcnemar's Test P-Value : 0.77283
##
## Sensitivity : 0.6818
## Specificity : 0.7222
## Pos Pred Value : 0.7500
## Neg Pred Value : 0.6500
## Prevalence : 0.5500
## Detection Rate : 0.3750
## Detection Prevalence : 0.5000
## Balanced Accuracy : 0.7020
##
## 'Positive' Class : 1
##
Dari hasil confusionMatrix()
di atas kita dapat melihat
rentang nilai yang cukup besar antara True Positive dan
False Positive. Begitu juga dengan True
negative dan False Negative. Ini menandakan
model yang kita buat sudah cukup baik. Kita juga dapat melihat kebaikan
dari sebuah model berdasarkan nilai Accuracynya. Model
yang kita punya memiliki nilai Accuracy 0,7.
Model yang sudah kita buat memiliki performa yang cukup baik tetapi kita perlu melakukan evaluasi. Kita akan memanfaatkan metriks Sensitivity atau Recall dengan tujuan untuk meminimalisir prediksi yang salah terhadap pasien yang kemungkinan besar divonis penyakit kardiovaskular. Kita menurunkan nilai threshold menjadi 0,4 dan melihat hasil prediksinya kembali.
<- ifelse(pred_prob4 > 0.4, yes = 1, no = 0)
pred_label5
<- as.factor(pred_label5)
pred_label5
head(pred_label5)
## 11 15 29 43 46 47
## 1 1 0 1 1 1
## Levels: 0 1
Kita melakukan confusionMatrix()
terhadap hasil prediksi
yang baru.
confusionMatrix(data = pred_label5,
reference = cardio_test$cardio,
positive = "1")
## Confusion Matrix and Statistics
##
## Reference
## Prediction 0 1
## 0 12 6
## 1 6 16
##
## Accuracy : 0.7
## 95% CI : (0.5347, 0.8344)
## No Information Rate : 0.55
## P-Value [Acc > NIR] : 0.03859
##
## Kappa : 0.3939
##
## Mcnemar's Test P-Value : 1.00000
##
## Sensitivity : 0.7273
## Specificity : 0.6667
## Pos Pred Value : 0.7273
## Neg Pred Value : 0.6667
## Prevalence : 0.5500
## Detection Rate : 0.4000
## Detection Prevalence : 0.5500
## Balanced Accuracy : 0.6970
##
## 'Positive' Class : 1
##
Setelah itu kita dapat melihat rentang nilai antara True Positive dan False Positive sudah cukup berkurang. Nilai Sensitivity bertambah menjadi 0,7273 dan Accuracy tidak berubah dari model sebelumnya.
K-NN
Kita akan membuat satu model lagi menggunakan metode K-NN atau K-Nearest Neighbor. Metode ini akan mengklasifikasikan data test berdasarkan karakteristik data train. Klasifikasi ditentukan berdasarkan kedekatan karakteristik yang diukur dengan cara Euclidean Distance atau menghitung jarak. Setelah itu dipilih menggunakan majority voting sesuai dengan nilai k yang sudah kita tentukan. Nilai k adalah jumlah data terdekat dari data test. Kita akan memisahkan terlebih dahulu variabel target dan variabel prediktor sebelum membuat model K-NN.
<- cardio_train[,-c(2,7,8,9,10,11,12)]
cardio_train_x <- cardio_test[,-c(2,7,8,9,10,11,12)]
cardio_test_x
<- cardio_train$cardio
cardio_train_y <- cardio_test$cardio cardio_test_y
Setelah itu kita melakukan scaling pada variabel prediktor di data train dan data test.
<- scale(cardio_train_x)
cardio_train_xs
<- scale(cardio_test_x ,
cardio_test_xs center = attr(cardio_train_xs,"scaled:center"),
scale = attr(cardio_train_xs,"scaled:scale"))
Seperti yang sudah kita bahas sebelumnya kita perlu menentukan nilai k. Untuk mendapatkan nilai k yang optimal kita dapat mengakar kuadratkan jumlah baris pada data kita.
sqrt(nrow(cardio_train_xs))
## [1] 12.64911
Yang selanjutnya kita lakukan adalah melakukan prediksi menggunakan
fungsi knn()
.
<- knn(train = cardio_train_xs,
cardio_pred test = cardio_test_xs,
cl = cardio_train_y,
k = 13)
head(cardio_pred)
## [1] 1 0 0 1 1 1
## Levels: 0 1
Di atas kita dapat melihat hasil prediksi pada model yang telah kita buat.
Kita melakukan confusionMatrix()
untuk evaluasi sama
seperti model-model sebelumnya.
confusionMatrix(data = cardio_pred,
reference = cardio_test_y,
positive = "1")
## Confusion Matrix and Statistics
##
## Reference
## Prediction 0 1
## 0 15 5
## 1 3 17
##
## Accuracy : 0.8
## 95% CI : (0.6435, 0.9095)
## No Information Rate : 0.55
## P-Value [Acc > NIR] : 0.0008833
##
## Kappa : 0.6
##
## Mcnemar's Test P-Value : 0.7236736
##
## Sensitivity : 0.7727
## Specificity : 0.8333
## Pos Pred Value : 0.8500
## Neg Pred Value : 0.7500
## Prevalence : 0.5500
## Detection Rate : 0.4250
## Detection Prevalence : 0.5000
## Balanced Accuracy : 0.8030
##
## 'Positive' Class : 1
##
Model K-NN memiliki nilai Accuracy yang lebih tinggi dibanding dengan model-model yang sudah kita buat sebelumnya. Rentang nilai antara True Positive dan False Positive juga sangat besar begitu juga dengan True Negative dan False Negative. Oleh karena itu model K-NN adalah model yang robust tetapi tidak dapat diinterpretasikan.
Kesimpulan
Kita sudah membuat model Logistic Regression dan K-NN. Model Logistic Regression dengan performa yang paling baik yang telah kita buat adalah model yang menggunakan semua variabelnya untuk dijadikan sebagai prediktor. Tetapi kita perlu menurunkan threshold untuk meminimalisir prediksi yang salah terhadap pasien yang kemungkinan besar divonis penyakit kardiovaskular. Sedangkan performa model K-NN lebih robust dalam melakukan prediksi dibandingkan dengan model Logistic Regression. Tetapi model K-NN merupakan model yang tidak dapat diinterpretasi.