library(dplyr)
library(gtools)
library(gmodels)
library(ggplot2)
library(class)
library(tidyr)
Load Data
Mydata<-read.csv("home.csv")
str(Mydata)
## 'data.frame': 295 obs. of 10 variables:
## $ age : int 63 37 41 56 57 57 56 44 52 57 ...
## $ sex : int 1 1 0 1 0 1 1 1 1 1 ...
## $ quant : int 5 4 3 3 2 2 3 3 4 4 ...
## $ usia : int 45 30 30 20 20 40 40 20 72 50 ...
## $ resid : int 1 0 0 0 0 0 0 0 1 0 ...
## $ kwn : int 2 3 2 3 1 1 2 1 1 1 ...
## $ pov : int 0 0 0 0 1 0 0 0 0 0 ...
## $ educ : int 1 1 3 3 3 2 2 3 3 3 ...
## $ jart : int 1 2 2 2 2 1 2 3 3 2 ...
## $ target: int 1 1 1 1 1 1 1 1 1 1 ...
Tipe data dari variabel-variabel yang digunakan belum seragam. Oleh karena itu yang perlu dilakukan adalah melakukan penyesuaian tipe data.
library(dplyr)
Mydata <- Mydata %>%
mutate_if(is.integer, as.factor) %>% #Mengubah semua kolom integer menjadi faktor.
mutate(sex = factor(sex, levels = c(0,1), labels = c("Female", "Male")),
resid =factor(resid, levels = c(0,1), labels = c("Desa", "Kota")),
pov = factor(pov, levels = c(0,1), labels = c("No", "Yes")),
target = factor(target, levels = c(0,1),
labels = c("Punya", "Tidak Punya")))
glimpse(Mydata)
## Rows: 295
## Columns: 10
## $ age <fct> 63, 37, 41, 56, 57, 57, 56, 44, 52, 57, 54, 48, 49, 64, 58, 50,…
## $ sex <fct> Male, Male, Female, Male, Female, Male, Male, Male, Male, Male,…
## $ quant <fct> 5, 4, 3, 3, 2, 2, 3, 3, 4, 4, 2, 4, 3, 5, 5, 4, 4, 5, 2, 5, 2, …
## $ usia <fct> 45, 30, 30, 20, 20, 40, 40, 20, 72, 50, 40, 30, 30, 20, 50, 20,…
## $ resid <fct> Kota, Desa, Desa, Desa, Desa, Desa, Desa, Desa, Kota, Desa, Des…
## $ kwn <fct> 2, 3, 2, 3, 1, 1, 2, 1, 1, 1, 2, 3, 3, 2, 2, 2, 2, 2, 2, 3, 2, …
## $ pov <fct> No, No, No, No, Yes, No, No, No, No, No, No, No, No, Yes, No, N…
## $ educ <fct> 1, 1, 3, 3, 3, 2, 2, 3, 3, 3, 4, 4, 3, 2, 3, 2, 3, 1, 3, 3, 2, …
## $ jart <fct> 1, 2, 2, 2, 2, 1, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, …
## $ target <fct> Tidak Punya, Tidak Punya, Tidak Punya, Tidak Punya, Tidak Punya…
pre-processing
Melakukan pengecekan terhadap missing value.
colSums(is.na(Mydata))
## age sex quant usia resid kwn pov educ jart target
## 0 0 0 0 0 0 0 0 0 0
Menghitung proporsi dan jumlah setiap kategori dalam variabel target, untuk memastikan distribusi data seimbang. Jika adanya permasalahan data yang tidak seimbang, maka perlu dilakukan handling imbalance data.
prop.table(table(Mydata$target))
##
## Punya Tidak Punya
## 0.4677966 0.5322034
table(Mydata$target)
##
## Punya Tidak Punya
## 138 157
Jika dilihat dari proporsi kedua kategori, sudah cukup seimbang sehingga tidak terlalu membutuhkan pre-processing tambahan untuk menyeimbangkan proporsi antar dua kelas target variabel.
Membagi data menjadi 70% untuk pelatihan (train) dan 30% untuk pengujian (test), dengan seed untuk memastikan hasil yang dapat direproduksi.
set.seed(303)
intrain <- sample(nrow(Mydata), nrow(Mydata)*0.7)
Mydata_train <- Mydata[intrain,]
Mydata_test <- Mydata[-intrain,]
Mydata$target %>%
levels()
## [1] "Punya" "Tidak Punya"
library(caret)
set.seed(100) # mengatur seed tertentu untuk hasil yang dapat direproduksi
trainIndex <- createDataPartition(Mydata$target, p = 0.70, list = FALSE, times = 1)
Membuat data latih dan data uji berdasarkan indeks yang dihasilkan.
data.train <- Mydata[trainIndex, ]
data.test <- Mydata[-trainIndex, ]
Melihat komposisi setiap kelas pada data train dan test.
cbind("train" = table(data.train$target), "test" = table(data.test$target))
## train test
## Punya 97 41
## Tidak Punya 110 47
model <- glm(formula = target~sex+quant+resid+kwn+pov+educ+jart, family = "binomial", data = Mydata_train)
summary(model)
##
## Call:
## glm(formula = target ~ sex + quant + resid + kwn + pov + educ +
## jart, family = "binomial", data = Mydata_train)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 18.8611 1577.7128 0.012 0.9905
## sexMale 0.1349 0.5158 0.262 0.7936
## quant2 -1.9242 1.0896 -1.766 0.0774 .
## quant3 -1.2604 1.1517 -1.094 0.2738
## quant4 -0.9962 1.1505 -0.866 0.3866
## quant5 -1.0332 1.1795 -0.876 0.3811
## residKota -0.1927 0.6206 -0.311 0.7562
## kwn2 -17.9785 1577.7118 -0.011 0.9909
## kwn3 -17.4745 1577.7118 -0.011 0.9912
## kwn4 -18.1310 1577.7127 -0.011 0.9908
## povYes -1.9091 0.4580 -4.168 3.07e-05 ***
## educ2 -0.1726 0.8157 -0.212 0.8324
## educ3 0.7101 0.8247 0.861 0.3892
## educ4 0.2062 1.0832 0.190 0.8491
## jart2 1.5583 0.9679 1.610 0.1074
## jart3 -0.3249 0.9614 -0.338 0.7354
## jart4 -0.3268 1.7835 -0.183 0.8546
## jart5 -17.0151 3178.0771 -0.005 0.9957
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 285.56 on 205 degrees of freedom
## Residual deviance: 164.17 on 188 degrees of freedom
## AIC: 200.17
##
## Number of Fisher Scoring iterations: 17
Model perlu dilakukan fitting karena banyak variabel prediktor yang tidak signifikan. Metode stepwise regression digunakan untuk memilih model terbaik berdasarkan AIC (Akaike Information Criterion).
library(MASS)
model2 <- stepAIC(model, direction = "backward")
## Start: AIC=200.17
## target ~ sex + quant + resid + kwn + pov + educ + jart
##
## Df Deviance AIC
## - quant 4 170.22 198.22
## - sex 1 164.24 198.24
## - resid 1 164.26 198.26
## - educ 3 168.48 198.48
## <none> 164.17 200.17
## - kwn 3 174.69 204.69
## - jart 4 185.40 213.40
## - pov 1 183.40 217.40
##
## Step: AIC=198.22
## target ~ sex + resid + kwn + pov + educ + jart
##
## Df Deviance AIC
## - resid 1 170.22 196.22
## - sex 1 170.42 196.42
## - educ 3 175.73 197.73
## <none> 170.22 198.22
## - kwn 3 180.15 202.15
## - jart 4 197.62 217.62
## - pov 1 194.88 220.88
##
## Step: AIC=196.22
## target ~ sex + kwn + pov + educ + jart
##
## Df Deviance AIC
## - sex 1 170.43 194.43
## - educ 3 175.76 195.76
## <none> 170.22 196.22
## - kwn 3 180.32 200.32
## - jart 4 197.66 215.66
## - pov 1 195.11 219.11
##
## Step: AIC=194.43
## target ~ kwn + pov + educ + jart
##
## Df Deviance AIC
## - educ 3 176.08 194.08
## <none> 170.43 194.43
## - kwn 3 180.49 198.49
## - jart 4 199.66 215.66
## - pov 1 195.40 217.40
##
## Step: AIC=194.08
## target ~ kwn + pov + jart
##
## Df Deviance AIC
## <none> 176.08 194.08
## - kwn 3 189.43 201.43
## - jart 4 211.11 221.11
## - pov 1 205.28 221.28
summary(model2)
##
## Call:
## glm(formula = target ~ kwn + pov + jart, family = "binomial",
## data = Mydata_train)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 16.7501 980.5391 0.017 0.9864
## kwn2 -17.1803 980.5387 -0.018 0.9860
## kwn3 -16.6083 980.5387 -0.017 0.9865
## kwn4 -17.6860 980.5399 -0.018 0.9856
## povYes -2.0828 0.4095 -5.087 3.64e-07 ***
## jart2 1.8746 0.9094 2.061 0.0393 *
## jart3 -0.1697 0.9175 -0.185 0.8533
## jart4 0.2424 1.5872 0.153 0.8786
## jart5 -16.4997 1842.0565 -0.009 0.9929
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 285.56 on 205 degrees of freedom
## Residual deviance: 176.08 on 197 degrees of freedom
## AIC: 194.08
##
## Number of Fisher Scoring iterations: 16
Menghitung probabilitas hasil prediksi menggunakan data uji berdasarkan model yang telah dibangun.
Mydata_test$prob_Mydata<-predict(model2, type = "response", newdata = Mydata_test)
Mydata_test$prob_Mydata
## [1] 3.940839e-01 8.825116e-01 9.999999e-01 8.091388e-01 1.000000e+00
## [6] 8.825116e-01 8.091388e-01 8.091388e-01 8.825116e-01 9.999999e-01
## [11] 1.000000e+00 1.000000e+00 8.091388e-01 8.825116e-01 8.091388e-01
## [16] 3.543719e-01 8.091388e-01 3.543719e-01 8.091388e-01 9.999999e-01
## [21] 8.091388e-01 8.091388e-01 9.999999e-01 3.456125e-01 8.825116e-01
## [26] 8.091388e-01 1.000000e+00 3.543719e-01 8.825116e-01 8.091388e-01
## [31] 8.825116e-01 6.400299e-02 1.000000e+00 8.091388e-01 9.999999e-01
## [36] 3.456125e-01 8.091388e-01 4.834127e-01 4.930333e-01 8.825116e-01
## [41] 3.456125e-01 3.456125e-01 8.091388e-01 1.000000e+00 1.000000e+00
## [46] 8.091388e-01 4.834127e-01 8.091388e-01 8.825116e-01 3.543719e-01
## [51] 8.091388e-01 1.000000e+00 3.543719e-01 3.456125e-01 1.000000e+00
## [56] 8.091388e-01 6.400299e-02 5.353982e-01 8.091388e-01 6.400299e-02
## [61] 3.543719e-01 1.080636e-01 9.999999e-01 6.400299e-02 3.543719e-01
## [66] 3.456125e-01 1.080636e-01 3.456125e-01 6.400299e-02 1.080636e-01
## [71] 6.400299e-02 3.543719e-01 1.080636e-01 6.400299e-02 8.825116e-01
## [76] 3.456125e-01 6.400299e-02 1.080636e-01 6.400299e-02 3.456125e-01
## [81] 3.543719e-01 8.825116e-01 4.930333e-01 1.255407e-01 8.091388e-01
## [86] 1.080636e-01 2.677976e-08 4.834127e-01 1.080636e-01
ggplot(Mydata_test, aes(x=prob_Mydata)) +
geom_density(lwd=0.5) +
labs(title = "Distribution of Probability Prediction Data") +
theme_minimal()
Dari grafik diatas dapat diinterpretasikan bahwa hasil prediksi yang dilakukan lebih condong ke arah 1 yang artinya Tidak Punya.
Mydata_test$pred_Mydata <- factor(ifelse(Mydata_test$prob_Mydata > 0.5, "Tidak Punya","Punya"))
Mydata_test[1:10, c("pred_Mydata", "target")]
## pred_Mydata target
## 1 Punya Tidak Punya
## 4 Tidak Punya Tidak Punya
## 6 Tidak Punya Tidak Punya
## 7 Tidak Punya Tidak Punya
## 10 Tidak Punya Tidak Punya
## 12 Tidak Punya Tidak Punya
## 18 Tidak Punya Tidak Punya
## 19 Tidak Punya Tidak Punya
## 20 Tidak Punya Tidak Punya
## 24 Tidak Punya Tidak Punya
Dari syntax diatas, ketika probabilitas data test lebih dari 0.5, artinya Tidak Punya Rumah Milik Sendiri.
Mengevaluasi performa model menggunakan confusion matrix, termasuk akurasi, sensitivitas, dan spesifisitas.
library(caret)
log_conf <- confusionMatrix(Mydata_test$pred_Mydata, Mydata_test$target)
log_conf
## Confusion Matrix and Statistics
##
## Reference
## Prediction Punya Tidak Punya
## Punya 28 14
## Tidak Punya 8 39
##
## Accuracy : 0.7528
## 95% CI : (0.65, 0.8381)
## No Information Rate : 0.5955
## P-Value [Acc > NIR] : 0.001374
##
## Kappa : 0.5003
##
## Mcnemar's Test P-Value : 0.286422
##
## Sensitivity : 0.7778
## Specificity : 0.7358
## Pos Pred Value : 0.6667
## Neg Pred Value : 0.8298
## Prevalence : 0.4045
## Detection Rate : 0.3146
## Detection Prevalence : 0.4719
## Balanced Accuracy : 0.7568
##
## 'Positive' Class : Punya
##
Tuning Cut-Off
Mengeksplorasi berbagai nilai cut-off untuk melihat pengaruhnya pada performa model.
performa <- function(cutoff, prob, ref, postarget, negtarget)
{
predict <- factor(ifelse(prob >= cutoff, postarget, negtarget))
conf <- caret::confusionMatrix(predict , ref, positive = postarget)
acc <- conf$overall[1]
rec <- conf$byClass[1]
prec <- conf$byClass[3]
spec <- conf$byClass[2]
mat <- t(as.matrix(c(rec , acc , prec, spec)))
colnames(mat) <- c("recall", "accuracy", "precicion", "specificity")
return(mat)
}
co <- seq(0.01,0.80,length=100)
result <- matrix(0,100,4)
for(i in 1:100){
result[i,] = performa(cutoff = co[i],
prob = Mydata_test$prob_Mydata,
ref = Mydata_test$target,
postarget = "Tidak Punya",
negtarget = "Punya")
}
data_frame("Recall" = result[,1],
"Accuracy" = result[,2],
"Precision" = result[,3],
"Specificity" = result[,4],
"Cutoff" = co) %>%
gather(key = "performa", value = "value", 1:4) %>%
ggplot(aes(x = Cutoff, y = value, col = performa)) +
geom_line(lwd = 1.5) +
scale_color_manual(values = c("darkred","darkgreen","orange", "blue")) +
scale_y_continuous(breaks = seq(0,1,0.1), limits = c(0,1)) +
scale_x_continuous(breaks = seq(0,1,0.1)) +
labs(title = "Tradeoff model perfomance") +
theme_minimal() +
theme(legend.position = "top",
panel.grid.minor.y = element_blank(),
panel.grid.minor.x = element_blank())
Berdasarkan Tradeoff model performance diatas, dapat diketahui dengan cut-off 0.5 diperoleh nilai precision dan re-call yang agak tinggi, namun nilai specificity agak rendah.
Model Interpretation
Menghitung odds ratio untuk interpretasi pengaruh setiap prediktor terhadap probabilitas hasil.
exp(model2$coefficients) %>%
data.frame()
## .
## (Intercept) 1.881356e+07
## kwn2 3.457047e-08
## kwn3 6.125269e-08
## kwn4 2.084794e-08
## povYes 1.245802e-01
## jart2 6.518225e+00
## jart3 8.439190e-01
## jart4 1.274359e+00
## jart5 6.827672e-08
Nilai ini menunjukkan bahwa jika seseorang berada dalam kondisi miskin, odds variabel dependen akan menjadi sekitar 12.46% dari kondisi referensi.
dmy <- dummyVars("~target+sex+quant+resid+kwn+pov+educ+jart", data = Mydata)
dmy <- data.frame(predict(dmy, newdata = Mydata))
str(dmy)
## 'data.frame': 295 obs. of 26 variables:
## $ target.Punya : num 0 0 0 0 0 0 0 0 0 0 ...
## $ target.Tidak.Punya: num 1 1 1 1 1 1 1 1 1 1 ...
## $ sex.Female : num 0 0 1 0 1 0 0 0 0 0 ...
## $ sex.Male : num 1 1 0 1 0 1 1 1 1 1 ...
## $ quant.1 : num 0 0 0 0 0 0 0 0 0 0 ...
## $ quant.2 : num 0 0 0 0 1 1 0 0 0 0 ...
## $ quant.3 : num 0 0 1 1 0 0 1 1 0 0 ...
## $ quant.4 : num 0 1 0 0 0 0 0 0 1 1 ...
## $ quant.5 : num 1 0 0 0 0 0 0 0 0 0 ...
## $ resid.Desa : num 0 1 1 1 1 1 1 1 0 1 ...
## $ resid.Kota : num 1 0 0 0 0 0 0 0 1 0 ...
## $ kwn.1 : num 0 0 0 0 1 1 0 1 1 1 ...
## $ kwn.2 : num 1 0 1 0 0 0 1 0 0 0 ...
## $ kwn.3 : num 0 1 0 1 0 0 0 0 0 0 ...
## $ kwn.4 : num 0 0 0 0 0 0 0 0 0 0 ...
## $ pov.No : num 1 1 1 1 0 1 1 1 1 1 ...
## $ pov.Yes : num 0 0 0 0 1 0 0 0 0 0 ...
## $ educ.1 : num 1 1 0 0 0 0 0 0 0 0 ...
## $ educ.2 : num 0 0 0 0 0 1 1 0 0 0 ...
## $ educ.3 : num 0 0 1 1 1 0 0 1 1 1 ...
## $ educ.4 : num 0 0 0 0 0 0 0 0 0 0 ...
## $ jart.1 : num 1 0 0 0 0 1 0 0 0 0 ...
## $ jart.2 : num 0 1 1 1 1 0 1 0 0 1 ...
## $ jart.3 : num 0 0 0 0 0 0 0 1 1 0 ...
## $ jart.4 : num 0 0 0 0 0 0 0 0 0 0 ...
## $ jart.5 : num 0 0 0 0 0 0 0 0 0 0 ...
Menghapus variabel dummy yang variabel sebelumnya hanya terdapat 2 kategori.
dmy$target.Punya <- NULL
dmy$sex.Female <- NULL
dmy$resid.Desa <- NULL
dmy$pov.No <- NULL
names(dmy)
## [1] "target.Tidak.Punya" "sex.Male" "quant.1"
## [4] "quant.2" "quant.3" "quant.4"
## [7] "quant.5" "resid.Kota" "kwn.1"
## [10] "kwn.2" "kwn.3" "kwn.4"
## [13] "pov.Yes" "educ.1" "educ.2"
## [16] "educ.3" "educ.4" "jart.1"
## [19] "jart.2" "jart.3" "jart.4"
## [22] "jart.5"
Mengetahui nama-nama dari variabel dummy yang terbentuk.
Membentuk data training dan data testing dari data dmy
yang telah terbentuk.
set.seed(300)
dmy_train <- dmy[intrain,2:21]
dmy_test <- dmy[-intrain,2:21]
dmy_train_label <- dmy[intrain,1]
dmy_test_label <- dmy[-intrain,1]
library(class)
library(caret)
# Mencari nilai k optimal
k_values <- seq(1, 20, 2) # K range (ganjil)
accuracy <- sapply(k_values, function(k) {
pred <- knn(train = dmy_train, test = dmy_test, cl = dmy_train_label, k = k)
mean(pred == dmy_test_label) # Akurasi
})
# Plot akurasi terhadap k
plot(k_values, accuracy, type = "b", col = "blue", pch = 19, xlab = "k", ylab = "Akurasi")
optimal_k <- k_values[which.max(accuracy)]
cat("Nilai k optimal adalah:", optimal_k, "\n")
## Nilai k optimal adalah: 7
Menggunakan algoritma KNN untuk prediksi dengan jumlah tetangga k=7.
pred_knn <- class::knn(train = dmy_train,
test = dmy_test,
cl = dmy_train_label,
k = 7)
pred_knn
## [1] 0 1 0 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 1 1 1 1 1 1 1 1 1 0 1 1 1 0 1 1 1 1 1 1
## [39] 1 1 1 1 1 1 1 1 0 1 1 0 1 1 1 0 1 1 0 0 1 0 0 0 1 0 0 0 1 1 0 0 0 0 0 0 1 0
## [77] 0 0 0 1 0 1 0 0 1 0 0 1 0
## Levels: 0 1
Membuat confusion matriks dari prediski KNN.
pred_knn_conf <- confusionMatrix(as.factor(pred_knn), as.factor(dmy_test_label),"1")
pred_knn_conf
## Confusion Matrix and Statistics
##
## Reference
## Prediction 0 1
## 0 25 8
## 1 11 45
##
## Accuracy : 0.7865
## 95% CI : (0.6869, 0.8663)
## No Information Rate : 0.5955
## P-Value [Acc > NIR] : 0.0001083
##
## Kappa : 0.5509
##
## Mcnemar's Test P-Value : 0.6463552
##
## Sensitivity : 0.8491
## Specificity : 0.6944
## Pos Pred Value : 0.8036
## Neg Pred Value : 0.7576
## Prevalence : 0.5955
## Detection Rate : 0.5056
## Detection Prevalence : 0.6292
## Balanced Accuracy : 0.7718
##
## 'Positive' Class : 1
##
Dari hasil output tersebut adalah:
True Positives (TP): 45 (Prediksi “Tidak Punya” dan sebenarnya “Tidak Punya”)
True Negatives (TN): 25 (Prediksi “Punya” dan sebenarnya “Punya”)
False Positives (FP): 11 (Prediksi “Tidak Punya” tapi sebenarnya “Punya”)
False Negatives (FN): 8 (Prediksi “Punya” tapi sebenarnya “Tidak Punya”)
Model berhasil memprediksi dengan benar 78.65% dari seluruh data. Akurasi model diperkirakan berada di antara 68.69% dan 86.63% dengan tingkat kepercayaan 95%. Rentang ini memberikan gambaran tentang variabilitas kinerja model.
No Information Rate menunjukkan akurasi jika model hanya memprediksi kelas yang paling sering muncul (dalam hal ini, “Punya”). Jika model hanya memprediksi “Punya” untuk semua data, akurasinya akan menjadi 59.55%. Model ini jauh lebih baik dibandingkan dengan classifier acak, yang dibuktikan dengan p-value yang sangat kecil.
P-value ini menunjukkan bahwa akurasi model jauh lebih baik dibandingkan dengan No Information Rate. Nilai p-value yang sangat kecil menunjukkan bahwa hasil ini signifikan secara statistik.
Kappa mengukur tingkat konsistensi antara prediksi dan data aktual, disesuaikan dengan kemungkinan terjadi secara acak. Nilai Kappa sebesar 0.5509 menunjukkan bahwa konsitensi yang kuat antara prediksi dan data nyata, yang berarti model lebih baik daripada prediksi acak.
Uji McNemar digunakan untuk memeriksa apakah ada perbedaan signifikan antara jumlah false positives dan false negatives. Karena p-value lebih besar dari 0.05, ini menunjukkan tidak ada perbedaan signifikan antara jumlah false positives dan false negatives.
Sensitivitas (juga dikenal sebagai Recall atau True Positive Rate) menunjukkan bahwa 84.91% dari kasus yang sebenarnya “Tidak Punya” berhasil dikenali dengan benar oleh model. Ini mencerminkan seberapa baik model mendeteksi kasus positif (dalam hal ini, kelas “Tidak Punya”).
Spesifisitas (True Negative Rate) menunjukkan bahwa 69.44% dari kasus yang sebenarnya “Punya” berhasil dikenali dengan benar sebagai “Punya”. Ini mencerminkan seberapa baik model menghindari false positives.
PPV menunjukkan proporsi prediksi “Tidak Punya” yang benar-benar sesuai dengan data yang sebenarnya “Tidak Punya”. Artinya sebesar 80.36% dari prediksi “Tidak Punya” adalah benar.
NPV menunjukkan proporsi prediksi “Punya” yang benar-benar sesuai dengan data yang sebenarnya “Punya”. Artinya 75.76% dari prediksi “Punya” adalah benar.
Balanced accuracy adalah rata-rata dari sensitivitas dan spesifisitas. Dalam hal ini, menunjukkan kinerja model yang seimbang, dengan nilai 77.18%.
Kelas “Positif” dalam model ini adalah “Tidak Punya” (kelas 1), yang berarti kelas ini yang menjadi fokus prediksi model.
eval_logit <- data_frame(Accuracy = log_conf$overall[1],
Recall = log_conf$byClass[1],
Specificity = log_conf$byClass[2],
Precision = log_conf$byClass[3])
eval_knn <- data_frame(Accuracy = pred_knn_conf$overall[1],
Recall = pred_knn_conf$byClass[1],
Specificity = log_conf$byClass[2],
Precision = pred_knn_conf$byClass[3])
Model Evaluasi Logit
eval_logit
## # A tibble: 1 × 4
## Accuracy Recall Specificity Precision
## <dbl> <dbl> <dbl> <dbl>
## 1 0.753 0.778 0.736 0.667
Akurasi menunjukkan kinerja model secara keseluruhan, dengan nilai 75.30% yang cukup baik.
Recall mengindikasikan model mendeteksi sebagian besar kasus positif (77.8%).
Specificity menunjukkan bahwa model sangat baik dalam mendeteksi kasus negatif, dengan 73.6%.
Precision menunjukkan model sangat baik dalam memberikan prediksi positif yang akurat, dengan 66.7%.
Model Evaluasi KNN
eval_knn
## # A tibble: 1 × 4
## Accuracy Recall Specificity Precision
## <dbl> <dbl> <dbl> <dbl>
## 1 0.787 0.849 0.736 0.804
Model Regresi KNN berhasil memprediksi dengan benar sekitar 78.7% dari seluruh data. Akurasi menunjukkan proporsi total prediksi yang benar dibandingkan dengan jumlah keseluruhan data.
Recall (Sensitivitas) mengukur seberapa baik model mendeteksi kelas positif. Model regresi KNN berhasil mendeteksi 84.9% dari semua kasus yang benar-benar positif.
Nilai 0.736 menunjukkan model ini berhasil mendeteksi 73.6% dari semua kasus yang sebenarnya negatif.
Nilai 0.804 berarti 80.4% dari prediksi positif yang dilakukan oleh model adalah benar-benar positif. Precision mengukur seberapa banyak prediksi positif yang relevan dan mengurangi prediksi positif yang salah.
Regresi KNN lebih unggul dalam hal precision yang menunjukkan bahwa model ini lebih akurat dalam prediksi positif. Artinya, prediksi positif yang dihasilkan oleh model regresi KNN lebih relevan dan kurang cenderung salah, dibandingkan dengan regresi Logistik.
Direktorat Statistik Kesejahteraan Rakyat, BPS, saptahas@bps.go.id