library(readxl)
library(dplyr)
library(ggplot2)
library(tidyverse)
library(tidyr)
library(nnet)
library(caret)
library(e1071)
library(rpart)
library(randomForest)
library(kernlab)
Dalam perbankan, risiko gagal bayar (default) merupakan salah satu permasalahan utama yang dapat mempengaruhi stabilitas keuangan. Oleh karena itu, diperlukan model prediksi yang mampu mengklasifikasikan nasabah berpotensi default secara akurat. Penelitian ini bertujuan untuk membandingkan performa beberapa metode machine learning, yaitu Artificial Neural Network (ANN), Support Vector Machine (SVM), Decision Tree, dan Random Forest dalam memprediksi status default nasabah.
Dataset yang digunakan merupakan data pinjaman bank dengan variabel sebagai berikut:
# Input Data
data_bank <- read_excel("C:/Users/asus/Downloads/data_pinjaman_bank.xlsx")
data_bank <- data.frame(data_bank)
data_bank$default <- as.factor(data_bank$default)
head(data_bank)
## age ed employ address income debtinc creddebt othdebt default
## 1 41 3 17 12 176 9 11359 5009 1
## 2 27 1 10 6 31 17 1362 4001 0
## 3 40 1 15 14 55 6 856 2169 0
## 4 41 1 15 14 120 3 2659 821 0
## 5 24 2 2 0 28 17 1787 3057 1
## 6 41 2 5 5 25 10 393 2157 0
Memastikan dan melihat apakah didalam data_bank terdapat data NULL atau tidak.
## Cleaning Data
colSums(is.na(data_bank))
## age ed employ address income debtinc creddebt othdebt
## 0 0 0 0 0 0 0 0
## default
## 0
Untuk melihat Distribusi Data dengan melakukan pengecekan ringkasan statistik menggunakan function “summary()”.
summary(data_bank)
## age ed employ address
## Min. :20.00 Min. :1.000 Min. : 0.000 Min. : 0.000
## 1st Qu.:29.00 1st Qu.:1.000 1st Qu.: 3.000 1st Qu.: 3.000
## Median :34.00 Median :1.000 Median : 7.000 Median : 7.000
## Mean :34.86 Mean :1.723 Mean : 8.389 Mean : 8.279
## 3rd Qu.:40.00 3rd Qu.:2.000 3rd Qu.:12.000 3rd Qu.:12.000
## Max. :56.00 Max. :5.000 Max. :31.000 Max. :34.000
## income debtinc creddebt othdebt default
## Min. : 14.0 Min. : 0.00 Min. : 12.0 Min. : 46 0:517
## 1st Qu.: 24.0 1st Qu.: 5.00 1st Qu.: 368.8 1st Qu.: 1044 1:183
## Median : 34.0 Median : 9.00 Median : 855.0 Median : 1988
## Mean : 45.6 Mean :10.24 Mean : 1553.6 Mean : 3058
## 3rd Qu.: 55.0 3rd Qu.:14.00 3rd Qu.: 1901.8 3rd Qu.: 3923
## Max. :446.0 Max. :41.00 Max. :20561.0 Max. :27034
table(data_bank$default)
##
## 0 1
## 517 183
Pada tahap ini, data dibagi menjadi dua bagian, yaitu data training dan data testing, dengan perbandingan 80:20. Data training akan digunakan untuk melatih model, sedangkan data testing digunakan untuk mengukur performa model terhadap data yang belum pernah dilihat sebelumnya.
set.seed(108)
train_id <- sample(1:nrow(data_bank), 0.8 * nrow(data_bank))
train_data_bank<- data_bank[train_id, ] # Data training
test_data_bank<- data_bank[-train_id, ] # Data testing
head(train_data_bank) # Data train
## age ed employ address income debtinc creddebt othdebt default
## 127 39 2 7 2 68 13 1017 7823 1
## 495 25 1 3 2 16 18 1011 1837 1
## 528 42 1 3 10 24 11 667 1877 0
## 679 34 1 9 8 48 9 420 4044 0
## 493 28 1 0 2 28 33 2284 7040 1
## 54 38 3 3 18 25 4 312 613 0
head(test_data_bank) # Data testing
## age ed employ address income debtinc creddebt othdebt default
## 4 41 1 15 14 120 3 2659 821 0
## 8 43 1 12 11 38 4 129 1239 0
## 10 36 1 0 13 25 20 2778 2147 0
## 11 27 1 0 1 16 2 183 89 0
## 12 25 1 4 0 23 5 252 944 0
## 16 36 2 9 6 49 9 818 3396 1
train_data_bank$default <- as.factor(train_data_bank$default)
test_data_bank$default <- as.factor(test_data_bank$default)
Membuat model Artificial Neural Network (ANN) dengan data yang digunakan adalah Data Pinjaman Bank
## Membuat Model ANN
ann_model <- nnet(default ~ age + ed + employ + address + income + debtinc + creddebt + othdebt,data = train_data_bank, size = 5, decay = 0.01, maxit = 200)
## # weights: 51
## initial value 337.424173
## iter 10 value 323.013234
## iter 20 value 320.769796
## iter 30 value 320.216164
## iter 40 value 320.052364
## iter 50 value 319.758396
## iter 60 value 316.640389
## iter 70 value 292.571713
## iter 80 value 277.149914
## iter 90 value 275.225483
## iter 100 value 273.896830
## iter 110 value 270.453904
## iter 120 value 270.272517
## iter 130 value 270.180431
## iter 140 value 269.883740
## iter 150 value 269.145783
## iter 160 value 267.257959
## iter 170 value 266.832750
## iter 180 value 265.383299
## iter 190 value 264.445129
## iter 200 value 264.019399
## final value 264.019399
## stopped after 200 iterations
head(ann_model)
## $n
## [1] 8 5 1
##
## $nunits
## [1] 15
##
## $nconn
## [1] 0 0 0 0 0 0 0 0 0 0 9 18 27 36 45 51
##
## $conn
## [1] 0 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6
## [26] 7 8 0 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 7 8 0 9 10 11 12
## [51] 13
##
## $nsunits
## [1] 15
##
## $decay
## [1] 0.01
ANNpred_train <- predict(ann_model, train_data_bank, type="class")
head(ANNpred_train)
## [1] "0" "1" "0" "0" "1" "0"
tail(ANNpred_train)
## [1] "1" "0" "1" "0" "0" "1"
ANNpred_test <- predict(ann_model, test_data_bank, type="class")
head(ANNpred_test)
## [1] "0" "0" "1" "0" "0" "0"
tail(ANNpred_train)
## [1] "1" "0" "1" "0" "0" "1"
# Perbandingan Y aktual dengan Y prediksi
compare_train_ANN <- data.frame(train_data_bank$default, ANNpred_train, ifelse(train_data_bank$default == ANNpred_train, "BENAR", "SALAH"))
head(compare_train_ANN)
## train_data_bank.default ANNpred_train
## 1 1 0
## 2 1 1
## 3 0 0
## 4 0 0
## 5 1 1
## 6 0 0
## ifelse.train_data_bank.default....ANNpred_train...BENAR....SALAH..
## 1 SALAH
## 2 BENAR
## 3 BENAR
## 4 BENAR
## 5 BENAR
## 6 BENAR
colnames(compare_train_ANN) = c("Y aktual", "Y prediksi", "Ket")
head(compare_train_ANN)
## Y aktual Y prediksi Ket
## 1 1 0 SALAH
## 2 1 1 BENAR
## 3 0 0 BENAR
## 4 0 0 BENAR
## 5 1 1 BENAR
## 6 0 0 BENAR
tail(compare_train_ANN)
## Y aktual Y prediksi Ket
## 555 1 1 BENAR
## 556 0 0 BENAR
## 557 1 1 BENAR
## 558 0 0 BENAR
## 559 0 0 BENAR
## 560 1 1 BENAR
compare_test_ANN <- data.frame(test_data_bank$default, ANNpred_test, ifelse(test_data_bank$default == ANNpred_test, "BENAR", "SALAH"))
head(compare_test_ANN)
## test_data_bank.default ANNpred_test
## 1 0 0
## 2 0 0
## 3 0 1
## 4 0 0
## 5 0 0
## 6 1 0
## ifelse.test_data_bank.default....ANNpred_test...BENAR....SALAH..
## 1 BENAR
## 2 BENAR
## 3 SALAH
## 4 BENAR
## 5 BENAR
## 6 SALAH
colnames(compare_test_ANN) = c("Y aktual", "Y prediksi", "Ket")
head(compare_test_ANN)
## Y aktual Y prediksi Ket
## 1 0 0 BENAR
## 2 0 0 BENAR
## 3 0 1 SALAH
## 4 0 0 BENAR
## 5 0 0 BENAR
## 6 1 0 SALAH
tail(compare_test_ANN)
## Y aktual Y prediksi Ket
## 135 0 0 BENAR
## 136 1 0 SALAH
## 137 0 1 SALAH
## 138 0 0 BENAR
## 139 0 0 BENAR
## 140 1 1 BENAR
# Confusion Matrix untuk data testing
confusionMatrix(
data = as.factor(ANNpred_test),
reference = as.factor(test_data_bank$default),
positive = "1"
)
## Confusion Matrix and Statistics
##
## Reference
## Prediction 0 1
## 0 78 9
## 1 30 23
##
## Accuracy : 0.7214
## 95% CI : (0.6394, 0.7938)
## No Information Rate : 0.7714
## P-Value [Acc > NIR] : 0.931804
##
## Kappa : 0.3583
##
## Mcnemar's Test P-Value : 0.001362
##
## Sensitivity : 0.7188
## Specificity : 0.7222
## Pos Pred Value : 0.4340
## Neg Pred Value : 0.8966
## Prevalence : 0.2286
## Detection Rate : 0.1643
## Detection Prevalence : 0.3786
## Balanced Accuracy : 0.7205
##
## 'Positive' Class : 1
##
# Confusion Matrix untuk data training
confusionMatrix(
data = as.factor(ANNpred_train),
reference = as.factor(train_data_bank$default),
positive = "1"
)
## Confusion Matrix and Statistics
##
## Reference
## Prediction 0 1
## 0 318 48
## 1 91 103
##
## Accuracy : 0.7518
## 95% CI : (0.7138, 0.787)
## No Information Rate : 0.7304
## P-Value [Acc > NIR] : 0.1363915
##
## Kappa : 0.4217
##
## Mcnemar's Test P-Value : 0.0003675
##
## Sensitivity : 0.6821
## Specificity : 0.7775
## Pos Pred Value : 0.5309
## Neg Pred Value : 0.8689
## Prevalence : 0.2696
## Detection Rate : 0.1839
## Detection Prevalence : 0.3464
## Balanced Accuracy : 0.7298
##
## 'Positive' Class : 1
##
Interpretasi :
Model klasifikasi menghasilkan akurasi sebesar 75,18%, namun tidak berbeda signifikan dibandingkan No Information Rate (p-value = 0,136). Nilai Kappa sebesar 0,4217 menunjukkan tingkat kesepakatan sedang. Model memiliki kemampuan yang lebih baik dalam mengklasifikasikan kelas negatif (Specificity = 0,7775) dibandingkan kelas positif (Sensitivity = 0,6821). Nilai precision yang relatif rendah (0,5309) menunjukkan bahwa prediksi kelas positif masih kurang akurat, meskipun prediksi kelas negatif cukup baik (NPV = 0,8689). Selain itu, hasil McNemar’s Test yang signifikan (p-value < 0,05) mengindikasikan adanya ketidakseimbangan kesalahan klasifikasi. Secara keseluruhan, model cukup baik, namun masih perlu perbaikan terutama dalam mendeteksi kelas positif.
Untuk memaikai model SVM (Support Vector Machine) maka harus memakai packages “nnet” dan “e1071”
# Input Data
data_bank <- read_excel("C:/Users/asus/Downloads/data_pinjaman_bank.xlsx")
data_bank <- data.frame(data_bank)
data_bank$default <- as.factor(data_bank$default)
head(data_bank)
## age ed employ address income debtinc creddebt othdebt default
## 1 41 3 17 12 176 9 11359 5009 1
## 2 27 1 10 6 31 17 1362 4001 0
## 3 40 1 15 14 55 6 856 2169 0
## 4 41 1 15 14 120 3 2659 821 0
## 5 24 2 2 0 28 17 1787 3057 1
## 6 41 2 5 5 25 10 393 2157 0
Memastikan dan melihat apakah didalam data_bank terdapat data NULL atau tidak.
## Cleaning Data
colSums(is.na(data_bank))
## age ed employ address income debtinc creddebt othdebt
## 0 0 0 0 0 0 0 0
## default
## 0
Untuk melihat Distribusi Data dengan melakukan pengecekan ringkasan statistik menggunakan function “summary()”.
summary(data_bank)
## age ed employ address
## Min. :20.00 Min. :1.000 Min. : 0.000 Min. : 0.000
## 1st Qu.:29.00 1st Qu.:1.000 1st Qu.: 3.000 1st Qu.: 3.000
## Median :34.00 Median :1.000 Median : 7.000 Median : 7.000
## Mean :34.86 Mean :1.723 Mean : 8.389 Mean : 8.279
## 3rd Qu.:40.00 3rd Qu.:2.000 3rd Qu.:12.000 3rd Qu.:12.000
## Max. :56.00 Max. :5.000 Max. :31.000 Max. :34.000
## income debtinc creddebt othdebt default
## Min. : 14.0 Min. : 0.00 Min. : 12.0 Min. : 46 0:517
## 1st Qu.: 24.0 1st Qu.: 5.00 1st Qu.: 368.8 1st Qu.: 1044 1:183
## Median : 34.0 Median : 9.00 Median : 855.0 Median : 1988
## Mean : 45.6 Mean :10.24 Mean : 1553.6 Mean : 3058
## 3rd Qu.: 55.0 3rd Qu.:14.00 3rd Qu.: 1901.8 3rd Qu.: 3923
## Max. :446.0 Max. :41.00 Max. :20561.0 Max. :27034
Pada tahap ini, data dibagi menjadi dua bagian, yaitu data training dan data testing, dengan perbandingan 80:20. Data training akan digunakan untuk melatih model, sedangkan data testing digunakan untuk mengukur performa model terhadap data yang belum pernah dilihat sebelumnya.
set.seed(108)
train_id <- sample(1:nrow(data_bank), 0.8 * nrow(data_bank))
train_data_bank<- data_bank[train_id, ] # Data training
test_data_bank<- data_bank[-train_id, ] # Data testing
head(train_data_bank) # Data train
## age ed employ address income debtinc creddebt othdebt default
## 127 39 2 7 2 68 13 1017 7823 1
## 495 25 1 3 2 16 18 1011 1837 1
## 528 42 1 3 10 24 11 667 1877 0
## 679 34 1 9 8 48 9 420 4044 0
## 493 28 1 0 2 28 33 2284 7040 1
## 54 38 3 3 18 25 4 312 613 0
head(test_data_bank) # Data testing
## age ed employ address income debtinc creddebt othdebt default
## 4 41 1 15 14 120 3 2659 821 0
## 8 43 1 12 11 38 4 129 1239 0
## 10 36 1 0 13 25 20 2778 2147 0
## 11 27 1 0 1 16 2 183 89 0
## 12 25 1 4 0 23 5 252 944 0
## 16 36 2 9 6 49 9 818 3396 1
train_data_bank$default <- as.factor(train_data_bank$default)
test_data_bank$default <- as.factor(test_data_bank$default)
Membuat model Support Vektor Machine dengan data yang digunakan adalah Titanic.
train_data_bank$default <- as.factor(train_data_bank$default)
# Buat grid parameter
tune_grid <- expand.grid(
sigma = c(0.01, 0.1, 1),
C = c(0.1, 1, 10, 100)
)
# Setup cross-validation 10-fold
control <- trainControl(method = "cv", number = 10)
# Train model SVM dengan radial basis function (RBF)
set.seed(123)
svm_tuned <- train(
default ~ age + ed + employ + address + income + debtinc + creddebt + othdebt,
data = train_data_bank,
method = "svmRadial",
trControl = control,
tuneGrid = tune_grid,
preProcess = c("center", "scale")
)
# Lihat hasil tuning
print(svm_tuned)
## Support Vector Machines with Radial Basis Function Kernel
##
## 560 samples
## 8 predictor
## 2 classes: '0', '1'
##
## Pre-processing: centered (8), scaled (8)
## Resampling: Cross-Validated (10 fold)
## Summary of sample sizes: 504, 504, 504, 504, 504, 503, ...
## Resampling results across tuning parameters:
##
## sigma C Accuracy Kappa
## 0.01 0.1 0.7303714 0.0000000
## 0.01 1.0 0.7679050 0.2238772
## 0.01 10.0 0.7928748 0.3827713
## 0.01 100.0 0.7892686 0.3855887
## 0.10 0.1 0.7303714 0.0000000
## 0.10 1.0 0.7910230 0.3633833
## 0.10 10.0 0.7768313 0.3578276
## 0.10 100.0 0.7303691 0.2716460
## 1.00 0.1 0.7303714 0.0000000
## 1.00 1.0 0.7410185 0.1677537
## 1.00 10.0 0.7176720 0.1926669
## 1.00 100.0 0.7089035 0.1740350
##
## Accuracy was used to select the optimal model using the largest value.
## The final values used for the model were sigma = 0.01 and C = 10.
plot(svm_tuned)
Interpretasi :
Grafik menunjukkan hubungan antara parameter cost dan sigma terhadap akurasi cross-validation. Terlihat bahwa:
Sigma kecil (0.01) memberikan performa terbaik dan paling stabil (akurasi tertinggi ~0,79) Sigma sedang (0.1) performanya menurun saat cost meningkat Sigma besar (1) menghasilkan akurasi terendah (cenderung underfitting) Nilai cost optimal berada di sekitar 1–10, karena setelah itu akurasi cenderung stagnan atau menurun
Artinya, model terbaik diperoleh saat kompleksitas model cukup (tidak terlalu sederhana atau terlalu kompleks), yaitu pada kombinasi sigma kecil dan cost moderat.
# Prediksi data training
SVMpred_train <- predict(svm_tuned, newdata = train_data_bank)
# Prediksi data testing
SVMpred_test <- predict(svm_tuned, newdata = test_data_bank)
# Lihat hasil prediksi
head(SVMpred_train)
## [1] 0 1 0 0 1 0
## Levels: 0 1
head(SVMpred_test)
## [1] 0 0 1 0 0 0
## Levels: 0 1
# Training set comparison
compare_train_SVM <- data.frame(train_data_bank$default, SVMpred_train,
ifelse(train_data_bank$default == SVMpred_train, "BENAR", "SALAH"))
colnames(compare_train_SVM) <- c("Y aktual", "Y prediksi", "Ket")
head(compare_train_SVM)
## Y aktual Y prediksi Ket
## 1 1 0 SALAH
## 2 1 1 BENAR
## 3 0 0 BENAR
## 4 0 0 BENAR
## 5 1 1 BENAR
## 6 0 0 BENAR
# Testing set comparison
compare_test_SVM <- data.frame(test_data_bank$default, SVMpred_test,
ifelse(test_data_bank$default == SVMpred_test, "BENAR", "SALAH"))
colnames(compare_test_SVM) <- c("Y aktual", "Y prediksi", "Ket")
head(compare_test_SVM)
## Y aktual Y prediksi Ket
## 1 0 0 BENAR
## 2 0 0 BENAR
## 3 0 1 SALAH
## 4 0 0 BENAR
## 5 0 0 BENAR
## 6 1 0 SALAH
# Confusion matrix untuk data training
confusionMatrix(SVMpred_train, train_data_bank$default, positive = "1")
## Confusion Matrix and Statistics
##
## Reference
## Prediction 0 1
## 0 393 89
## 1 16 62
##
## Accuracy : 0.8125
## 95% CI : (0.7777, 0.844)
## No Information Rate : 0.7304
## P-Value [Acc > NIR] : 3.578e-06
##
## Kappa : 0.4383
##
## Mcnemar's Test P-Value : 2.118e-12
##
## Sensitivity : 0.4106
## Specificity : 0.9609
## Pos Pred Value : 0.7949
## Neg Pred Value : 0.8154
## Prevalence : 0.2696
## Detection Rate : 0.1107
## Detection Prevalence : 0.1393
## Balanced Accuracy : 0.6857
##
## 'Positive' Class : 1
##
# Confusion matrix untuk data testing
confusionMatrix(SVMpred_test, test_data_bank$default, positive = "1")
## Confusion Matrix and Statistics
##
## Reference
## Prediction 0 1
## 0 99 17
## 1 9 15
##
## Accuracy : 0.8143
## 95% CI : (0.7398, 0.875)
## No Information Rate : 0.7714
## P-Value [Acc > NIR] : 0.1331
##
## Kappa : 0.4226
##
## Mcnemar's Test P-Value : 0.1698
##
## Sensitivity : 0.4688
## Specificity : 0.9167
## Pos Pred Value : 0.6250
## Neg Pred Value : 0.8534
## Prevalence : 0.2286
## Detection Rate : 0.1071
## Detection Prevalence : 0.1714
## Balanced Accuracy : 0.6927
##
## 'Positive' Class : 1
##
Interpretasi :
Model SVM pada data testing menghasilkan akurasi sebesar 81,43%, namun tidak berbeda signifikan dari No Information Rate (p-value = 0,133). Nilai Kappa sebesar 0,4226 menunjukkan kesepakatan sedang. Model memiliki specificity tinggi (0,9167) tetapi sensitivity rendah (0,4688), yang berarti model jauh lebih baik dalam mendeteksi kelas negatif dibandingkan kelas positif. Secara keseluruhan, meskipun akurasi cukup tinggi, model masih kurang optimal dalam mengidentifikasi kelas positif.
Untuk memaikai model Desicion Tree maka harus memakai packages “rpart”
# Input Data
data_bank <- read_excel("C:/Users/asus/Downloads/data_pinjaman_bank.xlsx")
data_bank <- data.frame(data_bank)
data_bank$default <- as.factor(data_bank$default)
head(data_bank)
## age ed employ address income debtinc creddebt othdebt default
## 1 41 3 17 12 176 9 11359 5009 1
## 2 27 1 10 6 31 17 1362 4001 0
## 3 40 1 15 14 55 6 856 2169 0
## 4 41 1 15 14 120 3 2659 821 0
## 5 24 2 2 0 28 17 1787 3057 1
## 6 41 2 5 5 25 10 393 2157 0
Memastikan dan melihat apakah didalam data_bank terdapat data NULL atau tidak.
## Cleaning Data
colSums(is.na(data_bank))
## age ed employ address income debtinc creddebt othdebt
## 0 0 0 0 0 0 0 0
## default
## 0
Untuk melihat Distribusi Data dengan melakukan pengecekan ringkasan statistik menggunakan function “summary()”.
summary(data_bank)
## age ed employ address
## Min. :20.00 Min. :1.000 Min. : 0.000 Min. : 0.000
## 1st Qu.:29.00 1st Qu.:1.000 1st Qu.: 3.000 1st Qu.: 3.000
## Median :34.00 Median :1.000 Median : 7.000 Median : 7.000
## Mean :34.86 Mean :1.723 Mean : 8.389 Mean : 8.279
## 3rd Qu.:40.00 3rd Qu.:2.000 3rd Qu.:12.000 3rd Qu.:12.000
## Max. :56.00 Max. :5.000 Max. :31.000 Max. :34.000
## income debtinc creddebt othdebt default
## Min. : 14.0 Min. : 0.00 Min. : 12.0 Min. : 46 0:517
## 1st Qu.: 24.0 1st Qu.: 5.00 1st Qu.: 368.8 1st Qu.: 1044 1:183
## Median : 34.0 Median : 9.00 Median : 855.0 Median : 1988
## Mean : 45.6 Mean :10.24 Mean : 1553.6 Mean : 3058
## 3rd Qu.: 55.0 3rd Qu.:14.00 3rd Qu.: 1901.8 3rd Qu.: 3923
## Max. :446.0 Max. :41.00 Max. :20561.0 Max. :27034
Pada tahap ini, data dibagi menjadi dua bagian, yaitu data training dan data testing, dengan perbandingan 80:20. Data training akan digunakan untuk melatih model, sedangkan data testing digunakan untuk mengukur performa model terhadap data yang belum pernah dilihat sebelumnya.
set.seed(108)
train_id <- sample(1:nrow(data_bank), 0.8 * nrow(data_bank))
train_data_bank<- data_bank[train_id, ] # Data training
test_data_bank<- data_bank[-train_id, ] # Data testing
head(train_data_bank) # Data train
## age ed employ address income debtinc creddebt othdebt default
## 127 39 2 7 2 68 13 1017 7823 1
## 495 25 1 3 2 16 18 1011 1837 1
## 528 42 1 3 10 24 11 667 1877 0
## 679 34 1 9 8 48 9 420 4044 0
## 493 28 1 0 2 28 33 2284 7040 1
## 54 38 3 3 18 25 4 312 613 0
head(test_data_bank) # Data testing
## age ed employ address income debtinc creddebt othdebt default
## 4 41 1 15 14 120 3 2659 821 0
## 8 43 1 12 11 38 4 129 1239 0
## 10 36 1 0 13 25 20 2778 2147 0
## 11 27 1 0 1 16 2 183 89 0
## 12 25 1 4 0 23 5 252 944 0
## 16 36 2 9 6 49 9 818 3396 1
train_data_bank$default <- as.factor(train_data_bank$default)
test_data_bank$default <- as.factor(test_data_bank$default)
Membuat model Decision Tree dengan data yang digunakan adalah Data Peminjaman Bank.
tree_model <- rpart(default ~ age + ed + employ + address + income + debtinc + creddebt + othdebt,
data = train_data_bank, method = "class")
tree_model
## n= 560
##
## node), split, n, loss, yval, (yprob)
## * denotes terminal node
##
## 1) root 560 151 0 (0.7303571 0.2696429)
## 2) debtinc< 15.5 456 88 0 (0.8070175 0.1929825)
## 4) employ>=2.5 352 45 0 (0.8721591 0.1278409) *
## 5) employ< 2.5 104 43 0 (0.5865385 0.4134615)
## 10) age>=38.5 15 0 0 (1.0000000 0.0000000) *
## 11) age< 38.5 89 43 0 (0.5168539 0.4831461)
## 22) creddebt< 879.5 69 29 0 (0.5797101 0.4202899)
## 44) employ< 1.5 51 18 0 (0.6470588 0.3529412) *
## 45) employ>=1.5 18 7 1 (0.3888889 0.6111111) *
## 23) creddebt>=879.5 20 6 1 (0.3000000 0.7000000) *
## 3) debtinc>=15.5 104 41 1 (0.3942308 0.6057692)
## 6) employ>=3.5 68 33 0 (0.5147059 0.4852941)
## 12) creddebt< 4878 48 16 0 (0.6666667 0.3333333)
## 24) employ>=9.5 24 3 0 (0.8750000 0.1250000) *
## 25) employ< 9.5 24 11 1 (0.4583333 0.5416667)
## 50) age< 38 16 6 0 (0.6250000 0.3750000) *
## 51) age>=38 8 1 1 (0.1250000 0.8750000) *
## 13) creddebt>=4878 20 3 1 (0.1500000 0.8500000) *
## 7) employ< 3.5 36 6 1 (0.1666667 0.8333333) *
tree_pred_train <- predict(tree_model, train_data_bank, type = "class")
head(tree_pred_train)
## 127 495 528 679 493 54
## 0 1 0 0 1 0
## Levels: 0 1
tree_pred_test <- predict(tree_model, test_data_bank, type = "class")
head(tree_pred_test)
## 4 8 10 11 12 16
## 0 0 1 0 0 0
## Levels: 0 1
# Evaluasi Decision Tree - Data Training
compare_train_tree <- data.frame(
"Y aktual" = train_data_bank$default,
"Y prediksi" = tree_pred_train,
"Keterangan" = ifelse(train_data_bank$default == tree_pred_train, "BENAR", "SALAH")
)
# Evaluasi Decision Tree - Data Testing
compare_test_tree <- data.frame(
"Y aktual" = test_data_bank$default,
"Y prediksi" = tree_pred_test,
"Keterangan" = ifelse(test_data_bank$default == tree_pred_test, "BENAR", "SALAH")
)
head(compare_train_tree)
## Y.aktual Y.prediksi Keterangan
## 127 1 0 SALAH
## 495 1 1 BENAR
## 528 0 0 BENAR
## 679 0 0 BENAR
## 493 1 1 BENAR
## 54 0 0 BENAR
head(compare_test_tree)
## Y.aktual Y.prediksi Keterangan
## 4 0 0 BENAR
## 8 0 0 BENAR
## 10 0 1 SALAH
## 11 0 0 BENAR
## 12 0 0 BENAR
## 16 1 0 SALAH
# Training
confusionMatrix(tree_pred_train, train_data_bank$default, positive = "1")
## Confusion Matrix and Statistics
##
## Reference
## Prediction 0 1
## 0 386 72
## 1 23 79
##
## Accuracy : 0.8304
## 95% CI : (0.7967, 0.8605)
## No Information Rate : 0.7304
## P-Value [Acc > NIR] : 1.578e-08
##
## Kappa : 0.5202
##
## Mcnemar's Test P-Value : 8.449e-07
##
## Sensitivity : 0.5232
## Specificity : 0.9438
## Pos Pred Value : 0.7745
## Neg Pred Value : 0.8428
## Prevalence : 0.2696
## Detection Rate : 0.1411
## Detection Prevalence : 0.1821
## Balanced Accuracy : 0.7335
##
## 'Positive' Class : 1
##
# Testing
confusionMatrix(tree_pred_test, test_data_bank$default, positive = "1")
## Confusion Matrix and Statistics
##
## Reference
## Prediction 0 1
## 0 100 18
## 1 8 14
##
## Accuracy : 0.8143
## 95% CI : (0.7398, 0.875)
## No Information Rate : 0.7714
## P-Value [Acc > NIR] : 0.13307
##
## Kappa : 0.4083
##
## Mcnemar's Test P-Value : 0.07756
##
## Sensitivity : 0.4375
## Specificity : 0.9259
## Pos Pred Value : 0.6364
## Neg Pred Value : 0.8475
## Prevalence : 0.2286
## Detection Rate : 0.1000
## Detection Prevalence : 0.1571
## Balanced Accuracy : 0.6817
##
## 'Positive' Class : 1
##
Interpretasi :
Model Decision Tree menghasilkan akurasi sebesar 81,43%, namun tidak berbeda signifikan dari No Information Rate (p-value = 0,133). Nilai Kappa sebesar 0,4083 menunjukkan tingkat kesepakatan sedang. Model memiliki specificity tinggi (0,9259) tetapi sensitivity rendah (0,4375), yang berarti model lebih baik dalam mengklasifikasikan kelas negatif dibandingkan kelas positif. Secara keseluruhan, performa model cukup baik dari sisi akurasi, namun masih lemah dalam mendeteksi kelas positif. Dibandingkan SVM sebelumnya, performa Decision Tree mirip (akurasi sama) tetapi sedikit lebih rendah dalam mendeteksi kelas positif (sensitivity lebih kecil).
Untuk memaikai model Desicion Tree maka harus memakai packages “randomForest”
# Input Data
data_bank <- read_excel("C:/Users/asus/Downloads/data_pinjaman_bank.xlsx")
data_bank <- data.frame(data_bank)
data_bank$default <- as.factor(data_bank$default)
head(data_bank)
## age ed employ address income debtinc creddebt othdebt default
## 1 41 3 17 12 176 9 11359 5009 1
## 2 27 1 10 6 31 17 1362 4001 0
## 3 40 1 15 14 55 6 856 2169 0
## 4 41 1 15 14 120 3 2659 821 0
## 5 24 2 2 0 28 17 1787 3057 1
## 6 41 2 5 5 25 10 393 2157 0
Memastikan dan melihat apakah didalam data_bank terdapat data NULL atau tidak.
## Cleaning Data
colSums(is.na(data_bank))
## age ed employ address income debtinc creddebt othdebt
## 0 0 0 0 0 0 0 0
## default
## 0
Untuk melihat Distribusi Data dengan melakukan pengecekan ringkasan statistik menggunakan function “summary()”.
summary(data_bank)
## age ed employ address
## Min. :20.00 Min. :1.000 Min. : 0.000 Min. : 0.000
## 1st Qu.:29.00 1st Qu.:1.000 1st Qu.: 3.000 1st Qu.: 3.000
## Median :34.00 Median :1.000 Median : 7.000 Median : 7.000
## Mean :34.86 Mean :1.723 Mean : 8.389 Mean : 8.279
## 3rd Qu.:40.00 3rd Qu.:2.000 3rd Qu.:12.000 3rd Qu.:12.000
## Max. :56.00 Max. :5.000 Max. :31.000 Max. :34.000
## income debtinc creddebt othdebt default
## Min. : 14.0 Min. : 0.00 Min. : 12.0 Min. : 46 0:517
## 1st Qu.: 24.0 1st Qu.: 5.00 1st Qu.: 368.8 1st Qu.: 1044 1:183
## Median : 34.0 Median : 9.00 Median : 855.0 Median : 1988
## Mean : 45.6 Mean :10.24 Mean : 1553.6 Mean : 3058
## 3rd Qu.: 55.0 3rd Qu.:14.00 3rd Qu.: 1901.8 3rd Qu.: 3923
## Max. :446.0 Max. :41.00 Max. :20561.0 Max. :27034
Pada tahap ini, data dibagi menjadi dua bagian, yaitu data training dan data testing, dengan perbandingan 80:20. Data training akan digunakan untuk melatih model, sedangkan data testing digunakan untuk mengukur performa model terhadap data yang belum pernah dilihat sebelumnya.
set.seed(108)
train_id <- sample(1:nrow(data_bank), 0.8 * nrow(data_bank))
train_data_bank<- data_bank[train_id, ] # Data training
test_data_bank<- data_bank[-train_id, ] # Data testing
head(train_data_bank) # Data train
## age ed employ address income debtinc creddebt othdebt default
## 127 39 2 7 2 68 13 1017 7823 1
## 495 25 1 3 2 16 18 1011 1837 1
## 528 42 1 3 10 24 11 667 1877 0
## 679 34 1 9 8 48 9 420 4044 0
## 493 28 1 0 2 28 33 2284 7040 1
## 54 38 3 3 18 25 4 312 613 0
head(test_data_bank) # Data testing
## age ed employ address income debtinc creddebt othdebt default
## 4 41 1 15 14 120 3 2659 821 0
## 8 43 1 12 11 38 4 129 1239 0
## 10 36 1 0 13 25 20 2778 2147 0
## 11 27 1 0 1 16 2 183 89 0
## 12 25 1 4 0 23 5 252 944 0
## 16 36 2 9 6 49 9 818 3396 1
train_data_bank$default <- as.factor(train_data_bank$default)
test_data_bank$default <- as.factor(test_data_bank$default)
Membuat Model Random Forest dengan data yang digunakan adalah Data Peminjaman Bank.
rf_model <- randomForest(default ~ age + ed + employ + address + income + debtinc + creddebt + othdebt,
data = train_data_bank, ntree = 100)
rf_model
##
## Call:
## randomForest(formula = default ~ age + ed + employ + address + income + debtinc + creddebt + othdebt, data = train_data_bank, ntree = 100)
## Type of random forest: classification
## Number of trees: 100
## No. of variables tried at each split: 2
##
## OOB estimate of error rate: 20.18%
## Confusion matrix:
## 0 1 class.error
## 0 379 30 0.07334963
## 1 83 68 0.54966887
rf_pred_train <- predict(rf_model, train_data_bank)
head(rf_pred_train)
## 127 495 528 679 493 54
## 1 1 0 0 1 0
## Levels: 0 1
rf_pred_test <- predict(rf_model, test_data_bank)
head(rf_pred_test)
## 4 8 10 11 12 16
## 0 0 1 0 0 0
## Levels: 0 1
# Evaluasi Random Forest - Data Training
compare_train_rf <- data.frame(
"Y aktual" = train_data_bank$default,
"Y prediksi" = rf_pred_train,
"Keterangan" = ifelse(train_data_bank$default == rf_pred_train, "BENAR", "SALAH")
)
# Evaluasi Random Forest - Data Testing
compare_test_rf <- data.frame(
"Y aktual" = test_data_bank$default,
"Y prediksi" = rf_pred_test,
"Keterangan" = ifelse(test_data_bank$default == rf_pred_test, "BENAR", "SALAH")
)
head(compare_train_rf)
## Y.aktual Y.prediksi Keterangan
## 127 1 1 BENAR
## 495 1 1 BENAR
## 528 0 0 BENAR
## 679 0 0 BENAR
## 493 1 1 BENAR
## 54 0 0 BENAR
head(compare_test_rf)
## Y.aktual Y.prediksi Keterangan
## 4 0 0 BENAR
## 8 0 0 BENAR
## 10 0 1 SALAH
## 11 0 0 BENAR
## 12 0 0 BENAR
## 16 1 0 SALAH
# Training
confusionMatrix(rf_pred_train, train_data_bank$default, positive = "1")
## Confusion Matrix and Statistics
##
## Reference
## Prediction 0 1
## 0 409 0
## 1 0 151
##
## Accuracy : 1
## 95% CI : (0.9934, 1)
## No Information Rate : 0.7304
## P-Value [Acc > NIR] : < 2.2e-16
##
## Kappa : 1
##
## Mcnemar's Test P-Value : NA
##
## Sensitivity : 1.0000
## Specificity : 1.0000
## Pos Pred Value : 1.0000
## Neg Pred Value : 1.0000
## Prevalence : 0.2696
## Detection Rate : 0.2696
## Detection Prevalence : 0.2696
## Balanced Accuracy : 1.0000
##
## 'Positive' Class : 1
##
# Testing
confusionMatrix(rf_pred_test, test_data_bank$default, positive = "1")
## Confusion Matrix and Statistics
##
## Reference
## Prediction 0 1
## 0 99 18
## 1 9 14
##
## Accuracy : 0.8071
## 95% CI : (0.7319, 0.8689)
## No Information Rate : 0.7714
## P-Value [Acc > NIR] : 0.1834
##
## Kappa : 0.3931
##
## Mcnemar's Test P-Value : 0.1237
##
## Sensitivity : 0.4375
## Specificity : 0.9167
## Pos Pred Value : 0.6087
## Neg Pred Value : 0.8462
## Prevalence : 0.2286
## Detection Rate : 0.1000
## Detection Prevalence : 0.1643
## Balanced Accuracy : 0.6771
##
## 'Positive' Class : 1
##
Interpretasi :
Model Random Forest menghasilkan akurasi sebesar 80,71%, namun tidak berbeda signifikan dari No Information Rate (p-value = 0,183). Nilai Kappa sebesar 0,3931 menunjukkan tingkat kesepakatan sedang. Model memiliki specificity tinggi (0,9167) tetapi sensitivity rendah (0,4375), yang menunjukkan bahwa model lebih baik dalam mengklasifikasikan kelas negatif dibandingkan kelas positif. Secara keseluruhan, performa model cukup baik, namun masih kurang optimal dalam mendeteksi kelas positif. Dibandingkan Decision Tree dan SVM, Random Forest memiliki akurasi sedikit lebih rendah dan tidak menunjukkan peningkatan signifikan, terutama pada kemampuan mendeteksi kelas positif.
#1.5 Hasil Perbandingan Setiap Model
# Samakan level faktor pada prediksi dan data asli
ANNpred_test <- factor(ANNpred_test, levels = c("0", "1"))
test_data_bank$default <- factor(test_data_bank$default, levels = c("0", "1"))
cm_ANN <- confusionMatrix(ANNpred_test, test_data_bank$default, positive = "1")
cm_SVM <- confusionMatrix(SVMpred_test, test_data_bank$default, positive = "1")
cm_TREE <- confusionMatrix(tree_pred_test, test_data_bank$default, positive = "1")
cm_RF <- confusionMatrix(rf_pred_test, test_data_bank$default, positive = "1")
# Buat fungsi untuk ambil metrik
ambil_metrik <- function(cm, nama_model) {
precision <- cm$byClass["Pos Pred Value"]
recall <- cm$byClass["Sensitivity"]
f1 <- 2 * (precision * recall) / (precision + recall)
return(data.frame(
Model = nama_model,
Akurasi = round(cm$overall["Accuracy"], 4),
Presisi = round(precision, 4),
Recall = round(recall, 4),
F1_Score = round(f1, 4)
))
}
# Gabungkan hasil semua model
hasil_perbandingan <- rbind(
ambil_metrik(cm_ANN, "ANN"),
ambil_metrik(cm_SVM, "SVM"),
ambil_metrik(cm_TREE, "Decision Tree"),
ambil_metrik(cm_RF, "Random Forest")
)
rownames(hasil_perbandingan) <- NULL
# Tampilkan tabel
knitr::kable(hasil_perbandingan, caption = "Perbandingan Kinerja Model pada Data Testing")
| Model | Akurasi | Presisi | Recall | F1_Score |
|---|---|---|---|---|
| ANN | 0.7214 | 0.4340 | 0.7188 | 0.5412 |
| SVM | 0.8143 | 0.6250 | 0.4688 | 0.5357 |
| Decision Tree | 0.8143 | 0.6364 | 0.4375 | 0.5185 |
| Random Forest | 0.8071 | 0.6087 | 0.4375 | 0.5091 |
Berdasarkan evaluasi pada data testing, SVM dan Decision Tree menunjukkan akurasi tertinggi (81,43%), diikuti oleh Random Forest (80,71%) dan ANN (72,14%). Namun, ketika mempertimbangkan keseimbangan antara precision dan recall melalui F1-Score, SVM memberikan performa terbaik (0,5357), sehingga dipilih sebagai model yang paling optimal. Meskipun demikian, seluruh model menunjukkan recall yang relatif rendah, yang mengindikasikan keterbatasan dalam mendeteksi kelas positif. Hal ini penting secara praktis karena kesalahan dalam mendeteksi kasus positif dapat berdampak lebih besar dibandingkan kesalahan pada kelas negatif, tergantung konteks aplikasi. Temuan ini mengindikasikan adanya potensi class imbalance, sehingga model cenderung bias terhadap kelas mayoritas. Oleh karena itu, peningkatan performa dapat dilakukan melalui pendekatan seperti resampling (SMOTE/undersampling), penyesuaian threshold, atau cost-sensitive learning untuk meningkatkan kemampuan deteksi kelas positif.
Secara keseluruhan, SVM dipilih sebagai model terbaik dalam studi kasus ini karena memberikan trade-off performa yang paling seimbang, namun masih memerlukan optimasi lebih lanjut agar lebih robust.