1 Introduction

1.1 Problem Statement

Sebuah lembaga perbankan di portugal sedang membuat layanan marketing baru berupa kampanye penjualan deposito berjangka dari panggilan telepon. Lembaga tersebut telah memiliki sejumlah data terkait yang berisi hasil penjualan dari telepon. sebagai seorang data analis kita diminta untuk membuat model yang dapat memprediksi klien yang berpotensi berlangganan deposito berjangka (variabel y).

1.2 Data’s Point of View

Berikut adalah tabel penjelasan variabel dari dataset :

No. Nama Variabel Tipe Data Kategori/Keterangan
1 Age Numerik Umur
2 Job Kategori Tipe Pekerjaan (admin, blue-collar, entrepreneur, housemaid, management, retired, self-employed, services, student, technician, unemployed, unknown)
3 Marital Kategori Status Perkawinan (divorced, married, single, unknown)
4 Education Kategori Pendidikan (basic.4y, basic.6y, basic.9y, high.school, illiterate, professional.course, university.degree, unknown)
5 Default Kategori Status Kredit Default (no, yes, unknown)
6 Housing Kategori Pemilikan Rumah (no, yes, unknown)
7 Loan Kategori Pinjaman Pribadi (no, yes, unknown)
8 Contact Kategori Jenis Komunikasi Kontak (cellular, telephone)
9 Month Kategori Bulan Terakhir Kontak (jan, feb, mar, …, nov, dec)
10 Day_of_week Kategori Hari Terakhir Kontak dalam Seminggu (mon, tue, wed, thu, fri)
11 Duration Numerik Durasi Terakhir Kontak, dalam detik
12 Campaign Numerik Jumlah Kontak yang Dilakukan selama Kampanye ini dan untuk Klien ini
13 Pdays Numerik Jumlah hari yang telah berlalu setelah klien terakhir dihubungi dari kampanye sebelumnya (999 berarti klien tidak pernah dihubungi sebelumnya)
14 Previous Numerik Jumlah kontak yang dilakukan sebelum kampanye ini dan untuk klien ini
15 Poutcome Kategori Hasil dari kampanye pemasaran sebelumnya (failure, nonexistent, success)
16 Emp.var.rate Numerik Tingkat variasi pekerjaan - indikator perempat tahun
17 Cons.price.idx Numerik Indeks harga konsumen - indikator bulanan
18 Cons.conf.idx Numerik Indeks kepercayaan konsumen - indikator bulanan
19 Euribor3m Numerik Tingkat euribor 3 bulan - indikator harian
20 Nr.employed Numerik Jumlah karyawan - indikator perempat tahun
21 y Kategori Apakah klien telah berlangganan deposito berjangka? (yes, no)

2 Data Cleanning

library(mlbench)
library(caTools) 
library(caret)
library(e1071)
library(rpart) 
library(randomForest) 
library(dplyr)
library(partykit)
library(naivebayes)
df <- read.csv("data_input/bank.csv", sep = ";")
rmarkdown::paged_table(df)
#periksa tipe data
glimpse(df)
#> Rows: 41,188
#> Columns: 21
#> $ age            <int> 56, 57, 37, 40, 56, 45, 59, 41, 24, 25, 41, 25, 29, 57,…
#> $ job            <chr> "housemaid", "services", "services", "admin.", "service…
#> $ marital        <chr> "married", "married", "married", "married", "married", …
#> $ education      <chr> "basic.4y", "high.school", "high.school", "basic.6y", "…
#> $ default        <chr> "no", "unknown", "no", "no", "no", "unknown", "no", "un…
#> $ housing        <chr> "no", "no", "yes", "no", "no", "no", "no", "no", "yes",…
#> $ loan           <chr> "no", "no", "no", "no", "yes", "no", "no", "no", "no", …
#> $ contact        <chr> "telephone", "telephone", "telephone", "telephone", "te…
#> $ month          <chr> "may", "may", "may", "may", "may", "may", "may", "may",…
#> $ day_of_week    <chr> "mon", "mon", "mon", "mon", "mon", "mon", "mon", "mon",…
#> $ duration       <int> 261, 149, 226, 151, 307, 198, 139, 217, 380, 50, 55, 22…
#> $ campaign       <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
#> $ pdays          <int> 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, …
#> $ previous       <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
#> $ poutcome       <chr> "nonexistent", "nonexistent", "nonexistent", "nonexiste…
#> $ emp.var.rate   <dbl> 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, …
#> $ cons.price.idx <dbl> 93.994, 93.994, 93.994, 93.994, 93.994, 93.994, 93.994,…
#> $ cons.conf.idx  <dbl> -36.4, -36.4, -36.4, -36.4, -36.4, -36.4, -36.4, -36.4,…
#> $ euribor3m      <dbl> 4.857, 4.857, 4.857, 4.857, 4.857, 4.857, 4.857, 4.857,…
#> $ nr.employed    <dbl> 5191, 5191, 5191, 5191, 5191, 5191, 5191, 5191, 5191, 5…
#> $ y              <chr> "no", "no", "no", "no", "no", "no", "no", "no", "no", "…

