Analisis Klasifikasi

Author

Bagus Sartono dan M. Rizky Nurhambali

Ilustrasi Kasus

Tim analisis data di sebuah bank menggunakan German Credit Data untuk membedakan antara kelompok berisiko tinggi dan kelompok berisiko rendah. Selain itu, ingin diketahui metode terbaik dalam memprediksi seseorang memiliki risiko tinggi atau rendah. Penelitian ini penting untuk memberikan gambaran kepada manajemen bank dan tim pemasaran untuk menghindari kredit macet.

Tim analisis data kemudian memutuskan akan menggunakan analisis klasifikasi dengan dataset yang bersumber pada:

Hofmann, H. (1994). Statlog (German Credit Data) [Dataset]. UCI Machine Learning Repository. https://doi.org/10.24432/C5NC77.

Dataset ini mengklasifikasikan orang-orang yang dijelaskan oleh serangkaian atribut atau peubah penjelas sebagai risiko kredit baik atau buruk. Terdapat 700 sampel yang tergolong risiko kredit baik dan 300 sampel tergolong risiko kredit macet. Terdapat 20 peubah penjelas yang diukur dalam German Credit Data, termasuk 7 peubah penjelas numerik dan 13 peubah penjelas kategorik sebagai berikut.

Nama Variabel Tipe Variabel Deskripsi
class Kategorik Status Kredit
checking_status Kategorik Rekening Koran
duration Numerik Durasi Kredit
credit_history Kategorik Riwayat Kredit
purpose Kategorik Tujuan Kredit
credit_amount Numerik Jumlah Kredit
savings_status Kategorik Rekening Tabungan/Obligasi
employment Kategorik Lama Bekerja
installment_commitment Numerik Tingkat angsuran dalam persentase pendapatan yang dapat disisihkan
personal_status Kategorik Jenis Kelamin dan Status
other_parties Kategorik Debitur Lain
residence_since Numerik Lama tinggal di alamat sekarang
property_magnitude Kategorik Properti atau Aset Paling Berharga
age Numerik Usia
other_payment_plans Kategorik Cicilan Lainnya
housing Kategorik Jenis tempat tinggal
existing_credits Numerik Jumlah Kredit yang ada di Bank ini
job Kategorik Pekerjaan
num_dependents Numerik Jumlah tanggungan
own_telephone Kategorik Langganan Telepon
foreign_worker Kategorik Status Pekerja Asing

Packages

Sebelum melakukan impor data, dilakukan pemanggilan packages untuk fungsi-fungsi yang digunakan sebagai berikut. Pemanggilan ini dilakukan di awal sehingga tidak perlu melakukan pemanggilan packages di tengah proses analisis data.

library(readxl) #untuk impor data ekstensi .xlsx dari penyimpanan lokal komputer
library(ggstatsplot) #untuk visualisasi data
Warning: package 'ggstatsplot' was built under R version 4.4.3
library(rsample)
Warning: package 'rsample' was built under R version 4.4.3
library(rpart) #untuk model pohon regresi
library(rpart.plot) #untuk visualisasi hasil pohon regresi
Warning: package 'rpart.plot' was built under R version 4.4.3
library(randomForest) #untuk model random forest
library(gbm) #untuk gradient boosting
library(neuralnet) #untuk neural network
Warning: package 'neuralnet' was built under R version 4.4.3
library(nnet)
library(caret)
Warning: package 'ggplot2' was built under R version 4.4.3
library(MLmetrics)
Warning: package 'MLmetrics' was built under R version 4.4.3

Data

Data yang digunakan dapat dilihat dan diunduh di sini.

Data dengan format .csv dapat diimpor melalui fungsi read.csv() dengan menyebutkan nama file beserta folder tempat menyimpannya.

 # Impor dari penyimpanan lokal
data <- read.csv("german_credit.csv", sep = ",")

Selanjutnya, kita dapat melihat informasi dasar dari variabel dan karakter dari variabel tersebut dengan str()

str(data)
'data.frame':   1000 obs. of  21 variables:
 $ checking_status       : chr  "'<0'" "'0<=X<200'" "'no checking'" "'<0'" ...
 $ duration              : int  6 48 12 42 24 36 24 36 12 30 ...
 $ credit_history        : chr  "'critical/other existing credit'" "'existing paid'" "'critical/other existing credit'" "'existing paid'" ...
 $ purpose               : chr  "radio/tv" "radio/tv" "education" "furniture/equipment" ...
 $ credit_amount         : int  1169 5951 2096 7882 4870 9055 2835 6948 3059 5234 ...
 $ savings_status        : chr  "'no known savings'" "'<100'" "'<100'" "'<100'" ...
 $ employment            : chr  "'>=7'" "'1<=X<4'" "'4<=X<7'" "'4<=X<7'" ...
 $ installment_commitment: int  4 2 2 2 3 2 3 2 2 4 ...
 $ personal_status       : chr  "'male single'" "'female div/dep/mar'" "'male single'" "'male single'" ...
 $ other_parties         : chr  "none" "none" "none" "guarantor" ...
 $ residence_since       : int  4 2 3 4 4 4 4 2 4 2 ...
 $ property_magnitude    : chr  "'real estate'" "'real estate'" "'real estate'" "'life insurance'" ...
 $ age                   : int  67 22 49 45 53 35 53 35 61 28 ...
 $ other_payment_plans   : chr  "none" "none" "none" "none" ...
 $ housing               : chr  "own" "own" "own" "'for free'" ...
 $ existing_credits      : int  2 1 1 1 2 1 1 1 1 2 ...
 $ job                   : chr  "skilled" "skilled" "'unskilled resident'" "skilled" ...
 $ num_dependents        : int  1 1 2 2 2 2 1 1 1 1 ...
 $ own_telephone         : chr  "yes" "none" "none" "none" ...
 $ foreign_worker        : chr  "yes" "yes" "yes" "yes" ...
 $ class                 : chr  "good" "bad" "good" "good" ...

