library(tidyverse)
library(dplyr)
library(ggplot2)
library(inspectdf)
library(GGally)
library(plotly)
library(e1071)
library(rsample)
library(randomForest)
library(DMwR)
library(ROCR)
library(caret)
library(partykit)Telemarketing adalah salah satu cara promosi yang masih dianggap efektif selain memasang iklan di media umum. Pengertian telemarketing yaitu memasarkan atau mensosialisasikan produk atau jasa melalui telepon. Biasanya, strategi pemasaran melalui telemarketing ini dipakai oleh beberapa perusahaan besar untuk menawarkan produknya. Menurut banyak ahli pemasaran, penawaran melalui telemarketing cenderung mudah diterima, karena sifatnya memang berbicara secara personal langsung kepada konsumen.
Bank merupakan salah satu lembaga yang menggunakan metode telmarketing untuk menjual product product yang ada di bank atau untuk menawarkan jasa. Bank sebagai lembaga financing sangat memperhatikan tingkat baiknya reputasi dan branding yang dimiliki, dan salah satu hal buruk yang dilakukan telemarketing dapat mengganggu reputasi itu sendiri. Jadi perlu dicari target mana yang akan membeli atau tudak membeli produk atau jasa yang akan ditawarkan oleh bank menggunakan metode telemarketing.
Dalam kasus ini kita akan menggunakan machine learning untuk melihat suatu pola dan menprediksi target dari telemarketing. Model yang akan kita gunakan adalah random forest dan decision tree.
Kita akan membandingkan kedua hasil prediksi dari kedua model tersebut. Dua model ini masuk kedalam kategori supervised learning, berdasarkan fitur tersebut kita akan membandingkan pola klasifikasi dari model yang didapat dari data untuk mendapatkan prediksi akhir yang terbaik.
Disini kita akan read data telemarketing yang kita dapatkan dari UCI Machine Learning Repository, data tersebut terkait dengan kampanye pemasaran dari lembaga perbankan Portugis. Dan disini kita akan menyimpan dataset kedalam bank.
bank <- read.csv("data_input/bank.csv", sep=";")
head(bank)glimpse(bank)## Rows: 4,521
## Columns: 17
## $ age <int> 30, 33, 35, 30, 59, 35, 36, 39, 41, 43, 39, 43, 36, 20, 3...
## $ job <chr> "unemployed", "services", "management", "management", "bl...
## $ marital <chr> "married", "married", "single", "married", "married", "si...
## $ education <chr> "primary", "secondary", "tertiary", "tertiary", "secondar...
## $ default <chr> "no", "no", "no", "no", "no", "no", "no", "no", "no", "no...
## $ balance <int> 1787, 4789, 1350, 1476, 0, 747, 307, 147, 221, -88, 9374,...
## $ housing <chr> "no", "yes", "yes", "yes", "yes", "no", "yes", "yes", "ye...
## $ loan <chr> "no", "yes", "no", "yes", "no", "no", "no", "no", "no", "...
## $ contact <chr> "cellular", "cellular", "cellular", "unknown", "unknown",...
## $ day <int> 19, 11, 16, 3, 5, 23, 14, 6, 14, 17, 20, 17, 13, 30, 29, ...
## $ month <chr> "oct", "may", "apr", "jun", "may", "feb", "may", "may", "...
## $ duration <int> 79, 220, 185, 199, 226, 141, 341, 151, 57, 313, 273, 113,...
## $ campaign <int> 1, 1, 1, 4, 1, 2, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 5, 1, 1, ...
## $ pdays <int> -1, 339, 330, -1, -1, 176, 330, -1, -1, 147, -1, -1, -1, ...
## $ previous <int> 0, 4, 1, 0, 0, 3, 2, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 2, 0, ...
## $ poutcome <chr> "unknown", "failure", "failure", "unknown", "unknown", "f...
## $ y <chr> "no", "no", "no", "no", "no", "no", "no", "no", "no", "no...
Pertama kita akan mengecek apakah didalam dataset yang kita miliki terdapat missing values.
colSums(is.na(bank))## age job marital education default balance housing loan
## 0 0 0 0 0 0 0 0
## contact day month duration campaign pdays previous poutcome
## 0 0 0 0 0 0 0 0
## y
## 0
Data bank tidak memiliki missing values, jadi kita akan langsung merubah beberapa kolom varibel ke tipe data yang seharusnya. Dan kita akan mengganti kolom target kita dari y menjadi subscribe.
bank <- bank %>%
mutate(job = as.factor(job)) %>%
mutate(marital = as.factor(marital)) %>%
mutate(education = as.factor(education)) %>%
mutate(default = as.factor(default)) %>%
mutate(housing = as.factor(housing)) %>%
mutate(month = as.factor(month)) %>%
mutate(loan = as.factor(loan)) %>%
mutate(contact = as.factor(contact)) %>%
mutate(poutcome = as.factor(poutcome)) %>%
mutate(subscribe = as.factor(y))Setelah merubah variabel penting kedalam tipe data yang benar. Kita akan menampilkan beberapa variabel numeric dengan histogram untuk mendapatkan distribusinya.
numericCols <- unlist(lapply(bank, is.numeric))
show_plot(inspect_num(bank[,numericCols])) # Cross Validation
Disini kita akan membagi dataset yang kita miliki menjadi dua subset yaitu data train dan data test. Dan kita memisahkan data dengan proporsi 80% untuk data train dan 20% untuk data test.
RNGkind(sample.kind = "Rounding")## Warning in RNGkind(sample.kind = "Rounding"): non-uniform 'Rounding' sampler
## used
set.seed(100)
intrain <- sample(nrow(bank), nrow(bank)*0.8)
bank_train <- bank[intrain,]
bank_test <- bank[-intrain,]Setelah kita bagi data, alagkah baiknya kita cek terlebih dahulu apakah proporsi kelas target yang kita miliki sudah balance.
prop.table(table(bank_train$subscribe))##
## no yes
## 0.8821903 0.1178097
Setelah kita cek ternyata terjadi imbalance dalam proporsi kelas target, agar model yang kita buat dapat memprediksi secara baik, kita akan melakukan metode upsampling karena data yang kita milik tidak terlalu banyak.
bank_train <- upSample(x = bank_train %>% select(-subscribe),
y = as.factor(bank_train$subscribe),
yname = "subscribe")Model pertama yang kita gunakan adalah model random forest.Random Forest melakukan prediksi dengan membuat banyak Decision Tree. Masing-masing Decision Tree memiliki karakteristik masing-masing dan tidak saling berhubungan satu sama lain. Random Forest kemudian melakukan prediksi untuk masing-masing decision tree, kemudian dari sekian banyak hasil prediksi tersebut dilakukan voting.
Traincontrol future selection yang menggunakan keuntungan dari random forest yaitu automatic feature selection: pemilihan prediktor secara otomatis dan random didalam pembuatan decision tree - method: traincontrol - number: 5 - repeats: r
set.seed(123)
control <- trainControl(method = "repeatedcv", number = 5, repeats = 4)
# pembuatan model random forest
bank_model <- train(subscribe ~ ., data = bank_train, method = "rf", trControl = control)
# simpan model
saveRDS(bank_model, "bank_forest.RDS")
bank_modelSetelah kita membuat model random forest kita akan menyimpan model tersebut kedalam bank_forest dan memanggil model tersebut untuk digunakan kedalam prediksi. Penting untung menyimpan model random forest agar kita tidak menjalankan model secara berulang dikarenakan kelamahan dari random forest adalah komputasinya yang lama.
bank_model_rf <- readRDS("bank_forest.RDS")
bank_model_rf## Random Forest
##
## 6380 samples
## 16 predictor
## 2 classes: 'no', 'yes'
##
## No pre-processing
## Resampling: Cross-Validated (5 fold, repeated 4 times)
## Summary of sample sizes: 5104, 5104, 5104, 5104, 5104, 5104, ...
## Resampling results across tuning parameters:
##
## mtry Accuracy Kappa
## 2 0.8851097 0.7702194
## 22 0.9681034 0.9362069
## 42 0.9631270 0.9262539
##
## Accuracy was used to select the optimal model using the largest value.
## The final value used for the model was mtry = 22.
Kita lihat final model didalam model random forest yang kita buat
bank_model_rf$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: 22
##
## OOB estimate of error rate: 2.49%
## Confusion matrix:
## no yes class.error
## no 3031 159 0.04984326
## yes 0 3190 0.00000000
Pada model fb_forest, nilai Out of Bag Error sebesar 2.49%. Dengan kata lain, akurasi model pada data test (out of bag data) adalah 97,51%. Selanjutnya kita akan menggunakan model yang telah kita buat kedalam prediksi dengan menggunakan data test yang telah kita buat dan kita akan mengecek apakah model yang kita buat memiliki accuracy, Specificity , precision, dan sensitivity yang tinggi.
bank_pred_rf <- predict(bank_model_rf, newdata = bank_test)
confusionMatrix(bank_pred_rf , bank_test$subscribe, positive = "yes")## Confusion Matrix and Statistics
##
## Reference
## Prediction no yes
## no 764 52
## yes 46 43
##
## Accuracy : 0.8917
## 95% CI : (0.8696, 0.9112)
## No Information Rate : 0.895
## P-Value [Acc > NIR] : 0.6524
##
## Kappa : 0.4072
##
## Mcnemar's Test P-Value : 0.6135
##
## Sensitivity : 0.45263
## Specificity : 0.94321
## Pos Pred Value : 0.48315
## Neg Pred Value : 0.93627
## Prevalence : 0.10497
## Detection Rate : 0.04751
## Detection Prevalence : 0.09834
## Balanced Accuracy : 0.69792
##
## 'Positive' Class : yes
##
Dapat dilihat walaupun memiliki tingkat akurasi dan Specificity yang baik, tapi dari hasil prediksi diatas model kita memiliki tinggkat sensitivity dan precision yang rendah. Kita perlu membandingkan hasil prediksi model random forest dengan model selanjutnya yaitu decision tree.
Decision Tree adalah model yang terbilang cukup sederhana, namun performanya robust/powerfull dan hasilnya dapat diinterpretasi dengan mudah. Model decision tree merupakan dasar dari tree-based model lainnya seperti Random Forest yang terkenal robust untuk menghasilkan prediksi. Sama seperti model random forest dikarenakan proporsi tarvet variabel kita tidak balance kita akan melakukan metode upsampling pada data train.
bank_train_up <- upSample(x = bank_train %>% select(-subscribe),
y = as.factor(bank_train$subscribe),
yname = "subscribe")Setelah itu kita akan buat model decision treenya.
set.seed(128)
bank_model_dtree <- ctree(subscribe ~ ., bank_train_up)Setelah itu kita akan memprediksi model yang kita buat kedalam data test
bank_pred_dtree <- predict(bank_model_dtree, bank_test)
confusionMatrix(bank_pred_dtree, bank_test$subscribe, positive = "yes")## Confusion Matrix and Statistics
##
## Reference
## Prediction no yes
## no 662 26
## yes 148 69
##
## Accuracy : 0.8077
## 95% CI : (0.7805, 0.8329)
## No Information Rate : 0.895
## P-Value [Acc > NIR] : 1
##
## Kappa : 0.3469
##
## Mcnemar's Test P-Value : <2e-16
##
## Sensitivity : 0.72632
## Specificity : 0.81728
## Pos Pred Value : 0.31797
## Neg Pred Value : 0.96221
## Prevalence : 0.10497
## Detection Rate : 0.07624
## Detection Prevalence : 0.23978
## Balanced Accuracy : 0.77180
##
## 'Positive' Class : yes
##
Dapat dilihat hasil accuracy, recall, dan specificity sudah cukup baik, tapi nilai precision kita masih terlalu rendah yaitu 31%. Model kita masih dapat di imprivo dengan melakukan tuning.
set.seed(128)
bank_dtree_tuning <- ctree(subscribe ~ ., bank_train_up,
control = ctree_control(mincriterion = 0.09, minsplit = 100, minbucket = 60))
dtree_prediction_tuning <- predict(bank_dtree_tuning, bank_test, positive = "yes")Mari kita tuning agar model yang kita buat tidak terlalu kompleks dengan menggunakan mincriterion 0,1, minsplit 60 dan minbucket 50. Setelah itu kita akan prediksi kembali kedalam data test.
confusionMatrix(dtree_prediction_tuning, bank_test$subscribe)## Confusion Matrix and Statistics
##
## Reference
## Prediction no yes
## no 610 16
## yes 200 79
##
## Accuracy : 0.7613
## 95% CI : (0.7322, 0.7888)
## No Information Rate : 0.895
## P-Value [Acc > NIR] : 1
##
## Kappa : 0.3152
##
## Mcnemar's Test P-Value : <2e-16
##
## Sensitivity : 0.7531
## Specificity : 0.8316
## Pos Pred Value : 0.9744
## Neg Pred Value : 0.2832
## Prevalence : 0.8950
## Detection Rate : 0.6740
## Detection Prevalence : 0.6917
## Balanced Accuracy : 0.7923
##
## 'Positive' Class : no
##
Setelah kita tuning terjadi peningkatan pada precision dari 31% menjadi 97%. Ini merupakan hasil yang sangat baik dan cukup.
Dari dua model diatas dapat dilihat model decision tree memiliki overall matrix yang sangat baik, dan dalam kasus telemerketing bank kita akan fokus pada target “No” yang artinya kita tidak ingin target dari telemarketing yang diramalkan tidak akan membeli produk atau jasa yang ditawarkan oleh telemarketing, karena kita tidak ingin reputasi bank menurun akibat kontak yang tidak perlu atau di anggap mengganggu, maka dapat dilihat model dtree_prediction_tuning memilki nilai sensitivity yang paling tinggi yaitu 75%.