terlihat sejumlah variabel belum sesuai tipe datanya, yaitu job, martial, education, default, housing, loan contact, month, day_of_week, poutcome, y.

#ubah tipe data.
df <- df %>% mutate_at(.vars=c('job', 'marital', "education", "default", "housing", "loan", "contact", "month",  "day_of_week", "poutcome", 'y'), as.factor)
# Periksa Missing Values
colSums(is.na(df))
#>            age            job        marital      education        default 
#>              0              0              0              0              0 
#>        housing           loan        contact          month    day_of_week 
#>              0              0              0              0              0 
#>       duration       campaign          pdays       previous       poutcome 
#>              0              0              0              0              0 
#>   emp.var.rate cons.price.idx  cons.conf.idx      euribor3m    nr.employed 
#>              0              0              0              0              0 
#>              y 
#>              0

Tidak Terdapat missing values

3 Data Pre processing

4 Periksa proporsi kolom target

untuk mendapatkan model yang baik kita perlu memiliki data yang seimbang pada kelas target, sehingga model tidak hanya handal dalam menilai salah satu kelas. Pada kasus kita variabel target adalah apakah nasabah mau untuk berlangganan deposito berjangka atau tidak, yang dalam hal ini diwakili oleh kolom y pada dataset.

prop.table(table(df$y))
#> 
#>        no       yes 
#> 0.8873458 0.1126542

Terlihat bahwa dataset kita imbalance dimana proporsi untuk target yes jauh lebih besar dari target no.

4.1 Split dataset

Data splitting dilakukan dengan tujuan memisahkan dataset menjadi dua bagian: data pelatihan (train), data pengujian (test) dengan perbandingan 70%:30%. Proses pemilihan data secara acak dilakukan dengan menggunakan seed bernilai 123. Penggunaan seed ini penting untuk memastikan bahwa pengacakan data akan menghasilkan hasil yang konsisten. Setiap kali kita menggunakan nilai seed yang sama (misalnya, 123), pengacakan akan menghasilkan hasil yang sama, tetapi jika kita menggunakan nilai seed yang berbeda, hasil pengacakan akan berbeda, yang pada akhirnya dapat memengaruhi akurasi dan hasil analisis.

set.seed(123)  # Seed for reproducibility
train_indices <- createDataPartition(df$y, p = 0.7, list = FALSE)
train_data <- df[train_indices, ]
test_data <- df[-train_indices, ]

4.2 Downsampling

karena dataset kita cukup besar, maka akan dilakukan downsampling karena adanya imbalance pada variabel target.

RNGkind(sample.kind = "Rounding")
set.seed(123)

train_data <- downSample(x = train_data %>% select(-y),
                         y = train_data$y,
                         yname = "y")

prop.table(table(train_data$y))
#> 
#>  no yes 
#> 0.5 0.5

5 Modeling

5.1 Model Random Forrest

Kekurangan random forest adalah beban komputasinya yang amat besar dan lama.

