Pada kesempatan ini, pemodelan yang dilakukan adalah untuk memprediksi seseorang menderita penyakit jantung atau tidak (“1” = menderita / sakit, “0” = tidak menderita / sehat). Pemodelan dilakukan menggunakan Logistic Regression dan k-Nearest Neighbor.
Kelas target yang diamati (kelas positif) pada pemodel ini adalah (“1” = menderita / sakit). Akan dibandingkan confusionMatix dari kedua model, dangan urutan prioritas berdasarkan:
1. Recall, yaitu seberapa akurat kedua model dalam memprediksi kelas positif (“1” = sakit) dari semua kelas positif (“1” = sakit) yang sebenarnya.
Artinya, tidak diinginkan tingginya error (adanya terprediksi “sehat” untuk yang “sakit”), dengan alasan membahayakan keselamatan orang - orang yang “sakit”, apabila mereka diprediksi “sehat”.
2. Precission, yaitu seberapa akurat kedua model memprediksi kelas positif (“1” = sakit) dari semua kelas positif (“1” = sakit) yang terprediksi.
Artinya, error (adanya terprediksi “sakit” untuk yang “sehat”) menjadi prioritas kedua, karena tidak terlalu membahayakan.
3. Accuracy yang tinggi, yaitu seberapa akurat masing - masing model memprediksi kelas target (baik sehat ataupun sakit) secara global.
Data diperoleh dari website kaggle.com, dengan alamat: https://www.kaggle.com/ronitf/heart-disease-uci.
Berikut ini informasi tentang data:
- age: usia (tahun)
- sex: jenis kelamin (1 = male; 0 = female)
- cp: tipe nyeri dada (1 = typical angina; 2 = atypical angina; 3 = non-anginal pain; 4 = asymptomatic)
- trestbps: tekanan darah istirahat (in mm Hg on admission to the hospital)
- chol: serum kolesterol (in mg/dl)
- fbs: gula darah puasa > 120 mg/dl (1 = true; 0 = false)
- restecg: hasil elektrokardiografi istirahat (0 = normal; 1 = having ST-T wave abnormality (T wave inversions and/or ST elevation or depression of > 0.05 mV); 2 = showing probable or definite left ventricular hypertrophy by Estes’ criteria)
- thalach: denyut jantung maksimum
- exang: latihan yang diinduksi angina (1 = yes; 0 = no)
- oldpeak: Depresi ST disebabkan oleh olahraga relatif terhadap istirahat
- slope: kemiringan segmen latihan ST puncak (1 = upsloping; 2 = flat; 3 = downsloping)
- ca: jumlah pembuluh darah utama (0-3) diwarnai dengan fluoroskopi
- thal: 3 = normal; 6 = fixed defect; 7 = reversable defect
- target: 1 = menderita / sakit, 0 = tidak menderita / sehat
Membaca dan melihat struktur data
heart <- read.csv("heart.csv")
str(heart)
## 'data.frame': 303 obs. of 14 variables:
## $ age : int 63 37 41 56 57 57 56 44 52 57 ...
## $ sex : int 1 1 0 1 0 1 0 1 1 1 ...
## $ cp : int 3 2 1 1 0 0 1 1 2 2 ...
## $ trestbps: int 145 130 130 120 120 140 140 120 172 150 ...
## $ chol : int 233 250 204 236 354 192 294 263 199 168 ...
## $ fbs : int 1 0 0 0 0 0 0 0 1 0 ...
## $ restecg : int 0 1 0 1 1 1 0 1 1 1 ...
## $ thalach : int 150 187 172 178 163 148 153 173 162 174 ...
## $ exang : int 0 0 0 0 1 0 0 0 0 0 ...
## $ oldpeak : num 2.3 3.5 1.4 0.8 0.6 0.4 1.3 0 0.5 1.6 ...
## $ slope : int 0 0 2 2 2 1 1 2 2 2 ...
## $ ca : int 0 0 0 0 0 0 0 0 0 0 ...
## $ thal : int 1 2 2 2 2 1 2 3 3 2 ...
## $ target : int 1 1 1 1 1 1 1 1 1 1 ...
Melihat apakah ada data missing
anyNA(heart)
## [1] FALSE
Terdapat 2 jenis data dengan kategori yang tidak sesuai dengan informasi yang diberikan oleh sumber data, yaitu cp dan thal. Pada pemodelan ini, hal tersebut diabaikan (data dianggap benar).
Selain itu, terdapat beberapa data yang kelas datanya tidak sesuai dengan informasi yang diberikan oleh sumber data, sehingga harus diubah terlebih dahulu.
heart <- heart %>%
mutate(sex = factor(sex, levels = c(0,1), labels = c("female","male")),
fbs = factor(fbs, levels = c(0,1), labels = c("false","true")),
exang = factor(exang, levels = c(0,1), labels = c("no","yes")),
target = factor(target, levels = c(0,1),
labels = c("sehat","sakit")))
heart[,c("cp","restecg", "slope", "ca", "thal")] <- lapply(heart[,c("cp","restecg", "slope", "ca", "thal")], as.factor)
str(heart)
## 'data.frame': 303 obs. of 14 variables:
## $ age : int 63 37 41 56 57 57 56 44 52 57 ...
## $ sex : Factor w/ 2 levels "female","male": 2 2 1 2 1 2 1 2 2 2 ...
## $ cp : Factor w/ 4 levels "0","1","2","3": 4 3 2 2 1 1 2 2 3 3 ...
## $ trestbps: int 145 130 130 120 120 140 140 120 172 150 ...
## $ chol : int 233 250 204 236 354 192 294 263 199 168 ...
## $ fbs : Factor w/ 2 levels "false","true": 2 1 1 1 1 1 1 1 2 1 ...
## $ restecg : Factor w/ 3 levels "0","1","2": 1 2 1 2 2 2 1 2 2 2 ...
## $ thalach : int 150 187 172 178 163 148 153 173 162 174 ...
## $ exang : Factor w/ 2 levels "no","yes": 1 1 1 1 2 1 1 1 1 1 ...
## $ oldpeak : num 2.3 3.5 1.4 0.8 0.6 0.4 1.3 0 0.5 1.6 ...
## $ slope : Factor w/ 3 levels "0","1","2": 1 1 3 3 3 2 2 3 3 3 ...
## $ ca : Factor w/ 5 levels "0","1","2","3",..: 1 1 1 1 1 1 1 1 1 1 ...
## $ thal : Factor w/ 4 levels "0","1","2","3": 2 3 3 3 3 2 3 4 4 3 ...
## $ target : Factor w/ 2 levels "sehat","sakit": 2 2 2 2 2 2 2 2 2 2 ...
Membagi data menjadi 2 bagian, train dan test.
set.seed(205)
idx <- sample(nrow(heart), nrow(heart)*0.7)
heart.train <- heart[idx,]
heart.test <- heart[-idx,]
Membuat model dengan menggunakan metode stepwise backward direction.
model.full <- glm(target ~ ., heart.train, family = "binomial")
model.log <- step(model.full, direction = "backward")
## Start: AIC=167.07
## target ~ age + sex + cp + trestbps + chol + fbs + restecg + thalach +
## exang + oldpeak + slope + ca + thal
##
## Df Deviance AIC
## - restecg 2 122.45 164.45
## - fbs 1 121.38 165.38
## - age 1 121.84 165.84
## - chol 1 122.08 166.08
## - slope 2 124.38 166.38
## - exang 1 122.93 166.93
## <none> 121.07 167.07
## - trestbps 1 123.24 167.24
## - thalach 1 123.44 167.44
## - thal 3 130.76 170.76
## - oldpeak 1 127.25 171.25
## - sex 1 129.76 173.76
## - cp 3 136.45 176.45
## - ca 4 148.79 186.79
##
## Step: AIC=164.45
## target ~ age + sex + cp + trestbps + chol + fbs + thalach + exang +
## oldpeak + slope + ca + thal
##
## Df Deviance AIC
## - fbs 1 122.82 162.82
## - age 1 123.06 163.06
## - chol 1 124.30 164.30
## - thalach 1 124.42 164.42
## <none> 122.45 164.45
## - exang 1 124.47 164.47
## - trestbps 1 124.76 164.76
## - slope 2 126.94 164.94
## - thal 3 131.26 167.26
## - oldpeak 1 128.32 168.32
## - sex 1 131.71 171.71
## - cp 3 137.59 173.59
## - ca 4 152.50 186.50
##
## Step: AIC=162.82
## target ~ age + sex + cp + trestbps + chol + thalach + exang +
## oldpeak + slope + ca + thal
##
## Df Deviance AIC
## - age 1 123.40 161.40
## - chol 1 124.57 162.57
## - exang 1 124.67 162.68
## - thalach 1 124.80 162.80
## <none> 122.82 162.82
## - trestbps 1 124.90 162.90
## - slope 2 127.10 163.10
## - thal 3 131.94 165.94
## - oldpeak 1 129.23 167.23
## - sex 1 131.84 169.84
## - cp 3 139.42 173.42
## - ca 4 152.85 184.85
##
## Step: AIC=161.4
## target ~ sex + cp + trestbps + chol + thalach + exang + oldpeak +
## slope + ca + thal
##
## Df Deviance AIC
## - thalach 1 124.87 160.87
## - chol 1 124.94 160.94
## - trestbps 1 125.16 161.16
## - slope 2 127.31 161.31
## <none> 123.40 161.40
## - exang 1 125.43 161.43
## - thal 3 132.62 164.62
## - oldpeak 1 130.27 166.27
## - sex 1 132.90 168.90
## - cp 3 140.97 172.97
## - ca 4 154.19 184.19
##
## Step: AIC=160.87
## target ~ sex + cp + trestbps + chol + exang + oldpeak + slope +
## ca + thal
##
## Df Deviance AIC
## - trestbps 1 126.20 160.20
## - chol 1 126.33 160.33
## <none> 124.87 160.87
## - exang 1 127.45 161.45
## - slope 2 131.03 163.03
## - thal 3 133.75 163.75
## - oldpeak 1 132.48 166.48
## - sex 1 133.75 167.75
## - cp 3 145.50 175.50
## - ca 4 157.23 185.23
##
## Step: AIC=160.2
## target ~ sex + cp + chol + exang + oldpeak + slope + ca + thal
##
## Df Deviance AIC
## - chol 1 127.77 159.77
## <none> 126.20 160.20
## - exang 1 128.76 160.76
## - slope 2 131.82 161.82
## - thal 3 134.99 162.99
## - sex 1 134.31 166.31
## - oldpeak 1 135.43 167.43
## - cp 3 147.04 175.04
## - ca 4 157.88 183.88
##
## Step: AIC=159.77
## target ~ sex + cp + exang + oldpeak + slope + ca + thal
##
## Df Deviance AIC
## <none> 127.77 159.77
## - exang 1 130.35 160.35
## - slope 2 133.70 161.70
## - thal 3 137.35 163.35
## - sex 1 134.50 164.50
## - oldpeak 1 137.66 167.66
## - cp 3 148.62 174.62
## - ca 4 159.57 183.57
summary(model.log)
##
## Call:
## glm(formula = target ~ sex + cp + exang + oldpeak + slope + ca +
## thal, family = "binomial", data = heart.train)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -3.04167 -0.28128 0.09517 0.45022 2.85204
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 0.5922 4.4221 0.134 0.893461
## sexmale -1.5436 0.6235 -2.476 0.013292 *
## cp1 0.4446 0.6638 0.670 0.502951
## cp2 2.3510 0.6214 3.783 0.000155 ***
## cp3 2.3831 0.8591 2.774 0.005540 **
## exangyes -0.8752 0.5439 -1.609 0.107567
## oldpeak -0.9181 0.3168 -2.898 0.003755 **
## slope1 -0.7896 0.9963 -0.793 0.428060
## slope2 0.5911 1.0972 0.539 0.590070
## ca1 -2.4078 0.6059 -3.974 0.0000706 ***
## ca2 -3.1939 0.8998 -3.550 0.000386 ***
## ca3 -1.5923 1.1540 -1.380 0.167622
## ca4 15.4841 1078.4219 0.014 0.988544
## thal1 2.8170 4.3746 0.644 0.519621
## thal2 2.6253 4.2890 0.612 0.540464
## thal3 1.1579 4.2926 0.270 0.787362
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 292.69 on 211 degrees of freedom
## Residual deviance: 127.77 on 196 degrees of freedom
## AIC: 159.77
##
## Number of Fisher Scoring iterations: 15
Dari summary model di atas, dapat dilihat bahwa variable cp (tipe nyeri dada), ca (jumlah pembuluh darah utama (0-3) diwarnai dengan fluoroskopi), oldpeak (depresi ST disebabkan oleh olahraga relatif terhadap istirahat), dan sex (jenis kelamin) memiliki pengaruh yang signifikan untuk memprediksi variable target.
Berikut ini Odds Ratio dari masing - masing variable prediktor:
as.data.frame(exp(model.log$coefficients))
## exp(model.log$coefficients)
## (Intercept) 1.80802781
## sexmale 0.21360738
## cp1 1.55993084
## cp2 10.49555898
## cp3 10.83827319
## exangyes 0.41678014
## oldpeak 0.39927125
## slope1 0.45402420
## slope2 1.80598405
## ca1 0.09000907
## ca2 0.04101364
## ca3 0.20345196
## ca4 5304592.69474923
## thal1 16.72586005
## thal2 13.80939222
## thal3 3.18315147
Interpretasi dari Odds Ratio di atas adalah:
Misalnya untuk jenis kelamin pria memberikan kemungkinan 0.22 kali lebih mungkin daripada wanita untuk sakit dengan syarat variable yang lainnya tetap.
Berikut ini adalah prediksi dari model Logistic Regression untuk variable target pada data heart.test.
Dengan type response, maka yang akan dikeluarkan adalah nilai peluang dari variable target.
pred.log <- predict(model.log, heart.test, type = "response")
Untuk melihat kemampuan model dalam memprediksi variable target, akan digunakan beberapa ambang batas (threshold), yaitu 0.4; 0.45; 0.5; 0.55; 0.6.
Menggunakan ambang batas (threshold) 0.4
heart.test$pred.log.label <- as.factor(ifelse(pred.log >= 0.4, "sakit", "sehat"))
confusionMatrix(heart.test$pred.log.label, heart.test$target, positive = "sakit")
## Warning in confusionMatrix.default(heart.test$pred.log.label, heart.test
## $target, : Levels are not in the same order for reference and data.
## Refactoring data to match.
## Confusion Matrix and Statistics
##
## Reference
## Prediction sehat sakit
## sehat 27 3
## sakit 13 48
##
## Accuracy : 0.8242
## 95% CI : (0.7302, 0.896)
## No Information Rate : 0.5604
## P-Value [Acc > NIR] : 0.0000000945
##
## Kappa : 0.6332
##
## Mcnemar's Test P-Value : 0.02445
##
## Sensitivity : 0.9412
## Specificity : 0.6750
## Pos Pred Value : 0.7869
## Neg Pred Value : 0.9000
## Prevalence : 0.5604
## Detection Rate : 0.5275
## Detection Prevalence : 0.6703
## Balanced Accuracy : 0.8081
##
## 'Positive' Class : sakit
##
num.pos <- nrow(heart.test %>%
filter(pred.log.label == "sakit" & target == "sakit"))
den.rec <- nrow(heart.test %>%
filter(target == "sakit"))
den.prec <- nrow(heart.test %>%
filter(pred.log.label == "sakit"))
num.neg <- nrow(heart.test %>%
filter(pred.log.label == "sehat" & target == "sehat"))
rec <- num.pos/den.rec
prec <- num.pos/den.prec
acc <- (num.pos + num.neg)/nrow(heart.test)
matrix.0.4 <- rbind(c("recall", "precission", "accuracy"), c(rec, prec ,acc))
Menggunakan ambang batas (threshold) 0.45
heart.test$pred.log.label <- as.factor(ifelse(pred.log >= 0.45, "sakit", "sehat"))
confusionMatrix(heart.test$pred.log.label, heart.test$target, positive = "sakit")
## Warning in confusionMatrix.default(heart.test$pred.log.label, heart.test
## $target, : Levels are not in the same order for reference and data.
## Refactoring data to match.
## Confusion Matrix and Statistics
##
## Reference
## Prediction sehat sakit
## sehat 28 4
## sakit 12 47
##
## Accuracy : 0.8242
## 95% CI : (0.7302, 0.896)
## No Information Rate : 0.5604
## P-Value [Acc > NIR] : 0.0000000945
##
## Kappa : 0.6353
##
## Mcnemar's Test P-Value : 0.08012
##
## Sensitivity : 0.9216
## Specificity : 0.7000
## Pos Pred Value : 0.7966
## Neg Pred Value : 0.8750
## Prevalence : 0.5604
## Detection Rate : 0.5165
## Detection Prevalence : 0.6484
## Balanced Accuracy : 0.8108
##
## 'Positive' Class : sakit
##
num.pos <- nrow(heart.test %>%
filter(pred.log.label == "sakit" & target == "sakit"))
den.rec <- nrow(heart.test %>%
filter(target == "sakit"))
den.prec <- nrow(heart.test %>%
filter(pred.log.label == "sakit"))
num.neg <- nrow(heart.test %>%
filter(pred.log.label == "sehat" & target == "sehat"))
rec <- num.pos/den.rec
prec <- num.pos/den.prec
acc <- (num.pos + num.neg)/nrow(heart.test)
matrix.0.45 <- rbind(c("recall", "precission", "accuracy"), c(rec, prec ,acc))
Menggunakan ambang batas (threshold) 0.5
heart.test$pred.log.label <- as.factor(ifelse(pred.log >= 0.5, "sakit", "sehat"))
confusionMatrix(heart.test$pred.log.label, heart.test$target, positive = "sakit")
## Warning in confusionMatrix.default(heart.test$pred.log.label, heart.test
## $target, : Levels are not in the same order for reference and data.
## Refactoring data to match.
## Confusion Matrix and Statistics
##
## Reference
## Prediction sehat sakit
## sehat 31 5
## sakit 9 46
##
## Accuracy : 0.8462
## 95% CI : (0.7554, 0.9133)
## No Information Rate : 0.5604
## P-Value [Acc > NIR] : 0.000000005991
##
## Kappa : 0.6843
##
## Mcnemar's Test P-Value : 0.4227
##
## Sensitivity : 0.9020
## Specificity : 0.7750
## Pos Pred Value : 0.8364
## Neg Pred Value : 0.8611
## Prevalence : 0.5604
## Detection Rate : 0.5055
## Detection Prevalence : 0.6044
## Balanced Accuracy : 0.8385
##
## 'Positive' Class : sakit
##
num.pos <- nrow(heart.test %>%
filter(pred.log.label == "sakit" & target == "sakit"))
den.rec <- nrow(heart.test %>%
filter(target == "sakit"))
den.prec <- nrow(heart.test %>%
filter(pred.log.label == "sakit"))
num.neg <- nrow(heart.test %>%
filter(pred.log.label == "sehat" & target == "sehat"))
rec <- num.pos/den.rec
prec <- num.pos/den.prec
acc <- (num.pos + num.neg)/nrow(heart.test)
matrix.0.5 <- rbind(c("recall", "precission", "accuracy"), c(rec, prec ,acc))
Menggunakan ambang batas (threshold) 0.55
heart.test$pred.log.label <- as.factor(ifelse(pred.log >= 0.55, "sakit", "sehat"))
confusionMatrix(heart.test$pred.log.label, heart.test$target, positive = "sakit")
## Warning in confusionMatrix.default(heart.test$pred.log.label, heart.test
## $target, : Levels are not in the same order for reference and data.
## Refactoring data to match.
## Confusion Matrix and Statistics
##
## Reference
## Prediction sehat sakit
## sehat 32 6
## sakit 8 45
##
## Accuracy : 0.8462
## 95% CI : (0.7554, 0.9133)
## No Information Rate : 0.5604
## P-Value [Acc > NIR] : 0.000000005991
##
## Kappa : 0.6861
##
## Mcnemar's Test P-Value : 0.7893
##
## Sensitivity : 0.8824
## Specificity : 0.8000
## Pos Pred Value : 0.8491
## Neg Pred Value : 0.8421
## Prevalence : 0.5604
## Detection Rate : 0.4945
## Detection Prevalence : 0.5824
## Balanced Accuracy : 0.8412
##
## 'Positive' Class : sakit
##
num.pos <- nrow(heart.test %>%
filter(pred.log.label == "sakit" & target == "sakit"))
den.rec <- nrow(heart.test %>%
filter(target == "sakit"))
den.prec <- nrow(heart.test %>%
filter(pred.log.label == "sakit"))
num.neg <- nrow(heart.test %>%
filter(pred.log.label == "sehat" & target == "sehat"))
rec <- num.pos/den.rec
prec <- num.pos/den.prec
acc <- (num.pos + num.neg)/nrow(heart.test)
matrix.0.55 <- rbind(c("recall", "precission", "accuracy"), c(rec, prec ,acc))
Menggunakan ambang batas (threshold) 0.6
heart.test$pred.log.label <- as.factor(ifelse(pred.log >= 0.6, "sakit", "sehat"))
confusionMatrix(heart.test$pred.log.label, heart.test$target, positive = "sakit")
## Warning in confusionMatrix.default(heart.test$pred.log.label, heart.test
## $target, : Levels are not in the same order for reference and data.
## Refactoring data to match.
## Confusion Matrix and Statistics
##
## Reference
## Prediction sehat sakit
## sehat 33 7
## sakit 7 44
##
## Accuracy : 0.8462
## 95% CI : (0.7554, 0.9133)
## No Information Rate : 0.5604
## P-Value [Acc > NIR] : 0.000000005991
##
## Kappa : 0.6877
##
## Mcnemar's Test P-Value : 1
##
## Sensitivity : 0.8627
## Specificity : 0.8250
## Pos Pred Value : 0.8627
## Neg Pred Value : 0.8250
## Prevalence : 0.5604
## Detection Rate : 0.4835
## Detection Prevalence : 0.5604
## Balanced Accuracy : 0.8439
##
## 'Positive' Class : sakit
##
num.pos <- nrow(heart.test %>%
filter(pred.log.label == "sakit" & target == "sakit"))
den.rec <- nrow(heart.test %>%
filter(target == "sakit"))
den.prec <- nrow(heart.test %>%
filter(pred.log.label == "sakit"))
num.neg <- nrow(heart.test %>%
filter(pred.log.label == "sehat" & target == "sehat"))
rec <- num.pos/den.rec
prec <- num.pos/den.prec
acc <- (num.pos + num.neg)/nrow(heart.test)
matrix.0.6 <- rbind(c("recall", "precission", "accuracy"), c(rec, prec ,acc))
Berikut adalah summary precission / pos pred value, recall, accuracy untuk masing - masing threshold:
matrix.0.4
## [,1] [,2] [,3]
## [1,] "recall" "precission" "accuracy"
## [2,] "0.941176470588235" "0.786885245901639" "0.824175824175824"
matrix.0.45
## [,1] [,2] [,3]
## [1,] "recall" "precission" "accuracy"
## [2,] "0.92156862745098" "0.796610169491525" "0.824175824175824"
matrix.0.5
## [,1] [,2] [,3]
## [1,] "recall" "precission" "accuracy"
## [2,] "0.901960784313726" "0.836363636363636" "0.846153846153846"
matrix.0.55
## [,1] [,2] [,3]
## [1,] "recall" "precission" "accuracy"
## [2,] "0.882352941176471" "0.849056603773585" "0.846153846153846"
matrix.0.6
## [,1] [,2] [,3]
## [1,] "recall" "precission" "accuracy"
## [2,] "0.862745098039216" "0.862745098039216" "0.846153846153846"
Dari summary di atas, maka nilai recall akan semakin rendah seiring bertambahnya nilai threshold, sebaliknya nilai precission akan semakin tinggi.
Jika hanya mempertimbangkan recall, maka nilai threshold yang dipilih adalah 0.4, karena memberikan recall = 0.94.
Artinya error (adanya terprediksi “sehat” untuk yang “sakit”) hanya 1 - recall = 0.06.
Jika mempertimbangkan recall, precission dan accuracy secara bersamaan, maka nilai threshold yang dipilih adalah 0.5, dimana recall = 0.90, precission = 0.84, dan accuracy = 0.85.
Model k-Nearest Neighbor ini adalah mengelompokkan variable target berdasarkan jarak yang dihasilkan dari masing - masing prediktor, sehingga variable prediktor yang digunakan adalah kelas numerik.
Selanjutnya, agar jarak yang dihasilkan sebanding, maka data ditansformasi menggunakan z-score.
Membagi data menjadi 2 bagian, train dan test.
set.seed(205)
idx <- sample(nrow(heart), nrow(heart)*0.7)
knn.train <- heart[idx,]
knn.test <- heart[-idx,]
Merubah data train dan test menjadi z-score.
knn.train.z <- as.data.frame(lapply(knn.train[,c(4,5,8,10)],scale))
knn.test.z <- as.data.frame(lapply(knn.test[,c(4,5,8,10)],scale))
Nilai k sebagai acuan awal adalah:
sqrt(nrow(knn.test))
## [1] 9.539392
Untuk melihat kemampuan model dalam memprediksi variable target, akan digunakan beberapa nilai k, yaitu 7; 9; 11; 13; 15.
Menggunakan nilai k = 7
knn.pred <- knn (train = knn.train.z,
test = knn.test.z,
cl = knn.train$target,
k = 7)
knn.test$knn.pred <- knn.pred
confusionMatrix(knn.test$knn.pred, knn.test$target, positive = "sakit")
## Confusion Matrix and Statistics
##
## Reference
## Prediction sehat sakit
## sehat 24 10
## sakit 16 41
##
## Accuracy : 0.7143
## 95% CI : (0.61, 0.8041)
## No Information Rate : 0.5604
## P-Value [Acc > NIR] : 0.001845
##
## Kappa : 0.4106
##
## Mcnemar's Test P-Value : 0.326800
##
## Sensitivity : 0.8039
## Specificity : 0.6000
## Pos Pred Value : 0.7193
## Neg Pred Value : 0.7059
## Prevalence : 0.5604
## Detection Rate : 0.4505
## Detection Prevalence : 0.6264
## Balanced Accuracy : 0.7020
##
## 'Positive' Class : sakit
##
num.pos <- nrow(knn.test %>%
filter(knn.pred == "sakit" & target == "sakit"))
den.rec <- nrow(knn.test %>%
filter(target == "sakit"))
den.prec <- nrow(knn.test %>%
filter(knn.pred == "sakit"))
num.neg <- nrow(knn.test %>%
filter(knn.pred == "sehat" & target == "sehat"))
rec <- num.pos/den.rec
prec <- num.pos/den.prec
acc <- (num.pos + num.neg)/nrow(knn.test)
matrix.7 <- rbind(c("recall", "precission", "accuracy"), c(rec, prec, acc))
Menggunakan nilai k = 9
knn.pred <- knn (train = knn.train.z,
test = knn.test.z,
cl = knn.train$target,
k = 9)
knn.test$knn.pred <- knn.pred
confusionMatrix(knn.test$knn.pred, knn.test$target, positive = "sakit")
## Confusion Matrix and Statistics
##
## Reference
## Prediction sehat sakit
## sehat 25 10
## sakit 15 41
##
## Accuracy : 0.7253
## 95% CI : (0.6217, 0.8137)
## No Information Rate : 0.5604
## P-Value [Acc > NIR] : 0.0008856
##
## Kappa : 0.4348
##
## Mcnemar's Test P-Value : 0.4237108
##
## Sensitivity : 0.8039
## Specificity : 0.6250
## Pos Pred Value : 0.7321
## Neg Pred Value : 0.7143
## Prevalence : 0.5604
## Detection Rate : 0.4505
## Detection Prevalence : 0.6154
## Balanced Accuracy : 0.7145
##
## 'Positive' Class : sakit
##
num.pos <- nrow(knn.test %>%
filter(knn.pred == "sakit" & target == "sakit"))
den.rec <- nrow(knn.test %>%
filter(target == "sakit"))
den.prec <- nrow(knn.test %>%
filter(knn.pred == "sakit"))
num.neg <- nrow(knn.test %>%
filter(knn.pred == "sehat" & target == "sehat"))
rec <- num.pos/den.rec
prec <- num.pos/den.prec
acc <- (num.pos + num.neg)/nrow(knn.test)
matrix.9 <- rbind(c("recall", "precission", "accuracy"), c(rec, prec, acc))
Menggunakan nilai k = 11
knn.pred <- knn (train = knn.train.z,
test = knn.test.z,
cl = knn.train$target,
k = 11)
knn.test$knn.pred <- knn.pred
confusionMatrix(knn.test$knn.pred, knn.test$target, positive = "sakit")
## Confusion Matrix and Statistics
##
## Reference
## Prediction sehat sakit
## sehat 23 8
## sakit 17 43
##
## Accuracy : 0.7253
## 95% CI : (0.6217, 0.8137)
## No Information Rate : 0.5604
## P-Value [Acc > NIR] : 0.0008856
##
## Kappa : 0.4285
##
## Mcnemar's Test P-Value : 0.1095986
##
## Sensitivity : 0.8431
## Specificity : 0.5750
## Pos Pred Value : 0.7167
## Neg Pred Value : 0.7419
## Prevalence : 0.5604
## Detection Rate : 0.4725
## Detection Prevalence : 0.6593
## Balanced Accuracy : 0.7091
##
## 'Positive' Class : sakit
##
num.pos <- nrow(knn.test %>%
filter(knn.pred == "sakit" & target == "sakit"))
den.rec <- nrow(knn.test %>%
filter(target == "sakit"))
den.prec <- nrow(knn.test %>%
filter(knn.pred == "sakit"))
num.neg <- nrow(knn.test %>%
filter(knn.pred == "sehat" & target == "sehat"))
rec <- num.pos/den.rec
prec <- num.pos/den.prec
acc <- (num.pos + num.neg)/nrow(knn.test)
matrix.11 <- rbind(c("recall", "precission", "accuracy"), c(rec, prec, acc))
Menggunakan nilai k = 13
knn.pred <- knn (train = knn.train.z,
test = knn.test.z,
cl = knn.train$target,
k = 13)
knn.test$knn.pred <- knn.pred
confusionMatrix(knn.test$knn.pred, knn.test$target, positive = "sakit")
## Confusion Matrix and Statistics
##
## Reference
## Prediction sehat sakit
## sehat 22 10
## sakit 18 41
##
## Accuracy : 0.6923
## 95% CI : (0.5868, 0.7849)
## No Information Rate : 0.5604
## P-Value [Acc > NIR] : 0.006902
##
## Kappa : 0.3617
##
## Mcnemar's Test P-Value : 0.185877
##
## Sensitivity : 0.8039
## Specificity : 0.5500
## Pos Pred Value : 0.6949
## Neg Pred Value : 0.6875
## Prevalence : 0.5604
## Detection Rate : 0.4505
## Detection Prevalence : 0.6484
## Balanced Accuracy : 0.6770
##
## 'Positive' Class : sakit
##
num.pos <- nrow(knn.test %>%
filter(knn.pred == "sakit" & target == "sakit"))
den.rec <- nrow(knn.test %>%
filter(target == "sakit"))
den.prec <- nrow(knn.test %>%
filter(knn.pred == "sakit"))
num.neg <- nrow(knn.test %>%
filter(knn.pred == "sehat" & target == "sehat"))
rec <- num.pos/den.rec
prec <- num.pos/den.prec
acc <- (num.pos + num.neg)/nrow(knn.test)
matrix.13 <- rbind(c("recall", "precission", "accuracy"), c(rec, prec, acc))
Menggunakan nilai k = 15
knn.pred <- knn (train = knn.train.z,
test = knn.test.z,
cl = knn.train$target,
k = 15)
knn.test$knn.pred <- knn.pred
confusionMatrix(knn.test$knn.pred, knn.test$target, positive = "sakit")
## Confusion Matrix and Statistics
##
## Reference
## Prediction sehat sakit
## sehat 21 10
## sakit 19 41
##
## Accuracy : 0.6813
## 95% CI : (0.5753, 0.7751)
## No Information Rate : 0.5604
## P-Value [Acc > NIR] : 0.01243
##
## Kappa : 0.3371
##
## Mcnemar's Test P-Value : 0.13739
##
## Sensitivity : 0.8039
## Specificity : 0.5250
## Pos Pred Value : 0.6833
## Neg Pred Value : 0.6774
## Prevalence : 0.5604
## Detection Rate : 0.4505
## Detection Prevalence : 0.6593
## Balanced Accuracy : 0.6645
##
## 'Positive' Class : sakit
##
num.pos <- nrow(knn.test %>%
filter(knn.pred == "sakit" & target == "sakit"))
den.rec <- nrow(knn.test %>%
filter(target == "sakit"))
den.prec <- nrow(knn.test %>%
filter(knn.pred == "sakit"))
num.neg <- nrow(knn.test %>%
filter(knn.pred == "sehat" & target == "sehat"))
rec <- num.pos/den.rec
prec <- num.pos/den.prec
acc <- (num.pos + num.neg)/nrow(knn.test)
matrix.15 <- rbind(c("recall", "precission", "accuracy"), c(rec, prec, acc))
Berikut adalah summary precission / pos pred value, recall, accuracy untuk masing - masing k:
matrix.7
## [,1] [,2] [,3]
## [1,] "recall" "precission" "accuracy"
## [2,] "0.803921568627451" "0.719298245614035" "0.714285714285714"
matrix.9
## [,1] [,2] [,3]
## [1,] "recall" "precission" "accuracy"
## [2,] "0.803921568627451" "0.732142857142857" "0.725274725274725"
matrix.11
## [,1] [,2] [,3]
## [1,] "recall" "precission" "accuracy"
## [2,] "0.843137254901961" "0.716666666666667" "0.725274725274725"
matrix.13
## [,1] [,2] [,3]
## [1,] "recall" "precission" "accuracy"
## [2,] "0.803921568627451" "0.694915254237288" "0.692307692307692"
matrix.15
## [,1] [,2] [,3]
## [1,] "recall" "precission" "accuracy"
## [2,] "0.803921568627451" "0.683333333333333" "0.681318681318681"
Dari summary di atas, nilai recall semakin tinggi seiring bertambahnya nilai k dari 7 sampai 11, tetapi precission semakin tinggi hanya untuk nilai k dari 7 sampai 9.
Nilai k yang terbaik adalah 11, karena memberikan recall = 0.84.
Artinya error (adanya terprediksi “sehat” untuk yang “sakit”) cukup kecil yaitu 1 - recall = 0.16.
Begitu juga dengan precission, dan accuracy yang baik, yaitu precission = 0.72, dan accuracy = 0.725.
Berikut ini kesimpulan yang dapat ditarik dari hasil pemodelan yang telah dilakukan:
Pada model Logistic Regression, variable yang berpengaruh cukup signifikan untuk memprediksi variable target adalah cp (tipe nyeri dada), ca (jumlah pembuluh darah utama (0-3) diwarnai dengan fluoroskopi), oldpeak (depresi ST disebabkan oleh olahraga relatif terhadap istirahat), dan sex (jenis kelamin).
Pada model Logistic Regression, nilai recall akan semakin rendah seiring bertambahnya nilai threshold (0.4; 0.45; 0.5; 0.55; 0.6), sebaliknya nilai precission akan semakin tinggi.
Pada model Logistic Regression, jika hanya mempertimbangkan recall, maka nilai threshold yang dipilih adalah 0.4, karena memberikan recall = 0.94.
Artinya error (adanya terprediksi “sehat” untuk yang “sakit”) hanya 1 - recall = 0.06.
Pada model Logistic Regression, jika mempertimbangkan recall, precission, dan accuracy secara bersamaan, maka nilai threshold yang dipilih adalah 0.5, dimana recall = 0.90, precission = 0.84, dan accuracy = 0.85.
Pada model k-Nearest Neighbor, nilai recall semakin tinggi seiring bertambahnya nilai k dari 7 sampai 11, tetapi precission semakin tinggi hanya untuk nilai k dari 7 sampai 9.
Pada model k-Nearest Neighbor, nilai k yang terbaik adalah 11, karena memberikan recall = 0.84. Artinya error (adanya terprediksi “sehat” untuk yang “sakit”) cukup kecil yaitu 1 - recall = 0.16.
Begitu juga dengan precission, dan accuracy yang baik, yaitu precission = 0.72, dan accuracy = 0.725.
Pada pemodelan ini, model Logistic Regression cukup baik memprediksi variable target dibandingkan model k-Nearest Neighbor, baik dari segi hanya mempertimbangkan recall (0.94 vs 0.84) ataupun mempertimbangkan recall, precission, dan accuracy (0.90 vs 0.84; 0.84 vs 0.72; 0.85 vs 0.725) secara bersamaan.