Halo!
Pada classification II kali ini, kita akan membuat model algortima klasifikasi. Data yang digunakan adalah data yang mengenai telemarketing dari sebuah bank di Portugal. Dengan data ini, kita dapat memprediksi calon nasabah mana yang akan membeli product ketika di tawarkan oleh pihak bank melalui telepon.
##Data Preparation
#import data
bank <- read.csv(file = "bank/bank.csv", sep = ";") #Menggunakan sep = ";" untuk memisahkan kolom
#Mengecheck data yang ada
glimpse(bank)#> Rows: 4,521
#> Columns: 17
#> $ age <int> 30, 33, 35, 30, 59, 35, 36, 39, 41, 43, 39, 43, 36, 20, 31, …
#> $ job <chr> "unemployed", "services", "management", "management", "blue-…
#> $ marital <chr> "married", "married", "single", "married", "married", "singl…
#> $ education <chr> "primary", "secondary", "tertiary", "tertiary", "secondary",…
#> $ 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, 26…
#> $ housing <chr> "no", "yes", "yes", "yes", "yes", "no", "yes", "yes", "yes",…
#> $ loan <chr> "no", "yes", "no", "yes", "no", "no", "no", "no", "no", "yes…
#> $ contact <chr> "cellular", "cellular", "cellular", "unknown", "unknown", "c…
#> $ day <int> 19, 11, 16, 3, 5, 23, 14, 6, 14, 17, 20, 17, 13, 30, 29, 29,…
#> $ month <chr> "oct", "may", "apr", "jun", "may", "feb", "may", "may", "may…
#> $ duration <int> 79, 220, 185, 199, 226, 141, 341, 151, 57, 313, 273, 113, 32…
#> $ campaign <int> 1, 1, 1, 4, 1, 2, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 5, 1, 1, 1, …
#> $ pdays <int> -1, 339, 330, -1, -1, 176, 330, -1, -1, 147, -1, -1, -1, -1,…
#> $ previous <int> 0, 4, 1, 0, 0, 3, 2, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 2, 0, 1, …
#> $ poutcome <chr> "unknown", "failure", "failure", "unknown", "unknown", "fail…
#> $ y <chr> "no", "no", "no", "no", "no", "no", "no", "no", "no", "no", …
Pada dataset ini tersedia keterangan mengenai masing - masing variabelnya, berikut mengenai masing - masing variabel tersebut :
• Age: Umur klien (variabel numerik)
• Job: Jenis pekerjaan klien (variabel kategorikal)
• Marital: Status perkawinan klien (variabel kategorikal)
• Education: Tingkat pendidikan klien (variabel kategorikal
• Default: Apakah klien memiliki kredit yang dalam keadaan default? (variabel biner)
• Balance: Rata-rata saldo tahunan klien dalam euro (variabel numerik)
• Housing: Apakah klien memiliki pinjaman rumah? (variabel biner)
• Loan: Apakah klien memiliki pinjaman pribadi? (variabel biner)
• Contact: Jenis komunikasi kontak terakhir (variabel kategorikal)
• Day: Hari terakhir kontak dalam bulan (variabel numerik)
• Month: Bulan terakhir kontak dalam tahun (variabel kategorikal)
• Duration: Durasi kontak terakhir dalam detik (variabel numerik)
• Campaign: Jumlah kontak yang dilakukan selama kampanye ini untuk klien (variabel numerik)
• Pdays: Jumlah hari yang telah berlalu setelah klien terakhir dihubungi dari kampanye sebelumnya (variabel numerik)
• Previous: Jumlah kontak yang dilakukan sebelum kampanye ini untuk klien (variabel numerik)
• Poutcome: Hasil kampanye pemasaran sebelumnya (variabel kategorikal)
• Y: Variabel target yang menunjukkan apakah klien telah berlangganan deposito jangka pendek (variabel biner)
Pada dataset yang kita miliki ada beberapa kolom yang perlu diubah
tipe datanya, kita akan menggunakan fungsi mutate untuk
mengubah tipe data tersebut.
bank <- bank %>%
mutate(job = as.factor(job),
marital = as.factor(marital),
education = as.factor(education),
default = as.factor(default),
housing = as.factor(housing),
loan = as.factor(loan),
contact = as.factor(contact),
month = as.factor(month),
poutcome = as.factor(poutcome),
subscribe = as.factor(y)) %>%
select(-c(y))#> 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
#> subscribe
#> 0
Setelah kita mengetahui bahwa data kita tidak ada Missing Value, selanjutnya kita mengecheck apakah data yang kita miliki balance atau tidak
#>
#> no yes
#> 0.88476 0.11524
Terlihat data kita imbalance, Artinya data mengacu pada situasi di mana jumlah observasi tidak sama untuk semua kelas dalam kumpulan data klasifikasi. Untuk menghindari hilangnya varians, kita akan menggunakan upsampling untuk menyeimbangkan proporsinya.
Cross-validation aka (CV) merupakan metode statistik yang dapat digunakan untuk mengevaluasi kinerja model atau algoritma dimana datanya dipisahkan menjadi dua subset yaitu data proses pembelajaran dan data validasi/evaluasi. Dalam hal ini kita akan memisahkan data dengan proporsi 80% dataset untuk data pelatihan dan sisanya 20% kita gunakan sebagai data uji.
RNGkind(sample.kind = "Rounding")
set.seed(101)
split <- initial_split(data = bank, prop = 0.8, strata = subscribe)
bank_train <- training(split)
bank_test <- testing(split)Check kembali proporsi yang ada
#>
#> no yes
#> 0.8849558 0.1150442
Sepertinya data kita masih tidak balance, dan perlu kita ubah agar menjadi balance
RNGkind(sample.kind = "Rounding")
set.seed(101)
#Menggunakan fungsi UpSample
bank_train_upsample <- upSample(x = bank_train %>% select(-subscribe),
y = bank_train$subscribe,
yname = "subscribe")Check kembali proporsi targer
#>
#> no yes
#> 0.5 0.5
Sekarang data kita sudah balance!
Kita akan membuat permodelan Naive Bayes, dimana Naive Bayes adalah Model Naive Bayes adalah salah satu model klasifikasi yang digunakan dalam pembelajaran mesin dan statistik. Model ini didasarkan pada teorema Bayes, dan itu adalah metode yang sederhana dan efisien untuk mengklasifikasikan data ke dalam kategori atau kelas yang berbeda.
#Menggunakan Fungsi naiveBayes
model_naive <- naiveBayes(subscribe ~ ., data = bank_train_upsample, laplace = 1)naive_prediction <- predict(model_naive, bank_test)
naive_prediction_raw <- as.data.frame(predict(model_naive, bank_test, type = "raw"))
naive_prediction_raw <- naive_prediction_raw %>%
mutate(no = round(no,4),
yes = round(yes,4))naive_matrix <- confusionMatrix(naive_prediction, bank_test$subscribe, positive = "yes")
table <- as.table(naive_matrix)
table <- as.data.frame(table)
table %>% ggplot(aes(x = Prediction, y = Reference, fill = Freq)) +
geom_tile() +
geom_text(aes(label = Freq), fontface = "bold", color = "white") +
theme_minimal() +
theme(legend.position = "none")Confussion Matrix Tabel ini menjelaskan:
Selanjutnya kita akan menggunakan ROC untuk melihat hubungan
ROC adalah kurva yang menggambarkan hubungan antara True Positive Rate dengan False Positive Rate pada setiap threshold. Model yang baik idealnya memiliki True Positive Rate yang tinggi dan False Positive Rate yang rendah.
#Memanggil ROC
naive_roc <- data.frame(prediction = naive_prediction_raw[,2],
trueclass = as.numeric(bank_test$subscribe=="yes"))
tail(naive_roc)naive_roc_pred <- prediction(naive_roc$prediction, naive_roc$trueclass)
# Membuat ROC curve
plot(performance(naive_roc_pred, "tpr", "fpr"),
main = "ROC")
abline(a = 0, b = 1)Karena berbentuk visual, kurva ROC sulit untuk dibandingkan antar model. Oleh karena itu diperlukan AUC.
AUC (Area Under Curve) adalah area di bawah kurva ROC. Nilai-nilai AUC mengindikasikan sejauh mana keberhasilan model dalam memprediksi atau membedakan dua kelas yang berbeda.
Nilai AUC memiliki rentang antara 0 hingga 1. Jika nilai AUC mendekati 1, itu berarti model klasifikasi mampu memprediksi atau membedakan kedua kelas dengan baik. Namun, jika nilai AUC mendekati 0,5, itu menunjukkan bahwa model klasifikasi tidak cukup baik dalam memprediksi atau membedakan kedua kelas.
Ketika nilai AUC mendekati 1, itu berarti model klasifikasi dapat memprediksi atau membedakan kedua kelas dengan baik. Namun, ketika nilai AUC mendekati 0,5, itu menunjukkan bahwa model klasifikasi tidak mampu memprediksi atau membedakan kedua kelas dengan baik.
Mari kita lihat apakah model kita bagus atau tidak
#> [1] 0.840381
Berdasarkan hasil kurva ROC dan nilai AUC, kita melihat bahwa kurva ROC menunjukkan pemisahan yang baik dengan skor AUC sebesar 0,8456519. Ini mengindikasikan bahwa kita memiliki peluang untuk meningkatkan model Naive Bayes ini. Dalam model Naive Bayes kita, akurasi, sensitivitas, dan spesifisitas sudah cukup baik, tetapi nilai positif prediksi kita masih rendah, yaitu sebesar 30%.
Dalam konteks kasus kita, berfokus pada kelas “Tidak,” yang berarti kita ingin menghindari menelepon orang yang diprediksi tidak ingin membeli produk atau layanan yang ditawarkan oleh pemasaran melalui telepon. Oleh karena itu, kita lebih berfokus pada parameter Sensitivitas, yang menunjukkan bahwa model Naive Bayes kita sudah memberikan hasil yang baik.
Decision tree merupakan tree-based model yang cukup sederhana dengan performa yang robust/powerful untuk prediksi. Decision Tree menghasilkan visualisasi berupa pohon keputusan. Kita akan membuat model Decison Tree pada dataset yang ada
#Membuat Model Decision tree
model_tree <- ctree(subscribe ~.,
bank_train,
control = ctree_control(mincriterion=0.8,
minsplit=0.3,
minbucket=0.3))#>
#> Model formula:
#> subscribe ~ age + job + marital + education + default + balance +
#> housing + loan + contact + day + month + duration + campaign +
#> pdays + previous + poutcome
#>
#> Fitted party:
#> [1] root
#> | [2] duration <= 631
#> | | [3] poutcome in failure, other, unknown
#> | | | [4] duration <= 292
#> | | | | [5] month in apr, aug, dec, feb, jan, jul, jun, may, nov
#> | | | | | [6] month in apr, feb
#> | | | | | | [7] day <= 9: no (n = 114, err = 0.9%)
#> | | | | | | [8] day > 9
#> | | | | | | | [9] month in apr
#> | | | | | | | | [10] housing in no: no (n = 36, err = 27.8%)
#> | | | | | | | | [11] housing in yes: no (n = 91, err = 3.3%)
#> | | | | | | | [12] month in feb: no (n = 19, err = 47.4%)
#> | | | | | [13] month in aug, dec, jan, jul, jun, may, nov
#> | | | | | | [14] poutcome in failure, other
#> | | | | | | | [15] month in aug, jun: no (n = 28, err = 25.0%)
#> | | | | | | | [16] month in dec, jan, jul, may, nov
#> | | | | | | | | [17] job in admin., retired, student, unemployed, unknown: no (n = 66, err = 13.6%)
#> | | | | | | | | [18] job in blue-collar, entrepreneur, housemaid, management, self-employed, services, technician
#> | | | | | | | | | [19] housing in no: no (n = 41, err = 4.9%)
#> | | | | | | | | | [20] housing in yes: no (n = 148, err = 0.0%)
#> | | | | | | [21] poutcome in unknown
#> | | | | | | | [22] duration <= 204
#> | | | | | | | | [23] age <= 34: no (n = 447, err = 1.8%)
#> | | | | | | | | [24] age > 34: no (n = 1020, err = 0.1%)
#> | | | | | | | [25] duration > 204
#> | | | | | | | | [26] contact in cellular, telephone
#> | | | | | | | | | [27] month in aug, dec, jan, jul, may, nov: no (n = 233, err = 4.3%)
#> | | | | | | | | | [28] month in jun: yes (n = 10, err = 40.0%)
#> | | | | | | | | [29] contact in unknown
#> | | | | | | | | | [30] month in jul, nov: no (n = 3, err = 33.3%)
#> | | | | | | | | | [31] month in jun, may: no (n = 184, err = 0.0%)
#> | | | | [32] month in mar, oct, sep
#> | | | | | [33] duration <= 140
#> | | | | | | [34] marital in divorced: yes (n = 2, err = 0.0%)
#> | | | | | | [35] marital in married, single: no (n = 54, err = 7.4%)
#> | | | | | [36] duration > 140: no (n = 35, err = 40.0%)
#> | | | [37] duration > 292
#> | | | | [38] month in apr, aug, feb, jan, jul, jun, may, nov, sep
#> | | | | | [39] contact in cellular, telephone
#> | | | | | | [40] month in apr, aug, feb, jan, jul, may, nov: no (n = 428, err = 16.4%)
#> | | | | | | [41] month in jun, sep: yes (n = 28, err = 46.4%)
#> | | | | | [42] contact in unknown
#> | | | | | | [43] duration <= 477: no (n = 140, err = 0.0%)
#> | | | | | | [44] duration > 477: no (n = 62, err = 17.7%)
#> | | | | [45] month in dec, mar, oct: yes (n = 24, err = 29.2%)
#> | | [46] poutcome in success
#> | | | [47] duration <= 171
#> | | | | [48] housing in no: no (n = 15, err = 46.7%)
#> | | | | [49] housing in yes: no (n = 10, err = 0.0%)
#> | | | [50] duration > 171: yes (n = 65, err = 18.5%)
#> | [51] duration > 631
#> | | [52] contact in cellular: yes (n = 201, err = 43.8%)
#> | | [53] contact in telephone, unknown
#> | | | [54] housing in no: yes (n = 38, err = 42.1%)
#> | | | [55] housing in yes: no (n = 74, err = 28.4%)
#>
#> Number of inner nodes: 27
#> Number of terminal nodes: 28
#> Confusion Matrix and Statistics
#>
#>
#> pred_tree no yes
#> no 764 61
#> yes 36 44
#>
#> Accuracy : 0.8928
#> 95% CI : (0.8708, 0.9122)
#> No Information Rate : 0.884
#> P-Value [Acc > NIR] : 0.21968
#>
#> Kappa : 0.4172
#>
#> Mcnemar's Test P-Value : 0.01482
#>
#> Sensitivity : 0.9550
#> Specificity : 0.4190
#> Pos Pred Value : 0.9261
#> Neg Pred Value : 0.5500
#> Prevalence : 0.8840
#> Detection Rate : 0.8442
#> Detection Prevalence : 0.9116
#> Balanced Accuracy : 0.6870
#>
#> 'Positive' Class : no
#>
DENGAN MENGGUNAKAN DECISION TREE MENDAPARKAN ACCURACY 89%
#> Rows: 4,521
#> Columns: 17
#> $ age <int> 30, 33, 35, 30, 59, 35, 36, 39, 41, 43, 39, 43, 36, 20, 31, …
#> $ job <fct> unemployed, services, management, management, blue-collar, m…
#> $ marital <fct> married, married, single, married, married, single, married,…
#> $ education <fct> primary, secondary, tertiary, tertiary, secondary, tertiary,…
#> $ default <fct> no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, …
#> $ balance <int> 1787, 4789, 1350, 1476, 0, 747, 307, 147, 221, -88, 9374, 26…
#> $ housing <fct> no, yes, yes, yes, yes, no, yes, yes, yes, yes, yes, yes, no…
#> $ loan <fct> no, yes, no, yes, no, no, no, no, no, yes, no, no, no, no, y…
#> $ contact <fct> cellular, cellular, cellular, unknown, unknown, cellular, ce…
#> $ day <int> 19, 11, 16, 3, 5, 23, 14, 6, 14, 17, 20, 17, 13, 30, 29, 29,…
#> $ month <fct> oct, may, apr, jun, may, feb, may, may, may, apr, may, apr, …
#> $ duration <int> 79, 220, 185, 199, 226, 141, 341, 151, 57, 313, 273, 113, 32…
#> $ campaign <int> 1, 1, 1, 4, 1, 2, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 5, 1, 1, 1, …
#> $ pdays <int> -1, 339, 330, -1, -1, 176, 330, -1, -1, 147, -1, -1, -1, -1,…
#> $ previous <int> 0, 4, 1, 0, 0, 3, 2, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 2, 0, 1, …
#> $ poutcome <fct> unknown, failure, failure, unknown, unknown, failure, other,…
#> $ subscribe <fct> no, no, no, no, no, no, no, no, no, no, no, no, no, yes, no,…
#> [1] 4521 15
Splitting train test dengan proporsi 80%:20% untuk dapat digunakan
Selanjutnya, kita akan melalakukan Model Fitting
set.seed(123)
ctrl <- trainControl(method = "repeatedcv",
number = 5, # k-fold
repeats = 3) # repetisi
bank2_forest <- train(subscribe ~ .,
data = bank2_train,
method = "rf", # random forest
trControl = ctrl)
saveRDS(bank2_forest, "bank2_forest_2.RDS") # simpan model#> Confusion Matrix and Statistics
#>
#>
#> pred_random no yes
#> no 770 66
#> yes 28 41
#>
#> Accuracy : 0.8961
#> 95% CI : (0.8744, 0.9152)
#> No Information Rate : 0.8818
#> P-Value [Acc > NIR] : 0.0974367
#>
#> Kappa : 0.4113
#>
#> Mcnemar's Test P-Value : 0.0001355
#>
#> Sensitivity : 0.9649
#> Specificity : 0.3832
#> Pos Pred Value : 0.9211
#> Neg Pred Value : 0.5942
#> Prevalence : 0.8818
#> Detection Rate : 0.8508
#> Detection Prevalence : 0.9238
#> Balanced Accuracy : 0.6740
#>
#> 'Positive' Class : no
#>
Pada menggunakan Model Random Forest didapati hasil sebesar 89,7%
Pada pembuatan model klasifikasi dengan menggunakan Naive Baiyes, Decision Tree, dan Random Forest pada kasus telemarketing di bank portugal. Model yang memiliki Accuracy paling bagus menggunakan model Random Forest dengan sebesar 89,7%