Hal ini dapat dikurangi dengan menseleksi prediktor sehingga tidak terlalu banyak. Bila ditemukan jumlah kolom yang amat banyak, kita dapat menghapus kolom yang memiliki variansi mendekati nol (kurang informatif) dengan nearZeroVar() dari package caret.

5.1.1 Modeling

# feature selection menggunakan nearZeroVar
zero_var <- nearZeroVar(df) #fungsi untuk mencari kolom yang zero variance

# JANGAN DI-RUN 2X!!
df_rf <- df %>% select(-zero_var)
set.seed(123)  # Seed for reproducibility
train_indices <- createDataPartition(df_rf$y, p = 0.7, list = FALSE)
train_data_rf <- df_rf[train_indices, ]
test_data_rf <- df_rf[-train_indices, ]
RNGkind(sample.kind = "Rounding")
set.seed(123)

train_data_rf <- downSample(x = train_data_rf %>% select(-y),
                         y = train_data_rf$y,
                         yname = "y")

prop.table(table(train_data_rf$y))
#> 
#>  no yes 
#> 0.5 0.5
# set.seed(123)
# ctrl <- trainControl(method = "repeatedcv", # repeated k-fold cross validation, cv = kfold
#                      number = 5,
#                     repeats=3) # k-fold

# model_rf <- caret::train(y ~ .,  # formula model
#                    data = train_data_rf, # data yg digunakan
#                    method = "rf", # random forest
#                    trControl = ctrl,
#                    importance = T)

# rf_imp <- varImp(model_rf, scale = FALSE)

# saveRDS(model_rf, "model_rf.RDS")
model_rf <- readRDS("model_rf.RDS")
model_rf$finalModel
#> 
#> Call:
#>  randomForest(x = x, y = y, mtry = param$mtry, importance = ..1) 
#>                Type of random forest: classification
#>                      Number of trees: 500
#> No. of variables tried at each split: 27
#> 
#>         OOB estimate of  error rate: 10.93%
#> Confusion matrix:
#>       no  yes class.error
#> no  2738  510  0.15701970
#> yes  200 3048  0.06157635

Pada tahap Bootstrap sampling, terdapat data yang tidak digunakan dalam pembuatan model, ini yang disebut sebagai data Out-of-Bag (OOB). Model Random Forest akan menggunakan data OOB sebagai data untuk melakukan evaluasi dengan cara menghitung error (serupa dengan data test). Error inilah yang disebut OOB Error. Dalam kasus klasifikasi, OOB error merupakan persentase data OOB yang misklasifikasi

Nilai OOB Error pada model model_rf sebesar 10.93%. Dengan kata lain, akurasi model pada data OOB adalah 89.07%

5.1.2 Prediksi dan Evaluasi

prediksi_rf <- predict(object = model_rf,newdata = test_data_rf)
cm_rf <- confusionMatrix(data = prediksi_rf,reference = test_data_rf$y)$byClass
cm_rf
#>          Sensitivity          Specificity       Pos Pred Value 
#>            0.8389274            0.9310345            0.9896708 
#>       Neg Pred Value            Precision               Recall 
#>            0.4232528            0.9896708            0.8389274 
#>                   F1           Prevalence       Detection Rate 
#>            0.9080857            0.8873422            0.7444157 
#> Detection Prevalence    Balanced Accuracy 
#>            0.7521852            0.8849809

hasil akurasi model RF untuk data test adalah 89.07% sementara untuk data train adalah 88.46%, maka model dapat disimpulkan tidak overfitting.

5.2 Model Naive Bayes

5.2.1 Modeling

model_nb <- naive_bayes(y~., data=train_data)

5.2.2 Prediksi dan Evaluasi

prediksi_nb <- predict(object = model_nb,newdata = test_data, type = 'class')
cm_nb <- confusionMatrix(data = prediksi_nb,reference = test_data$y)$byClass
cm_nb
#>          Sensitivity          Specificity       Pos Pred Value 
#>            0.8277089            0.7614943            0.9647071 
#>       Neg Pred Value            Precision               Recall 
#>            0.3594439            0.9647071            0.8277089 
#>                   F1           Prevalence       Detection Rate 
#>            0.8909725            0.8873422            0.7344610 
#> Detection Prevalence    Balanced Accuracy 
#>            0.7613305            0.7946016