Dapat kita lihat data yang digunakan terdiri atas 1000 baris dan 21 kolom. Baris menunjukkan jumlah observasi / sample, kolom menunjukkan variabel atau karakteristik dari observasi. Berdasarkan output tersebut, dapat diketahui bahwa ada variabel dalam bentuk integer (int) dan karakter (chr).

Eksplorasi Data

Kemudian, dilakukan eksplorasi data dengan:

  1. melihat proporsi kelas y

  2. melihat hubungan antara variabel respons dengan variabel prediktor dengan stacked barplot.

Proporsi Kelas Respons

Seperti yang disampaikan sebelumnya bahwa dataset memuat 1000 amatan. Sebaran banyaknya kredit macet dan kredit lancar dapat diperoleh dengan menampilkan frekuensi kejadiannya dengan cara berikut.

table(data$class)

 bad good 
 300  700 
prop.table(table(data$class))

 bad good 
 0.3  0.7 

Selain itu, dapat digunakan pula pie-chart seperti di bawah ini. Sebanyak 30% amatan adalah kredit macet, dan 70% sisanya kredit lancar.

ggpiestats(data = data,
           x = "class",
           label = "both",
           results.subtitle = FALSE )

Hubungan Variabel Prediktor dengan Kelancaran Kredit

Sebelum lebih jauh menyusun model klasifikasi, kita dapat mendeskripsikan secara sederhana bagaimana hubungan antara variabel penjelas dalam model dengan kelancaran kredit. Di bawah ini kita coba untuk melihat apakah ada keterkaitan variabel pekerjaan “job” dengan kelancaran kredit menggunakan stacked-bar chart.

ggbarstats(data = data,
            x="class",
            y="job",
            results.subtitle = FALSE)

Diagram di atas menunjukkan kredit macet cukup tinggi pada kelompok pekerja dengan kualifikasi tinggi (’high qualif/self emp/mgmt). Namun, besaran proporsi antar kelompok relatif sama sehingga dapat dianggap variabel ini kemungkunin besar tidak akan memberikan pengaruh pada model.

Selanjutnya, dilakukan ekplorasi yang sama untuk riwayat kredit (credit_history) sebagai berikut.

ggbarstats(data = data,
            x="class",
            y="credit_history",
            results.subtitle = FALSE)

Diagram di atas menunjukkan ada perbedaan cukup tinggi untuk masing-masing riwayat kredit. Besaran proporsi antar kelompok yang relatif berbeda mengindikasikan variabel ini kemungkunin besar memberikan pengaruh pada model.

Kemudian, untuk variabel numerik seperti umur, dapat dikelompokkan sebagai berikut untuk mempermudah visualisasi.

subs = data
subs$age = ifelse(data$age <= 30, "<=30", ifelse(data$age <= 40, "31-40", 
                  ifelse(data$age <= 50, "41-50", ">50")))
ggbarstats(data = subs,
            x="class",
            y="age",
            results.subtitle = FALSE)

Berdasarkan gambar, dapat diketahui kredit macet kebanyakan terjadi pada seseorang dengan umur di bawah 30.

Selain itu, dapat dibuat plot perbandingan masing-masing variabel per kelas baik kategorik maupun numerik dengan cara berikut.

#variabel kategorik
DataExplorer::plot_bar(data = data,by = "class",
             ggtheme = theme_classic(),
         ncol = 2)

#variabel numerik
DataExplorer::plot_boxplot(data = data,by = "class",
             geom_boxplot_args = list(fill="#03A9F4"),
             ggtheme = theme_classic())

Pembagian Data

Sebelum melakukan pemodelan, dilakukan pembagian data menjadi data train dan data test. Data train digunakan untuk membangun model, sementara data test digunakan untuk mengevaluasi model. Pada kesempatan ini, pembagian data train dan data test akan menggunakan prinsip Pareto dengan perbandingan data train dan data test sebesar 80:20.

Berikut ini adalah perintah/program untuk melakukan pemisahan data secara acak berstrata untuk menjamin persentase nasabah yang berlangganan di data train dan data test relatif sama. Namun, sebelum itu juga dilakukan pengubahan nilai menjadi 1 (untuk bad) dan 0 (untuk good)

#data$class = relevel(data$class, ref = "good")
data$class = ifelse(data$class == "bad", 1, 0)
set.seed(4321) #digunakan agar dapat diulang dan menghasilkan hasil yang sama
define_split <- initial_split(data = data,
                              prop = 0.8,
                              strata = "class")

train <- training(define_split)
test <- testing(define_split)
dim(train)
[1] 800  21
prop.table(table(train$class))

  0   1 
0.7 0.3 
dim(test)
[1] 200  21
prop.table(table(test$class))

  0   1 
0.7 0.3 

Berdasarkan output di atas, diperoleh bahwa data latih berisi 800 amatan, sedangkan data uji berisi 200 amatan. Proporsi kredit macet di kedua dataset tersebut relatif sama yaitu 30%.

Regresi Logistik

Pemodelan

Model klasifikasi pertama yang disusun adalah regresi logistik. Model ini menggunakan variabel class sebagai variabel respon.

Fungsi di R yang bisa digunakan adalah glm() dengan opsi family="binomial".

reglog.model = glm(class ~ foreign_worker + credit_history + credit_amount + age + 
                     installment_commitment + housing + num_dependents + own_telephone + 
                     property_magnitude + savings_status + checking_status + purpose, 
                   data=train, family="binomial"(link = "logit"))
reglog.model

Call:  glm(formula = class ~ foreign_worker + credit_history + credit_amount + 
    age + installment_commitment + housing + num_dependents + 
    own_telephone + property_magnitude + savings_status + checking_status + 
    purpose, family = binomial(link = "logit"), data = train)

Coefficients:
                                   (Intercept)  
                                     -1.566972  
                             foreign_workeryes  
                                      1.642618  
