Perbandingan Model Klasifikasi pada Data Pinjaman Bank

library(readxl)
library(dplyr)
library(ggplot2)
library(tidyverse)
library(tidyr)
library(nnet)
library(caret)
library(e1071)
library(rpart)
library(randomForest)
library(kernlab)

PENDAHULUAN

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.

IDENTIFIKASI DATA

Dataset yang digunakan merupakan data pinjaman bank dengan variabel sebagai berikut:

1.1 Model Artificial Neural Network (ANN)

# 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

Cleaning Data

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

Eksplorasi & Visualisasi Data

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

Spliting Data

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 ANN

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

Validasi

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"

Evaluasi

# 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

# 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.

1.2 Model Support Vector Machine (SVM)

Untuk memaikai model SVM (Support Vector Machine) maka harus memakai packages “nnet” dan “e1071”

Input Data

# 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

Cleaning Data

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

Eksplorasi & Visualisasi Data

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

Splitting Data/Membuat Data Training dan Data Testing

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 SVM

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.

Validasi

# 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

Evaluasi

# 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

# 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.

1.3 Model Decision Tree

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

Cleaning Data

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

Eksplorasi & Visualisasi Data

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

Splitting Data/Membuat Data Training dan Data Testing

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

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) *

Validasi

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

# 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

Confusion Matrix

# 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).

1.4 Model Random Forest

Untuk memaikai model Desicion Tree maka harus memakai packages “randomForest”

Input Data

# 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

Cleaning Data

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

Eksplorasi & Visualisasi Data

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

Splitting Data/Membuat Data Training dan Data Testing

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

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

Validasi

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

# 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

Confusion Matrix

# 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")
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

KESIMPULAN

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.