5.3 Model Decision tree

5.3.1 Modeling

model_dt <- ctree(formula = y ~.,
                 data = train_data)

5.3.2 Prediksi dan Evaluasi

prediksi_dt <- predict(object = model_dt,
                          newdata = test_data,
                          type = "response")

cm_dt <- confusionMatrix(data = prediksi_dt,
                reference = test_data$y)$byClass #data actual

cm_dt
#>          Sensitivity          Specificity       Pos Pred Value 
#>            0.8041773            0.9554598            0.9930172 
#>       Neg Pred Value            Precision               Recall 
#>            0.3825137            0.9930172            0.8041773 
#>                   F1           Prevalence       Detection Rate 
#>            0.8886761            0.8873422            0.7135804 
#> Detection Prevalence    Balanced Accuracy 
#>            0.7185983            0.8798185

6 Model Tuning

Karena kita ingin mengetahui seberapa akurat model kita dalam memprediksi apakah seorang pelanggan akan berlangganan deposito berjangka, kita sebaiknya mempertimbangkan presisi (precision) sebagai metrik utama:

Presisi (Precision) adalah metrik evaluasi dalam analisis klasifikasi yang mengukur sejauh mana prediksi positif yang dibuat oleh model adalah benar positif. Lebih tepatnya, presisi mengukur berapa persen dari prediksi positif yang benar-benar benar.

Rumus untuk menghitung presisi adalah:

\[Presisi = \frac{TP}{TP + FP}\]

Di mana: - TP (True Positive) adalah jumlah data yang benar-benar positif dan telah diprediksi dengan benar sebagai positif oleh model. - FP (False Positive) adalah jumlah data yang sebenarnya negatif tetapi salah diprediksi sebagai positif oleh model.

Dalam konteks ini, presisi akan memberikan gambaran tentang seberapa baik model dalam mengidentifikasi pelanggan yang benar-benar akan berlangganan deposito berjangka. Semakin tinggi nilai presisi, semakin baik model dalam menghindari kesalahan memprediksi pelanggan yang sebenarnya tidak akan berlangganan.

6.1 Random Forest

Dalam studi kasus ini, kita akan fokus pada penyesuaian dua parameter, yaitu mtry dan ntree, yang memiliki pengaruh berikut pada model random forest kita. Meskipun ada banyak parameter lain, dua parameter ini mungkin memiliki dampak terbesar pada akurasi akhir Anda.

Berikut penjelasan kedua parameter tersebut :

  • mtry: Jumlah variabel yang diambil secara acak sebagai kandidat pada setiap pemisahan (split).
  • ntree: Jumlah pohon yang akan dibangun.

6.1.1 Tuning RF Grid

Metode pertama yang dapat digunakan untuk tuning model RF adalah Grid Search. Setiap sumbu dari grid adalah parameter algoritma, dan titik-titik dalam grid adalah kombinasi khusus dari parameter-parameter tersebut. Karena kita hanya menyesuaikan satu parameter, maka pencarian grid ini merupakan pencarian linear melalui vektor nilai-nilai kandidat untuk parameter tersebut.

# Tuning model RF dengan grid search
# control <- trainControl(method="repeatedcv", 
#                         number=10, 
#                         repeats=3, 
#                         search="grid") # 10 fold cross validation, repeadted 3 kali.
# set.seed(123)
# tunegrid <- expand.grid(.mtry=c(1:15))
# rf_gridsearch <- train(y~., data=train_data_rf, method="rf", metric='accuracy', tuneGrid=tunegrid, trControl=control)
# print(rf_gridsearch)
# plot(rf_gridsearch)

# saveRDS(rf_gridsearch, "rf_gridsearch.RDS")

Dengan tambahan tanda ‘#’ di depan setiap baris, kode ini sekarang adalah komentar dan tidak akan dieksekusi saat dijalankan.