credit_history'critical/other existing credit'  
                                     -1.784311  
            credit_history'delayed previously'  
                                     -1.224721  
                 credit_history'existing paid'  
                                     -1.001765  
           credit_history'no credits/all paid'  
                                     -0.072889  
                                 credit_amount  
                                      0.000177  
                                           age  
                                     -0.016940  
                        installment_commitment  
                                      0.351943  
                                    housingown  
                                      0.321985  
                                   housingrent  
                                      0.601920  
                                num_dependents  
                                      0.040496  
                              own_telephoneyes  
                                     -0.532473  
         property_magnitude'no known property'  
                                      0.611017  
               property_magnitude'real estate'  
                                     -0.431454  
                         property_magnitudecar  
                                      0.030119  
                        savings_status'>=1000'  
                                     -1.104227  
                    savings_status'100<=X<500'  
                                     -0.176879  
                   savings_status'500<=X<1000'  
                                     -0.530629  
              savings_status'no known savings'  
                                     -0.780802  
                        checking_status'>=200'  
                                     -1.200469  
                     checking_status'0<=X<200'  
                                     -0.350614  
                  checking_status'no checking'  
                                     -1.526454  
                              purpose'new car'  
                                      0.435475  
                             purpose'used car'  
                                     -1.070490  
                               purposebusiness  
                                      0.081435  
                              purposeeducation  
                                      0.618671  
                    purposefurniture/equipment  
                                     -0.348866  
                                  purposeother  
                                     -0.449657  
                               purposeradio/tv  
                                     -0.454599  
                                purposerepairs  
                                      0.063904  
                             purposeretraining  
                                     -1.765454  

Degrees of Freedom: 799 Total (i.e. Null);  768 Residual
Null Deviance:      977.4 
Residual Deviance: 750.3    AIC: 814.3

Koefisien

Untuk mengeluarkan dugaan parameter model, dapat memanggil objek yang digunakan sebagai tempat menyimpan model, yaitu reg.model . Namun, apabila ingin lebih jelas mengetahui informasi dari model yang tidak terbatas pada dugaan parameter, gunakan fungsi summary() seperti berikut.

summary(reglog.model)

Call:
glm(formula = class ~ foreign_worker + credit_history + credit_amount + 
    age + installment_commitment + housing + num_dependents + 
    own_telephone + property_magnitude + savings_status + checking_status + 
    purpose, family = binomial(link = "logit"), data = train)

Coefficients:
                                                 Estimate Std. Error z value
(Intercept)                                    -1.567e+00  1.375e+00  -1.140
foreign_workeryes                               1.643e+00  6.985e-01   2.352
credit_history'critical/other existing credit' -1.784e+00  4.746e-01  -3.760
credit_history'delayed previously'             -1.225e+00  5.384e-01  -2.275
credit_history'existing paid'                  -1.002e+00  4.462e-01  -2.245
credit_history'no credits/all paid'            -7.289e-02  6.101e-01  -0.119
credit_amount                                   1.770e-04  3.779e-05   4.684
age                                            -1.694e-02  9.066e-03  -1.868
installment_commitment                          3.519e-01  9.037e-02   3.894
housingown                                      3.220e-01  4.713e-01   0.683
housingrent                                     6.019e-01  5.022e-01   1.199
num_dependents                                  4.050e-02  2.572e-01   0.157
own_telephoneyes                               -5.325e-01  2.077e-01  -2.564
property_magnitude'no known property'           6.110e-01  4.312e-01   1.417
property_magnitude'real estate'                -4.315e-01  2.688e-01  -1.605
property_magnitudecar                           3.012e-02  2.479e-01   0.121
savings_status'>=1000'                         -1.104e+00  5.490e-01  -2.011
savings_status'100<=X<500'                     -1.769e-01  3.113e-01  -0.568
savings_status'500<=X<1000'                    -5.306e-01  4.597e-01  -1.154
savings_status'no known savings'               -7.808e-01  2.734e-01  -2.856
checking_status'>=200'                         -1.200e+00  4.316e-01  -2.781
checking_status'0<=X<200'                      -3.506e-01  2.312e-01  -1.516
checking_status'no checking'                   -1.526e+00  2.456e-01  -6.214
purpose'new car'                                4.355e-01  7.548e-01   0.577
purpose'used car'                              -1.070e+00  8.238e-01  -1.300
purposebusiness                                 8.144e-02  8.018e-01   0.102
purposeeducation                                6.187e-01  8.315e-01   0.744
purposefurniture/equipment                     -3.489e-01  7.608e-01  -0.459
purposeother                                   -4.497e-01  1.038e+00  -0.433
purposeradio/tv                                -4.546e-01  7.513e-01  -0.605
purposerepairs                                  6.390e-02  9.152e-01   0.070
purposeretraining                              -1.765e+00  1.371e+00  -1.288
                                               Pr(>|z|)    
(Intercept)                                     0.25433    
foreign_workeryes                               0.01869 *  
credit_history'critical/other existing credit'  0.00017 ***
credit_history'delayed previously'              0.02293 *  
credit_history'existing paid'                   0.02476 *  
credit_history'no credits/all paid'             0.90490    
credit_amount                                  2.81e-06 ***
age                                             0.06170 .  
installment_commitment                         9.84e-05 ***
housingown                                      0.49450    
housingrent                                     0.23071    
num_dependents                                  0.87490    
own_telephoneyes                                0.01035 *  
property_magnitude'no known property'           0.15651    
property_magnitude'real estate'                 0.10848    
property_magnitudecar                           0.90331    
savings_status'>=1000'                          0.04430 *  
savings_status'100<=X<500'                      0.56985    
savings_status'500<=X<1000'                     0.24841    
savings_status'no known savings'                0.00429 ** 
checking_status'>=200'                          0.00542 ** 
checking_status'0<=X<200'                       0.12947    
checking_status'no checking'                   5.16e-10 ***
purpose'new car'                                0.56400    
purpose'used car'                               0.19376    
purposebusiness                                 0.91910    
purposeeducation                                0.45685    
purposefurniture/equipment                      0.64658    
purposeother                                    0.66490    
purposeradio/tv                                 0.54511    
purposerepairs                                  0.94433    
purposeretraining                               0.19784    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 977.38  on 799  degrees of freedom
Residual deviance: 750.32  on 768  degrees of freedom
AIC: 814.32

Number of Fisher Scoring iterations: 5

Output dari ringkasan model terdiri atas fungsi yang dimasukkan seperti koefisien regresi dan hasil uji-z, serta kebaikan model yang ditunjukkan dengan AIC.