rf_gridsearch <- readRDS("rf_gridsearch.RDS")
rf_gridsearch$finalModel
#> 
#> Call:
#>  randomForest(x = x, y = y, mtry = param$mtry) 
#>                Type of random forest: classification
#>                      Number of trees: 500
#> No. of variables tried at each split: 13
#> 
#>         OOB estimate of  error rate: 10.87%
#> Confusion matrix:
#>       no  yes class.error
#> no  2736  512  0.15763547
#> yes  194 3054  0.05972906
# Prediksi dan evaluasi RF Tune Grid
prediksi_rf_tune <- predict(object = rf_gridsearch,newdata = test_data_rf)
cm_rf_tune_grid <- confusionMatrix(data = prediksi_rf_tune,reference = test_data_rf$y)$byClass
cm_rf_tune_grid
#>          Sensitivity          Specificity       Pos Pred Value 
#>            0.8375593            0.9324713            0.9898674 
#>       Neg Pred Value            Precision               Recall 
#>            0.4215654            0.9898674            0.8375593 
#>                   F1           Prevalence       Detection Rate 
#>            0.9073662            0.8873422            0.7432017 
#> Detection Prevalence    Balanced Accuracy 
#>            0.7508093            0.8850153

Kita dapat melihat bahwa nilai yang paling akurat untuk mtry adalah 13, dengan tingkat akurasi data train sebesar 83,78% serta akurasi data test sebesar 88.50%

6.1.2 Tuning RF Random

untuk itu kita akan mencoba model tuning kedua dengan random search. Random search adalah mencoba nilai-nilai acak dalam suatu rentang. Ini bisa berguna jika kita tidak yakin dengan nilai yang mungkin cocok dan kita ingin mengatasi bias yang mungkin kita miliki dalam menentukan parameter. Mari coba pencarian acak untuk mtry menggunakan paket caret:

# control <- trainControl(method="repeatedcv", number=10, repeats=3, search="random")
# set.seed(123)
# mtry <- 7
# rf_random <- train(y~., data=train_data_rf, method="rf", metric="accuracy", tuneLength=15, trControl=control)
# print(rf_random)
# plot(rf_random)

# saveRDS(rf_random, "rf_random.RDS")
rf_random <- readRDS("rf_random.RDS")
rf_random$finalModel
#> 
#> Call:
#>  randomForest(x = x, y = y, mtry = param$mtry) 
#>                Type of random forest: classification
#>                      Number of trees: 500
#> No. of variables tried at each split: 24
#> 
#>         OOB estimate of  error rate: 10.9%
#> Confusion matrix:
#>       no  yes class.error
#> no  2740  508  0.15640394
#> yes  200 3048  0.06157635
# Prediksi dan evaluasi RF Tune
prediksi_rf_tune_random <- predict(object = rf_random,newdata = test_data_rf)
cm_rf_tune_random <- confusionMatrix(data = prediksi_rf_tune_random,reference = test_data_rf$y)$byClass
cm_rf_tune_random
#>          Sensitivity          Specificity       Pos Pred Value 
#>            0.8377417            0.9317529            0.9897629 
#>       Neg Pred Value            Precision               Recall 
#>            0.4216515            0.9897629            0.8377417 
#>                   F1           Prevalence       Detection Rate 
#>            0.9074294            0.8873422            0.7433635 
#> Detection Prevalence    Balanced Accuracy 
#>            0.7510521            0.8847473

Berikut tabel perbandingan dari ketiga model RF kita :

comparison_table_rf <- data.frame(
  Model = c("Model RF", "Model RF Grid", "Model RF Random"),
  Accuracy = c(cm_rf["Balanced Accuracy"], cm_rf_tune_grid["Balanced Accuracy"], cm_rf_tune_random["Balanced Accuracy"]),
  Sensitivity = c(cm_rf["Sensitivity"], cm_rf_tune_grid["Sensitivity"], cm_rf_tune_random["Sensitivity"]),
  Specificity = c(cm_rf["Specificity"], cm_rf_tune_grid["Specificity"], cm_rf_tune_random["Specificity"]),
  Precision = c(cm_rf["Pos Pred Value"], cm_rf_tune_grid["Pos Pred Value"], cm_rf_tune_random["Pos Pred Value"]),
  F1_Score = c(cm_rf["F1"], cm_rf_tune_grid["F1"], cm_rf_tune_random["F1"])
)