Berdasarkan output di atas dapat dilihat bahwa:

  • foreign_workeryes memiliki koefisien positif, yang berarti bahwa pekerja asing memiliki peluang/resiko kredit macet tinggi

  • credit_amount memiliki koefisien positif, yang berarti bahwa semakin tinggi jumlah kredit seseorang maka peluang/resiko kredit macetnya akan semakin membesar

  • age memiliki koefisien negatif, yang berarti bahwa semakin tua seseorang maka peluang/resiko kredit macetnya akan semakin mengecil

Selanjutnya, pada hasil uji statistik, dapat dilihat bahwa status pekerja asing, jumlah kredit, dan umur berpengaruh signifikan. Akan tetapi, pada riwayat kredit terdapat kategori yang tidak signifikan, yaitu pada “no credits/all paid” sementara kategori lainnya signifikan sehingga untuk memastikan signifikansinya digunakan Analysis of Deviance sebagai berikut.

anodev = car::Anova(reglog.model, type = 3)
anodev
Analysis of Deviance Table (Type III tests)

Response: class
                       LR Chisq Df Pr(>Chisq)    
foreign_worker            7.317  1  0.0068321 ** 
credit_history           25.766  4  3.527e-05 ***
credit_amount            23.106  1  1.533e-06 ***
age                       3.583  1  0.0583845 .  
installment_commitment   15.934  1  6.559e-05 ***
housing                   1.979  2  0.3718317    
num_dependents            0.025  1  0.8750244    
own_telephone             6.732  1  0.0094680 ** 
property_magnitude        7.014  3  0.0714573 .  
savings_status           12.702  4  0.0128268 *  
checking_status          48.133  3  1.995e-10 ***
purpose                  29.086  9  0.0006268 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Berdasarkan output, credit_history berpengaruh signifikan terhadap kejadian kredit macet. Selain itu, variabel yang memiliki pengaruh ditandakan dengan bintang (*), sementara jika tidak berpengaruh maka tanda bintang tidak ada.

Evaluasi Model

Selanjutnya dilakukan evaluasi model dengan melakukan prediksi variabel respon pada data test. Untuk melakukan prediksi gunakan fungsi predict() . Berbeda dari model regresi linear, pada regresi logistik gunakan type=response .

Tahapan yang dilakukan kira-kira adalah:

  1. melakukan prediksi menggunakan model regresi logistik yang telah didapatkan –> hasil prediksi berupa peluang terjadinya kejadian respon (dalam kasus ini adalah kredit macet)
  2. melakukan pengkelasan nilai prediksi peluang/resiko kredit macet. Jika prediksi peluangnya di atas 0.5 maka disimpulkan diprediksi kredit macet, jika kurang dari 0.5 disimpulkan kredit lancar
  3. membandingkan kelas prediksi dengan kelas aktual
  4. menghitung persentase ketepatan hasil prediksi dengan ukuran akurasi, sensitivity, atau specificity.
library(caret)
p.pred_test_reglog <-  predict(reglog.model,newdata = test, type='response')
pred_test_reglog = ifelse(p.pred_test_reglog < 0.5, 0, 1)
confusionMatrix(as.factor(pred_test_reglog), as.factor(test$class), positive="1")
Confusion Matrix and Statistics

          Reference
Prediction   0   1
         0 124  33
         1  16  27
                                          
               Accuracy : 0.755           
                 95% CI : (0.6894, 0.8129)
    No Information Rate : 0.7             
    P-Value [Acc > NIR] : 0.05059         
                                          
                  Kappa : 0.3653          
                                          
 Mcnemar's Test P-Value : 0.02227         
                                          
            Sensitivity : 0.4500          
            Specificity : 0.8857          
         Pos Pred Value : 0.6279          
         Neg Pred Value : 0.7898          
             Prevalence : 0.3000          
         Detection Rate : 0.1350          
   Detection Prevalence : 0.2150          
      Balanced Accuracy : 0.6679          
                                          
       'Positive' Class : 1               
                                          

Untuk menyimpan nilai seperti akurasi, sensitivitas, dan spesifisitas dapat menggunakan packages MLmetrics.

acc_reglog <- Accuracy(as.factor(pred_test_reglog), as.factor(test$class))
sen_reglog <- Sensitivity(as.factor(pred_test_reglog), as.factor(test$class))
spe_reglog <- Specificity(as.factor(pred_test_reglog), as.factor(test$class))

Performa model klasifikasi dapat direpresentasikan dalam sebuah grafik, yaitu kurva receiver operating characteristic (ROC) yang menggambarkan hubungan sensitivitas (pada sumbu y) dengan 1-spesifisitas (pada sumbu x). Pembuatan kurva ROC dapat dilakukan dengan

library(PRROC)
Warning: package 'PRROC' was built under R version 4.4.3
Loading required package: rlang
Warning: package 'rlang' was built under R version 4.4.3
roc_curve_reglog <- roc.curve(weights.class0 =  test$class, scores.class0 = pred_test_reglog, curve = TRUE)
plot(roc_curve_reglog, color = FALSE)

library(precrec)
Warning: package 'precrec' was built under R version 4.4.3
precrec_reglog <- evalmod(scores = pred_test_reglog, labels = test$class)
autoplot(precrec_reglog)

Luas area di bawah kurva ROC dinyatakan dalam metrik area under curve (AUC) yang menunjukkan performal model, di mana semakin mendekati 1 maka kemampuan model semakin baik.

Nilai di bawah kurva ROC dapat disimpan dengan cara berikut.

AUC_reglog <- AUC(as.factor(pred_test_reglog), as.factor(test$class))
AUC_reglog
[1] 0.6678571

CART

Pemodelan

Untuk melakukan pemodelan dengan pohon klasifikasi, digunakan fungsi rpart() dengan memasukkan ekspresi method="class". Apabila fungsi tersebut hanya menggunakan input berupa formula dan data, maka fungsi tersebut akan menjalankan fungsi default pada rpart.control .