comparison_table_rf

Perbandingan ketiga model RF menunjukan hasil yang hampir sama nilai nya, namun dapat terlihat bahwa model RF Random memiliki precision yang sedikit lebih unggul dari kedua model lainnya. untuk itu model RF yang akan digunakan adalah RF Random.

6.2 Naive Bayes

Kita dapat menyesuaikan beberapa parameter hiper yang dimiliki oleh model Naïve Bayes.

  • Parameter usekernel memungkinkan kita untuk menggunakan estimasi kerapatan kernel (kernel density estimate) untuk variabel kontinu daripada estimasi kerapatan Gaussian.
  • Parameter adjust memungkinkan kita untuk menyesuaikan lebar bandwidth dari estimasi kerapatan kernel (nilai yang lebih besar menghasilkan estimasi kerapatan yang lebih fleksibel).
  • Parameter fL memungkinkan kita untuk menggunakan smoothing Laplace.

kita juga akan menggabungkan beberapa tahap preprocessing fitur (normalisasi dengan Box Cox, standarisasi dengan center-scaling, dan reduksi dengan PCA).

Proses preprocessing diharapkan ini membantu model Naïve Bayes untuk menghasilkan hasil yang lebih baik dengan mengolah data input sebelum digunakan dalam proses pelatihan model. Hal ini sering digunakan untuk meningkatkan performa model dan mengurangi masalah overfitting.

# train_control <- trainControl(
#   method = "cv", 
#   number = 10
#   )
#
# # set up tuning grid
# search_grid <- expand.grid(
#   usekernel = c(TRUE, FALSE),
#   fL = 0:5,
#   adjust = seq(0, 5, by = 1)
# )
#
# # train model
# nb.m2 <- train(
#   x = train_data %>% select(-y),
#   y = train_data$y,
#   method = "nb",
#   trControl = train_control,
#   tuneGrid = search_grid,
#   preProc = c("BoxCox", "center", "scale", "pca")
#   )
#
# # top 5 modesl
# nb.m2$results %>% 
#   top_n(5, wt = Accuracy) %>%
#   arrange(desc(Accuracy))
#
# saveRDS(nb.m2, "model_nb_tune.RDS")
nb.m2 <- readRDS("model_nb_tune.RDS")

pred_nb_tune<-predict(nb.m2,test_data)
cm_nb_tune <- confusionMatrix(pred_nb_tune,test_data$y)$byClass
comparison_table_nb <- data.frame(
  Model = c("Model NB", "Model NB Tune"),
  Accuracy = c(cm_nb["Balanced Accuracy"], cm_nb_tune["Balanced Accuracy"]),
  Sensitivity = c(cm_nb["Sensitivity"], cm_nb_tune["Sensitivity"]),
  Specificity = c(cm_nb["Specificity"], cm_nb_tune["Specificity"]),
  Precision = c(cm_nb["Pos Pred Value"], cm_nb_tune["Pos Pred Value"]),
  F1_Score = c(cm_nb["F1"], cm_nb_tune["F1"])
)

comparison_table_nb

Hasil tuning model NB tidak menunjukan peningkatan performa yang signifikan, ini mungkin terjadi karena prediktor kita yang mayoritas variabel kategorik. untuk itu kita akan memilih model NB tampa tuning.

6.3 Decision Tree