class.tree <- rpart(class ~ foreign_worker + credit_history + credit_amount + age + 
                     installment_commitment + housing + num_dependents + own_telephone + 
                     property_magnitude + savings_status + checking_status + purpose, 
                    data = train, method = "class",
                  control = rpart.control(minsplit = 20, 
                                          minbucket = round(20/3), 
                                          cp = 0.01,
                                          maxcompete = 4, 
                                          maxsurrogate = 5, 
                                          usesurrogate = 2, 
                                          xval = 10,
                                          surrogatestyle = 0, 
                                          maxdepth = 30))
class.tree
n= 800 

node), split, n, loss, yval, (yprob)
      * denotes terminal node

  1) root 800 240 0 (0.70000000 0.30000000)  
    2) checking_status='>=200','no checking' 361  48 0 (0.86703601 0.13296399) *
    3) checking_status='<0','0<=X<200' 439 192 0 (0.56264237 0.43735763)  
      6) property_magnitude='real estate' 121  33 0 (0.72727273 0.27272727)  
       12) age>=31.5 60   9 0 (0.85000000 0.15000000) *
       13) age< 31.5 61  24 0 (0.60655738 0.39344262)  
         26) savings_status='>=1000','100<=X<500','500<=X<1000' 9   0 0 (1.00000000 0.00000000) *
         27) savings_status='<100','no known savings' 52  24 0 (0.53846154 0.46153846)  
           54) credit_amount< 1217 20   4 0 (0.80000000 0.20000000) *
           55) credit_amount>=1217 32  12 1 (0.37500000 0.62500000)  
            110) credit_amount>=2128 16   6 0 (0.62500000 0.37500000) *
            111) credit_amount< 2128 16   2 1 (0.12500000 0.87500000) *
      7) property_magnitude='life insurance','no known property',car 318 159 0 (0.50000000 0.50000000)  
       14) credit_history='critical/other existing credit','delayed previously','existing paid' 274 125 0 (0.54379562 0.45620438)  
         28) credit_amount< 8015.5 245 102 0 (0.58367347 0.41632653)  
           56) purpose='used car',furniture/equipment,other,retraining 87  24 0 (0.72413793 0.27586207) *
           57) purpose='domestic appliance','new car',business,education,radio/tv,repairs 158  78 0 (0.50632911 0.49367089)  
            114) credit_amount>=1007 137  62 0 (0.54744526 0.45255474)  
              228) installment_commitment< 1.5 11   1 0 (0.90909091 0.09090909) *
              229) installment_commitment>=1.5 126  61 0 (0.51587302 0.48412698)  
                458) age>=25.5 97  41 0 (0.57731959 0.42268041)  
                  916) property_magnitude='life insurance',car 72  25 0 (0.65277778 0.34722222) *
                  917) property_magnitude='no known property' 25   9 1 (0.36000000 0.64000000) *
                459) age< 25.5 29   9 1 (0.31034483 0.68965517) *
            115) credit_amount< 1007 21   5 1 (0.23809524 0.76190476) *
         29) credit_amount>=8015.5 29   6 1 (0.20689655 0.79310345) *
       15) credit_history='all paid','no credits/all paid' 44  10 1 (0.22727273 0.77272727) *

Pemanggilan objek class.tree akan menampilkan pohon yang terbentuk. Pada partisi pertama, terlihat penggunaan variabel checking status. Namun, untuk lebih mempermudah melihat pohon yang terbentu, dapat menggunakan fungsi rpart.plot() sebagai berikut.

rpart.plot(class.tree, box.palette="RdBu", nn=TRUE)

Pohon yang terbentuk menunjukkan aturan-aturan keputusan dari model. Simpul akar dari pohon berada di bagian atas, dan simpul daun berada di bagian bawah. Setiap node diberi label dengan variabel yang digunakan untuk membagi data pada node tersebut dan nilai dari pembagian tersebut. Node daun menunjukkan nilai prediksi (1 sebagai “bad” atau kredit macet, 0 sebagai “good” atau kredit lancar), nilai desimal di bawahnya menunjukkan peluang untuk kredit macet, dan persentase menunjukkan persentase dari observasi yang tercakup di dalamnya.

Selain itu, dapat diketahui variabel penting dari pohon regresi dengan cara berikut.

class.tree$variable.importance
       checking_status          credit_amount         credit_history 
            36.7098732             21.4281887             12.9247248 
    property_magnitude                purpose         savings_status 
            12.5410552             10.8606813              8.3530702 
                   age installment_commitment                housing 
             8.1860006              6.7157831              1.9087904 
        num_dependents          own_telephone         foreign_worker 
             1.3409269              1.0000000              0.7108528 

Output menunjukkan bahwa variabel checking status, jumlah kredit, dan riwayat kredit menjadi tiga variabel penting.

Evaluasi Model

Evaluasi model dilakukan dengan cara yang sama dengan regresi logistik, yaitu dengan melakukan prediksi variabel respon pada data test. Untuk melakukan prediksi gunakan fungsi predict() , dengan type="prob". Kemudian diikuti dengan melihat keakuratan prediksi menggunakan confussion matrix.

p.pred_test_tree <-  predict(class.tree,newdata = test, type="prob")[,2]
pred_test_tree = ifelse(p.pred_test_tree < 0.5, 0, 1)
confusionMatrix(as.factor(pred_test_tree), as.factor(test$class), positive="1")
Confusion Matrix and Statistics

          Reference
Prediction   0   1
         0 126  40
         1  14  20
                                          
               Accuracy : 0.73            
                 95% CI : (0.6628, 0.7902)
    No Information Rate : 0.7             
    P-Value [Acc > NIR] : 0.1988496       
                                          
                  Kappa : 0.2663          
                                          
 Mcnemar's Test P-Value : 0.0006688       
                                          
            Sensitivity : 0.3333          
            Specificity : 0.9000          
         Pos Pred Value : 0.5882          
         Neg Pred Value : 0.7590          
             Prevalence : 0.3000          
         Detection Rate : 0.1000          
   Detection Prevalence : 0.1700          
      Balanced Accuracy : 0.6167          
                                          
       'Positive' Class : 1               
                                          

Selanjutnya dilakukan penyimpanan metrik akurasi, sensitivitas, dan spesifisitas.