Kekurangan dari Decision Tree adalah kecenderungannya untuk overfitting. Hal ini terjadi karena Decision tree mampu membagi-bagi data hingga amat detail (bahkan hingga dalam leaf node hanya terdapat 1 observasi). Pada keadaan ini, decision tree justru menghafal pola di data train, dan membuat aturan yang terlalu kompleks, bukan mempelajari pola tersebut. Alhasil model menjadi kurang general untuk diaplikasikan ke data yang bukan data train, sehingga cenderung overfit. Untuk mengatasinya, decision tree perlu tahu kapan ia berhenti membuat cabang sehingga pohon yang dihasilkan tidak terlalu kompleks. Pemotongan/pencegahan cabang pohon disebut Pruning. Parameter yang dapat digunakan untuk pruning model DT adalah :

mincriterion: 1- tingkat signifikan minsplit: syarat jumlah observasi sebelum membuat cabang minbucket: syarat jumlah observasi setelah membuat cabang

model_dt_tune <- ctree(formula = y~., 
                          data = train_data,
                          control = ctree_control(mincriterion = 0.90, 
                                                  minsplit = 30,
                                                  minbucket = 9))
prediksi_dt_tune <- predict(object = model_dt_tune,
                          newdata = test_data,
                          type = "response")

cm_dt_tune <- confusionMatrix(data = prediksi_dt_tune,
                reference = test_data$y)$byClass #data actual
cm_dt_tune
#>          Sensitivity          Specificity       Pos Pred Value 
#>            0.8027180            0.9561782            0.9931167 
#>       Neg Pred Value            Precision               Recall 
#>            0.3809388            0.9931167            0.8027180 
#>                   F1           Prevalence       Detection Rate 
#>            0.8878241            0.8873422            0.7122855 
#> Detection Prevalence    Balanced Accuracy 
#>            0.7172224            0.8794481
comparison_table_dt <- data.frame(
  Model = c("Model DT", "Model DT Tune"),
  Accuracy = c(cm_dt["Balanced Accuracy"], cm_dt_tune["Balanced Accuracy"]),
  Sensitivity = c(cm_dt["Sensitivity"], cm_dt_tune["Sensitivity"]),
  Specificity = c(cm_dt["Specificity"], cm_dt_tune["Specificity"]),
  Precision = c(cm_dt["Pos Pred Value"], cm_dt_tune["Pos Pred Value"]),
  F1_Score = c(cm_dt["F1"], cm_dt_tune["F1"])
)

comparison_table_dt

Perbandingan kedua model DT kita menunjukan performa yang hampir sama. meskipun model DT dengan tuning sedikit lebih unggul pada metrik akurasi, namun terlihat model DT tampa tuning sedikit lebih unggul pada metrik precision, maka kita akan menggunakan model DT tampa tuning

7 Perbandingan Model

Langkah terakhir adalah membandingkan ketiga model yang telah kita buat. seperti yang telah dijelaskan diatas bahwa pada case bisnis kita akan lebih memperhatikan metrik Precision.

comparison_table <- data.frame(
  Model = c("Model RF", "Model NB", "Model DT"),
  Accuracy = c(cm_rf_tune_random["Balanced Accuracy"], cm_nb["Balanced Accuracy"], cm_dt["Balanced Accuracy"]),
  Sensitivity = c(cm_rf_tune_random["Sensitivity"], cm_nb["Sensitivity"], cm_dt["Sensitivity"]),
  Specificity = c(cm_rf_tune_random["Specificity"], cm_nb["Specificity"], cm_dt["Specificity"]),
  Precision = c(cm_rf_tune_random["Pos Pred Value"], cm_nb["Pos Pred Value"], cm_dt["Pos Pred Value"]),
  F1_Score = c(cm_rf_tune_random["F1"], cm_nb["F1"], cm_dt["F1"])
)

comparison_table

8 Kesimpulan

Berdasarkan hasil perbandingan ketiga model kita didapatkan model RF unggul pada matrik Precision dengan 98.98%. selain itu model RF juga unggul di semua matrik lainnya. Untuk itu kita dapat menggunakan model RF untuk membuat prediksi hingga 98.98% dari prediksi positif yang benar-benar benar. Dengan demikian kita telah menjawab masalah dalam percobaan ini yaitu membuat model yang dapat memprediksi klien yang berpotensi berlangganan deposito berjangka.