acc_tree <- Accuracy(as.factor(pred_test_tree), as.factor(test$class))
sen_tree <- Sensitivity(as.factor(pred_test_tree), as.factor(test$class))
spe_tree <- Specificity(as.factor(pred_test_tree), as.factor(test$class))

Kemudian dilakukan pembuatan kurva ROC dapat dilakukan dengan cara berikut.

library(PRROC) 
roc_curve_tree <- roc.curve(weights.class0 =  test$class, scores.class0 = pred_test_tree, curve = TRUE) 
plot(roc_curve_tree, color = FALSE)

library(precrec) 
precrec_tree <- evalmod(scores = pred_test_tree, labels = test$class) 
ggplot2::autoplot(precrec_tree)

Luas area di bawah kurva ROC terlihat kecil dan hanya sedikit di atas 0,5 yang menunjukkan performa model masih belum baik.

Nilai di bawah kurva ROC dapat disimpan dengan cara berikut.

AUC_tree <- AUC(as.factor(pred_test_tree), as.factor(test$class)) 
AUC_tree
[1] 0.6166667

Random Forest

Pemodelan

Untuk melakukan pemodelan dengan random forest, digunakan fungsi randomForest() dengan type="classification". Apabila fungsi tersebut hanya menggunakan input berupa formula dan data, maka fungsi tersebut akan menjalankan fungsi default.

Perlu diperhatikan, input class yang sudah berupa angka akan terbaca numerik sehingga perlu dilakukan penyesuaian dengan menambahkan as.factor() .

rf <- randomForest(as.factor(class) ~ foreign_worker + credit_history + credit_amount + age + 
                     installment_commitment + housing + num_dependents + own_telephone + 
                     property_magnitude + savings_status + checking_status + purpose, 
                   data = train, ntree = 500, type = "classification")
rf

Call:
 randomForest(formula = as.factor(class) ~ foreign_worker + credit_history +      credit_amount + age + installment_commitment + housing +      num_dependents + own_telephone + property_magnitude + savings_status +      checking_status + purpose, data = train, ntree = 500, type = "classification") 
               Type of random forest: classification
                     Number of trees: 500
No. of variables tried at each split: 3

        OOB estimate of  error rate: 25.75%
Confusion matrix:
    0  1 class.error
0 506 54  0.09642857
1 152 88  0.63333333

Tingkat kesalahan Out-of-Bag (OOB) adalah 25,75% yang mencerminkan keakuratan model berdasarkan data yang tidak digunakan selama pelatihan. Tingkat kesalahan OOB yang lebih rendah menunjukkan kinerja yang lebih baik. Selanjutnya pada class.error menunjukkan kesalahan klasifikasi di setiap kelas.

Selanjutnya, apabila ingin menampilkan variabel penting, perlu dimasukkan ekspresi importance=TRUE .

rf <- randomForest(as.factor(class) ~ foreign_worker + credit_history + credit_amount + age + 
                     installment_commitment + housing + num_dependents + own_telephone + 
                     property_magnitude + savings_status + checking_status + purpose, 
                   data = train, ntree = 500, type = "classification", importance = TRUE)
rf$importance
                                  0             1 MeanDecreaseAccuracy
foreign_worker         0.0015599249  0.0016234055         0.0015725398
credit_history         0.0084150638  0.0148035122         0.0103342318
credit_amount          0.0137246185  0.0193418788         0.0154266341
age                    0.0092549081  0.0117272638         0.0099276175
installment_commitment 0.0112151082  0.0077890736         0.0102596671
housing                0.0020954830 -0.0049599559        -0.0000875016
num_dependents         0.0018963666  0.0022247282         0.0019677653
own_telephone          0.0044440465  0.0080427763         0.0055738768
property_magnitude     0.0056820106  0.0003267055         0.0040051392
savings_status         0.0007802916  0.0099559159         0.0035601752
checking_status        0.0195194801  0.0531892801         0.0296475739
purpose                0.0092153620  0.0031786302         0.0074269650
                       MeanDecreaseGini
foreign_worker                 3.128880
credit_history                26.641128
credit_amount                 71.790310
age                           53.817153
installment_commitment        21.904328
housing                       12.161714
num_dependents                 7.706751
own_telephone                 10.986993
property_magnitude            20.439454
savings_status                18.775429
checking_status               38.750922
purpose                       30.215666

Berdasarkan dua keluaran di atas, variabel checking status, jumlah kredit, riwayat kredit menjadi tiga variabel penting.

Evaluasi Model

Evaluasi model dilakukan dengan cara yang sama, yaitu dengan melakukan prediksi variabel respon pada data test. Namun, pada random forest, hasil prediksi sudah berupa kelas, yaitu 0 atau 1 sehingga tidak perlu dilakukan pengelompokkan secara manual seperti regresi logistik dan pohon klasifikasi. Untuk melakukan prediksi gunakan fungsi predict() dan diikuti dengan melihat keakuratan prediksi menggunakan confussion matrix.

pred_test_rf = predict(rf,newdata = test)
confusionMatrix(as.factor(pred_test_rf), as.factor(test$class), positive="1")
Confusion Matrix and Statistics

          Reference
Prediction   0   1
         0 127  41
         1  13  19
                                          
               Accuracy : 0.73            
                 95% CI : (0.6628, 0.7902)
    No Information Rate : 0.7             
    P-Value [Acc > NIR] : 0.1988496       
                                          
                  Kappa : 0.2582          
                                          
 Mcnemar's Test P-Value : 0.0002386       
                                          
            Sensitivity : 0.3167          
            Specificity : 0.9071          
         Pos Pred Value : 0.5938          
         Neg Pred Value : 0.7560          
             Prevalence : 0.3000          
         Detection Rate : 0.0950          
   Detection Prevalence : 0.1600          
      Balanced Accuracy : 0.6119          
                                          
       'Positive' Class : 1               
                                          

Selanjutnya dilakukan penyimpanan metrik akurasi, sensitivitas, dan spesifisitas.

acc_rf <- Accuracy(as.factor(pred_test_rf), as.factor(test$class))
sen_rf <- Sensitivity(as.factor(pred_test_rf), as.factor(test$class)) 
spe_rf <- Specificity(as.factor(pred_test_rf), as.factor(test$class))

Kemudian dilakukan pembuatan kurva ROC dapat dilakukan dengan cara berikut.

library(PRROC)  
roc_curve_rf <- roc.curve(weights.class0 =  test$class, scores.class0 = pred_test_rf, curve = TRUE)  
plot(roc_curve_rf, color = FALSE)

Luas area di bawah kurva ROC terlihat sedikit di atas 0,5 yang menunjukkan performa model masih belum baik.

Nilai di bawah kurva ROC dapat disimpan dengan cara berikut.

AUC_rf <- AUC(as.factor(pred_test_rf), as.factor(test$class))  
AUC_rf
[1] 0.6119048

Gradient Boosting

Pemodelan

Untuk melakukan pemodelan dengan gradient boosting, digunakan fungsi gbm() . Namun, untuk klasifikasi, tambahkan opsi distribution="bernoulli" . Apabila fungsi tersebut hanya menggunakan input berupa formula dan data, maka fungsi tersebut akan menjalankan fungsi default.

Perlu diperhatikan di sini, respons untuk pemodelan gbm() memerlukan input berupa numerik dan variabel kategoriknya harus dalam factor . Oleh karena itu, perlu dilakukan beberapa penyesuaian seperti berikut ini.

#cek bentuk dari variabel respons
is.numeric(train$class)
[1] TRUE
gbm.model <- gbm(class ~ as.factor(foreign_worker) + as.factor(credit_history) + credit_amount + age + 
                     installment_commitment + as.factor(housing) + num_dependents + as.factor(own_telephone) + 
                     as.factor(property_magnitude) + as.factor(savings_status) + as.factor(checking_status) + as.factor(purpose), 
                 data = train, distribution = "bernoulli")

Untuk melihat hasil pemodelan berupa peubah penting, gunakan summary() .

summary(gbm.model)

                                                        var    rel.inf
as.factor(checking_status)       as.factor(checking_status) 28.1049541
as.factor(credit_history)         as.factor(credit_history) 14.4339443
credit_amount                                 credit_amount 14.2486032
as.factor(purpose)                       as.factor(purpose) 12.7231731
age                                                     age  7.8027733
as.factor(savings_status)         as.factor(savings_status)  6.3545230
as.factor(property_magnitude) as.factor(property_magnitude)  6.2458427
installment_commitment               installment_commitment  5.5626797
as.factor(housing)                       as.factor(housing)  2.5513886
as.factor(own_telephone)           as.factor(own_telephone)  1.1792609
as.factor(foreign_worker)         as.factor(foreign_worker)  0.7928569
num_dependents                               num_dependents  0.0000000

Output akan menunjukkan variabel yang memiliki kontribusi besar dalam pemodelan. Berdasarkan output tersebut terdapat variabel checking status, jumlah kredit, riwayat kredit sebagai tiga peubah penting.

Evaluasi Model

Evaluasi model dilakukan dengan cara yang sama, yaitu dengan melakukan prediksi variabel respon pada data test. Untuk melakukan prediksi gunakan fungsi predict() dengan tahapan yang sama dengan regresi logistik dan pohon klasifikasi. Setelah itu, keakuratan prediksi dilihat menggunakan confussion matrix.

p.pred_test_gbm <-  predict(gbm.model,newdata = test)
pred_test_gbm = ifelse(p.pred_test_gbm < 0.5, 0, 1)
confusionMatrix(as.factor(pred_test_gbm), as.factor(test$class), positive="1")
Confusion Matrix and Statistics

          Reference
Prediction   0   1
         0 133  48
         1   7  12
                                          
               Accuracy : 0.725           
                 95% CI : (0.6576, 0.7856)
    No Information Rate : 0.7             
    P-Value [Acc > NIR] : 0.2455          
                                          
                  Kappa : 0.1864          
                                          
 Mcnemar's Test P-Value : 6.906e-08       
                                          
            Sensitivity : 0.2000          
            Specificity : 0.9500          
         Pos Pred Value : 0.6316          
         Neg Pred Value : 0.7348          
             Prevalence : 0.3000          
         Detection Rate : 0.0600          
   Detection Prevalence : 0.0950          
      Balanced Accuracy : 0.5750          
                                          
       'Positive' Class : 1               
                                          

Selanjutnya dilakukan penyimpanan metrik akurasi, sensitivitas, dan spesifisitas.

acc_gbm <- Accuracy(as.factor(pred_test_gbm), as.factor(test$class)) 
sen_gbm <- Sensitivity(as.factor(pred_test_gbm), as.factor(test$class))  
spe_gbm <- Specificity(as.factor(pred_test_gbm), as.factor(test$class))

Kemudian dilakukan pembuatan kurva ROC dapat dilakukan dengan cara berikut.

library(PRROC)   
roc_curve_gbm <- roc.curve(weights.class0 =  test$class, scores.class0 = pred_test_gbm, curve = TRUE)   
plot(roc_curve_gbm, color = FALSE)

precrec_gbm <- evalmod(scores = pred_test_gbm, labels = test$class)  
ggplot2::autoplot(precrec_gbm)

Luas area di bawah kurva ROC terlihat sedikit di atas 0,5 yang menunjukkan performa model masih belum baik.

Nilai di bawah kurva ROC dapat disimpan dengan cara berikut.

AUC_gbm <- AUC(as.factor(pred_test_gbm), as.factor(test$class))   
AUC_gbm
[1] 0.575

Support Vector Machine (SVM)

Pemodelan

Pemodelan SVM dilakukan dengan fungsi svm() pada package e1071 . Pemodelan klasifikasi SVM dilakukan dengan memberi ekpresi type="C-classification" . Selain itu, terdapat beberapa kernel yang dapat digunakan, seperti:

  • linear

  • polynomial

  • radial basis

  • sigmoid

Pada ilustrasi ini, digunakan kernel linear.

library(e1071)

Attaching package: 'e1071'
The following object is masked from 'package:rsample':

    permutations
svm.lin <- svm(class ~ foreign_worker + credit_history + credit_amount + age + 
                     installment_commitment + housing + num_dependents + own_telephone + 
                     property_magnitude + savings_status + checking_status + purpose, 
               data = train, type = "C-classification", kernel = "linear")
print(svm.lin)

Call:
svm(formula = class ~ foreign_worker + credit_history + credit_amount + 
    age + installment_commitment + housing + num_dependents + own_telephone + 
    property_magnitude + savings_status + checking_status + purpose, 
    data = train, type = "C-classification", kernel = "linear")


Parameters:
   SVM-Type:  C-classification 
 SVM-Kernel:  linear 
       cost:  1 

Number of Support Vectors:  439

Variabel penting hasil SVM dapat dicari dengan cara berikut.

coefficients <- t(svm.lin$coefs) %*% svm.lin$SV
importance <- abs(coefficients)
importance <- importance / max(importance)
importance_svm <- as.data.frame(t(data.frame(Importance = importance)))

#mengurutkan nilai variable importance
library(dplyr)

Attaching package: 'dplyr'
The following object is masked from 'package:neuralnet':

    compute
The following object is masked from 'package:randomForest':

    combine
The following objects are masked from 'package:stats':

    filter, lag
The following objects are masked from 'package:base':

    intersect, setdiff, setequal, union
importance_svm <- importance_svm %>% arrange(desc(V1))
head(importance_svm)
                                                                 V1
Importance.credit_history.critical.other.existing.credit. 1.0000000
Importance.checking_status.no.checking.                   0.7848407
Importance.checking_status...200.                         0.6618393
Importance.credit_history.delayed.previously.             0.6349689
Importance.credit_history.existing.paid.                  0.5407742
Importance.savings_status...1000.                         0.5173848

Evaluasi Model

Evaluasi model dilakukan dengan cara yang sama, yaitu dengan melakukan prediksi variabel respon pada data test. Namun, pada SVM, hasil prediksi sudah berupa kelas, yaitu 0 atau 1 sehingga tidak perlu dilakukan pengelompokkan secara manual. Untuk melakukan prediksi gunakan fungsi predict() dan diikuti dengan melihat keakuratan prediksi menggunakan confussion matrix.

pred_test_svm = predict(svm.lin,newdata = test)
confusionMatrix(as.factor(pred_test_svm), as.factor(test$class), positive="1")
Confusion Matrix and Statistics

          Reference
Prediction   0   1
         0 124  35
         1  16  25
                                          
               Accuracy : 0.745           
                 95% CI : (0.6787, 0.8039)
    No Information Rate : 0.7             
    P-Value [Acc > NIR] : 0.09344         
                                          
                  Kappa : 0.3325          
                                          
 Mcnemar's Test P-Value : 0.01172         
                                          
            Sensitivity : 0.4167          
            Specificity : 0.8857          
         Pos Pred Value : 0.6098          
         Neg Pred Value : 0.7799          
             Prevalence : 0.3000          
         Detection Rate : 0.1250          
   Detection Prevalence : 0.2050          
      Balanced Accuracy : 0.6512          
                                          
       'Positive' Class : 1               
                                          

Selanjutnya dilakukan penyimpanan metrik akurasi, sensitivitas, dan spesifisitas.

acc_svm <- Accuracy(as.factor(pred_test_svm), as.factor(test$class))  
sen_svm <- Sensitivity(as.factor(pred_test_svm), as.factor(test$class))   
spe_svm <- Specificity(as.factor(pred_test_svm), as.factor(test$class))

Kemudian dilakukan pembuatan kurva ROC dapat dilakukan dengan cara berikut.

library(PRROC)    
roc_curve_svm <- roc.curve(weights.class0 =  test$class, scores.class0 = pred_test_svm, curve = TRUE)    
plot(roc_curve_svm, color = FALSE)

Luas area di bawah kurva ROC terlihat sedikit di atas 0,5 yang menunjukkan performa model masih belum baik.

Nilai di bawah kurva ROC dapat disimpan dengan cara berikut.

AUC_svm <- AUC(as.factor(pred_test_svm), as.factor(test$class))    
AUC_svm
[1] 0.6511905

Perbandingan Metode

Setelah dilakukan berbagai pemodelan, dilakukan perbandingan metrik yang digunakan untuk menentukan model terbaik dengan cara sebagai berikut.

# membuat matrix dengan 4 kolom dan 6 baris
metrics_data <- matrix(c(acc_reglog, sen_reglog, spe_reglog, AUC_reglog,
                         acc_tree, sen_tree, spe_tree, AUC_tree,
                         acc_rf, sen_rf, spe_rf, AUC_rf,
                         acc_gbm, sen_gbm, spe_gbm, AUC_gbm,
                         acc_svm, sen_svm, spe_svm, AUC_svm), 
                       ncol=4, byrow=TRUE)

# mengubah nama kolom dan nama baris
colnames(metrics_data) <- c('Accuracy','Sensitivity', "Specificity", 'AUC')
rownames(metrics_data) <- c('Regresi Logistik','CART', 'Random Forest',
                            'Gradient Boosting', 'SVM')

as.table(metrics_data)
                   Accuracy Sensitivity Specificity       AUC
Regresi Logistik  0.7550000   0.7898089   0.6279070 0.6678571
CART              0.7300000   0.7590361   0.5882353 0.6166667
Random Forest     0.7300000   0.7559524   0.5937500 0.6119048
Gradient Boosting 0.7250000   0.7348066   0.6315789 0.5750000
SVM               0.7450000   0.7798742   0.6097561 0.6511905

Berdasarkan metrik yang digunakan, dapat dilihat bahwa regresi logistik dan SVM sebagai dua metode terbaik. Hal ini ditandakan dengan nilai metrik yang cukup tinggi di antara metode lainnya. Perlu menjadi perhatian, pada ilustrasi ini ada ketidakseimbangan kelas sehingga metrik evaluasi yang bisa manjadi fokus utama adalah AUC. Nilai AUC yang semakin tinggi menunjukkan performa metode semakin baik. Apabila nilai AUC mendekati 0,5, maka performal model seperti tebakan acak (random guessing).