install.packages("rpart")
install.packages("ranger")
Statistical Machine Learning dengan tidymodels
R memiliki beberapa ekosistem yang bisa digunakan untuk menerapkan statistical machine learning, seperti
Manfaat dari ekosistem-ekosistem ini adalah menggabungkan model-model statistical machine lerning yang berasal dari berbagai macam package sehingga mudah untuk digunakan karena sintaksnya yang seragam.
Pada tulisan ini kita akan menggunakan ekosistem tidymodels
untuk menerapkan statistical machine learning. Jika tertarik belajar lebih lanjut tentang tidymodels
bisa membuka sumber-sumber berikut
- Buku Tidy Modeling with R
- Website Learning tidymodels
- Youtube Playlist TidyX - tidymodels
Machine learning Workflow
Data
This dataset classifies people described by a set of attributes as good or bad credit risks.
Author: Dr. Hans Hofmann Source: UCI - 1994 Please cite: Dua, D. and Graff, C. (2019). UCI Machine Learning Repository [http://archive.ics.uci.edu/ml]. Irvine, CA: University of California, School of Information and Computer Science.
Attribute description
- Status of existing checking account, in Deutsche Mark.
- Credit history (credits taken, paid back duly, delays, critical accounts)
- Purpose of the credit (car, television,…)
- Credit amount
- Status of savings account/bonds, in Deutsche Mark.
- Present employment, in number of years.
- Installment rate in percentage of disposable income
- Personal status (married, single,…) and sex
- Other debtors / guarantors
- Present residence since X years
- Property (e.g. real estate)
- Age in years
- Other installment plans (banks, stores)
- Housing (rent, own,…)
- Number of existing credits at this bank
- Job
- Number of people being liable to provide maintenance for
- Telephone (yes,no)
- Foreign worker (yes,no)
- Duration in months
data bisa didownload pada link berikut:
Package
Package diatas harus dinstall tapi tidak perlu dipanggil menggunakan library
library(skimr)
library(DataExplorer)
library(tidyverse)
library(tidymodels)
library(rpart.plot)
Import Data
<- read.csv("german_credit.csv",stringsAsFactors = TRUE)
df glimpse(df)
Rows: 1,000
Columns: 21
$ checking_status <fct> '<0', '0<=X<200', 'no checking', '<0', '<0', 'n…
$ duration <int> 6, 48, 12, 42, 24, 36, 24, 36, 12, 30, 12, 48, …
$ credit_history <fct> 'critical/other existing credit', 'existing pai…
$ purpose <fct> radio/tv, radio/tv, education, furniture/equipm…
$ credit_amount <int> 1169, 5951, 2096, 7882, 4870, 9055, 2835, 6948,…
$ savings_status <fct> 'no known savings', '<100', '<100', '<100', '<1…
$ employment <fct> '>=7', '1<=X<4', '4<=X<7', '4<=X<7', '1<=X<4', …
$ installment_commitment <int> 4, 2, 2, 2, 3, 2, 3, 2, 2, 4, 3, 3, 1, 4, 2, 4,…
$ personal_status <fct> 'male single', 'female div/dep/mar', 'male sing…
$ other_parties <fct> none, none, none, guarantor, none, none, none, …
$ residence_since <int> 4, 2, 3, 4, 4, 4, 4, 2, 4, 2, 1, 4, 1, 4, 4, 2,…
$ property_magnitude <fct> 'real estate', 'real estate', 'real estate', 'l…
$ age <int> 67, 22, 49, 45, 53, 35, 53, 35, 61, 28, 25, 24,…
$ other_payment_plans <fct> none, none, none, none, none, none, none, none,…
$ housing <fct> own, own, own, 'for free', 'for free', 'for fre…
$ existing_credits <int> 2, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1,…
$ job <fct> skilled, skilled, 'unskilled resident', skilled…
$ num_dependents <int> 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
$ own_telephone <fct> yes, none, none, none, none, yes, none, yes, no…
$ foreign_worker <fct> yes, yes, yes, yes, yes, yes, yes, yes, yes, ye…
$ class <fct> good, bad, good, good, bad, good, good, good, g…
Eksplorasi Data
plot_intro(df,ggtheme = theme_classic())
Eksploarasi Variabel Respon
%>%
df count(class) %>%
mutate(percent=n*100/sum(n),label=str_c(round(percent,2),"%")) %>%
ggplot(aes(x="",y=n,fill=class))+
geom_col()+
geom_text(aes(label = label),
position = position_stack(vjust = 0.5)) +
coord_polar(theta = "y")+
theme_void()
Eksplorasi Secara Numerik
skim_without_charts(df)
Name | df |
Number of rows | 1000 |
Number of columns | 21 |
_______________________ | |
Column type frequency: | |
factor | 14 |
numeric | 7 |
________________________ | |
Group variables | None |
Variable type: factor
skim_variable | n_missing | complete_rate | ordered | n_unique | top_counts |
---|---|---|---|---|---|
checking_status | 0 | 1 | FALSE | 4 | ‘no: 394,’<0: 274, ‘0<: 269,’>=: 63 |
credit_history | 0 | 1 | FALSE | 5 | ’ex: 530, ’cr: 293, ’de: 88, ’al: 49 |
purpose | 0 | 1 | FALSE | 10 | rad: 280, ’ne: 234, fur: 181, ’us: 103 |
savings_status | 0 | 1 | FALSE | 5 | ’<1: 603, ’no: 183, ’10: 103, ’50: 63 |
employment | 0 | 1 | FALSE | 5 | ‘1<: 339,’>=: 253, ‘4<: 174,’<1: 172 |
personal_status | 0 | 1 | FALSE | 4 | ’ma: 548, ’fe: 310, ’ma: 92, ’ma: 50 |
other_parties | 0 | 1 | FALSE | 3 | non: 907, gua: 52, ’co: 41 |
property_magnitude | 0 | 1 | FALSE | 4 | car: 332, ’re: 282, ’li: 232, ’no: 154 |
other_payment_plans | 0 | 1 | FALSE | 3 | non: 814, ban: 139, sto: 47 |
housing | 0 | 1 | FALSE | 3 | own: 713, ren: 179, ’fo: 108 |
job | 0 | 1 | FALSE | 4 | ski: 630, ’un: 200, ’hi: 148, ’un: 22 |
own_telephone | 0 | 1 | FALSE | 2 | non: 596, yes: 404 |
foreign_worker | 0 | 1 | FALSE | 2 | yes: 963, no: 37 |
class | 0 | 1 | FALSE | 2 | goo: 700, bad: 300 |
Variable type: numeric
skim_variable | n_missing | complete_rate | mean | sd | p0 | p25 | p50 | p75 | p100 |
---|---|---|---|---|---|---|---|---|---|
duration | 0 | 1 | 20.90 | 12.06 | 4 | 12.0 | 18.0 | 24.00 | 72 |
credit_amount | 0 | 1 | 3271.26 | 2822.74 | 250 | 1365.5 | 2319.5 | 3972.25 | 18424 |
installment_commitment | 0 | 1 | 2.97 | 1.12 | 1 | 2.0 | 3.0 | 4.00 | 4 |
residence_since | 0 | 1 | 2.85 | 1.10 | 1 | 2.0 | 3.0 | 4.00 | 4 |
age | 0 | 1 | 35.55 | 11.38 | 19 | 27.0 | 33.0 | 42.00 | 75 |
existing_credits | 0 | 1 | 1.41 | 0.58 | 1 | 1.0 | 1.0 | 2.00 | 4 |
num_dependents | 0 | 1 | 1.16 | 0.36 | 1 | 1.0 | 1.0 | 1.00 | 2 |
Eksplorasi Hubungan prediktor kategorik dengan respon
plot_bar(data = df,by = "class",
ggtheme = theme_classic(),
ncol = 2)
Eksplorasi Hubungan prediktor kontinu dengan respon
plot_boxplot(data = df,by = "class",
ggtheme = theme_classic(),
geom_boxplot_args = list(fill="#03A9F4"))
Eksploarsi Hubungan antar Prediktor Kontinu
plot_correlation(data = df,
type = "continuous",
cor_args = list(method="spearman"),
ggtheme = theme_classic(),
theme_config = list(legend.position = "none",
axis.text.x=element_text(angle = 90)))
Praproses Data
Dalam ekosistem tidymodels
, praproses data dapat dilakukan dengan package recipe
(read more) dan juga turunannya seperti:
- package
themis
untuk menangani masalah class imbalanced - package
embed
untuk predictors transformation (encoding) - package
textrecipes
untuk praproses text data
Tahap praproses data terdiri dari
- Data Cleaning. Menangani Missing Value, outlier, duplikasi data dan kesalahan input data.
- Feature Engineering. Feature Engineering adalah proses transformasi data mentah menjadi suatu fitur yang lebih baik dalam merepresentasikan pola yang terkandung di dalam data, sehingga dapat meningkatkan performa model.
Berikut adalah ilustrasi penggunaan package recipe untuk Feature Engineering.
Disclaimer: praproses di bawah hanya diperuntukan untuk ilustrasi penggunaan package
recipe
saja sehingga tidak memiliki alasan khusus kenapa di terapan tahapan praproses dibawah ini.
Tanpa Praproses
Kita hanya perlu menuliskan fungsi recipe
dari package recipe
dengan argumen formula
dan data
.
<- recipe(formula=class~.,data = df) no_preproc
Dengan Praproses
Kita perlu menambahkan fungsi step_*
setelah fungsi recipe
. Dalam ilustrasi ini, kita akan mereduksi dimensi seluruh variabel prediktor kontinu ke 3 dimensi saja dengan metode PCA. Hal ini dapat dicapai dengan menggunakan fungsi step_pca
.
<- recipe(class~.,data = df) %>%
basic_prepoc step_pca(all_numeric_predictors(),
num_comp = 3,
options = list(center = TRUE,
scale. = TRUE))
- fungsi
all_numeric_predictors()
menandakan bahwa variabel yang akan direduksi adalah semua variabel prediktor kontinu num_comp=3
berarti kita akan mereduksi dimensi menjadi 3 dimensioptions = list(center = TRUE,scale. = TRUE)
berarti sebelum direduksi dimensi variabel asalnya kita rubah menjadi variabel-variabel yang memiliki rata-rata yang mendekati 0 dan standar deviasi mendekati 1.
Kemudian, kita bisa memeriksa bagaimana hasi praproses dengan menggunakan fungsi prep
dan bake
seperti dibawah ini
## memeriksa hasil praproses
%>%
basic_prepoc prep() %>%
bake(new_data = NULL)
## memeriksa hasil praproses
%>%
basic_prepoc prep() %>%
bake(new_data = NULL) %>%
glimpse()
Rows: 1,000
Columns: 17
$ checking_status <fct> '<0', '0<=X<200', 'no checking', '<0', '<0', 'no c…
$ credit_history <fct> 'critical/other existing credit', 'existing paid',…
$ purpose <fct> radio/tv, radio/tv, education, furniture/equipment…
$ savings_status <fct> 'no known savings', '<100', '<100', '<100', '<100'…
$ employment <fct> '>=7', '1<=X<4', '4<=X<7', '4<=X<7', '1<=X<4', '1<…
$ personal_status <fct> 'male single', 'female div/dep/mar', 'male single'…
$ other_parties <fct> none, none, none, guarantor, none, none, none, non…
$ property_magnitude <fct> 'real estate', 'real estate', 'real estate', 'life…
$ other_payment_plans <fct> none, none, none, none, none, none, none, none, no…
$ housing <fct> own, own, own, 'for free', 'for free', 'for free',…
$ job <fct> skilled, skilled, 'unskilled resident', skilled, s…
$ own_telephone <fct> yes, none, none, none, none, yes, none, yes, none,…
$ foreign_worker <fct> yes, yes, yes, yes, yes, yes, yes, yes, yes, yes, …
$ class <fct> good, bad, good, good, bad, good, good, good, good…
$ PC1 <dbl> -1.4374699, 2.2597114, -0.5184279, 2.6376242, 0.74…
$ PC2 <dbl> 2.7622605, -1.8069247, 1.2076170, 1.3624068, 2.734…
$ PC3 <dbl> -0.80190159, -0.09224456, 1.86397366, 1.01548818, …
Selanjutnya kita dapat menambahkan tahap praproses lain dengan menuliskan fungsi step_*
lainnya. Sebagai ilustrasi kita akan mereduksi banyaknya kategori di variabel purpose
dengan menyatukan beberapa kategori yang memiliki frekuensi sedikit
%>%
df count(purpose) %>%
arrange(n)
Misal kita akan menggabungkan kategori yang memiliki frekuensi dibawah 50. Berdasarkan output diatas, maka kategori yang akan digabungkan adalah kategori retraining
,domestic appliance
, other
dan repairs
.
Kita bisa mereduksi banyaknya kategori dalam suatu variabel kategorik dengan fungsi step_other
.
<- basic_prepoc %>%
basic_prepoc step_other(purpose,threshold = 50)
threshold = 50
berarti kategori yang memiliki frekuensi dibawah 50 akan digabung.
Berikut adalah hasil praprosesnya
## memeriksa hasil praproses
%>%
basic_prepoc prep() %>%
bake(new_data = NULL) %>%
glimpse()
Rows: 1,000
Columns: 17
$ checking_status <fct> '<0', '0<=X<200', 'no checking', '<0', '<0', 'no c…
$ credit_history <fct> 'critical/other existing credit', 'existing paid',…
$ purpose <fct> radio/tv, radio/tv, education, furniture/equipment…
$ savings_status <fct> 'no known savings', '<100', '<100', '<100', '<100'…
$ employment <fct> '>=7', '1<=X<4', '4<=X<7', '4<=X<7', '1<=X<4', '1<…
$ personal_status <fct> 'male single', 'female div/dep/mar', 'male single'…
$ other_parties <fct> none, none, none, guarantor, none, none, none, non…
$ property_magnitude <fct> 'real estate', 'real estate', 'real estate', 'life…
$ other_payment_plans <fct> none, none, none, none, none, none, none, none, no…
$ housing <fct> own, own, own, 'for free', 'for free', 'for free',…
$ job <fct> skilled, skilled, 'unskilled resident', skilled, s…
$ own_telephone <fct> yes, none, none, none, none, yes, none, yes, none,…
$ foreign_worker <fct> yes, yes, yes, yes, yes, yes, yes, yes, yes, yes, …
$ class <fct> good, bad, good, good, bad, good, good, good, good…
$ PC1 <dbl> -1.4374699, 2.2597114, -0.5184279, 2.6376242, 0.74…
$ PC2 <dbl> 2.7622605, -1.8069247, 1.2076170, 1.3624068, 2.734…
$ PC3 <dbl> -0.80190159, -0.09224456, 1.86397366, 1.01548818, …
## memeriksa hasil praproses
%>%
basic_prepoc prep() %>%
bake(new_data = NULL) %>%
count(purpose) %>%
arrange(n)
atau kita bisa menuliskan sintaksnya secara langsung
<- recipe(class~.,data = df) %>%
basic_prepoc step_pca(all_numeric_predictors(),
num_comp = 3,
options = list(center = TRUE,
scale. = TRUE)) %>%
step_other(purpose,threshold = 50)
## memeriksa hasil praproses
%>%
basic_prepoc prep() %>%
bake(new_data = NULL) %>%
glimpse()
Rows: 1,000
Columns: 17
$ checking_status <fct> '<0', '0<=X<200', 'no checking', '<0', '<0', 'no c…
$ credit_history <fct> 'critical/other existing credit', 'existing paid',…
$ purpose <fct> radio/tv, radio/tv, education, furniture/equipment…
$ savings_status <fct> 'no known savings', '<100', '<100', '<100', '<100'…
$ employment <fct> '>=7', '1<=X<4', '4<=X<7', '4<=X<7', '1<=X<4', '1<…
$ personal_status <fct> 'male single', 'female div/dep/mar', 'male single'…
$ other_parties <fct> none, none, none, guarantor, none, none, none, non…
$ property_magnitude <fct> 'real estate', 'real estate', 'real estate', 'life…
$ other_payment_plans <fct> none, none, none, none, none, none, none, none, no…
$ housing <fct> own, own, own, 'for free', 'for free', 'for free',…
$ job <fct> skilled, skilled, 'unskilled resident', skilled, s…
$ own_telephone <fct> yes, none, none, none, none, yes, none, yes, none,…
$ foreign_worker <fct> yes, yes, yes, yes, yes, yes, yes, yes, yes, yes, …
$ class <fct> good, bad, good, good, bad, good, good, good, good…
$ PC1 <dbl> -1.4374699, 2.2597114, -0.5184279, 2.6376242, 0.74…
$ PC2 <dbl> 2.7622605, -1.8069247, 1.2076170, 1.3624068, 2.734…
$ PC3 <dbl> -0.80190159, -0.09224456, 1.86397366, 1.01548818, …
%>%
basic_prepoc prep() %>%
bake(new_data = NULL) %>%
count(purpose)
Fungsi step_*
lainnya bisa diakses pada website recipe
berikut ini
Model Training and Evaluation
Tahap ini harusnya berada di dalam Tahap Model Selection. Namun diletakan sebelum Model Selection hanya untuk ilustrasi saja. Pada Praktiknya bisa langsung ke Model Selection.
Mendefinisikan model
Model-model yang bisa digunakan dalam ekosistem tidymodels
ada di dalam pacakge parsnip
(read more).Selain itu package turunan dari parsnip
seperti brulee
dan bonsai
juga bisa digunakan.
Package parsnip
menggunakan istilah engine
untuk mengakses package asal dari model. Misalkan saja untuk model decision_tree
kita bisa menggunakan package/engine rpart
dan C5.0
(dengan catatan kita harus menginstall package tersebut). Daftar lengkap package/engine yang bisa digunakan untuk decision_tree
ada di website parsnip
.
Berikut adalah ilustrasi penggunaanya
<- decision_tree() %>%
tree_mod set_engine(engine = "rpart") %>%
set_mode(mode = "classification")
- fungsi
decision_tree
berarti kita ingin menggunakan model decision tree - fungsi
set_engine
digunakan untuk mengakses package/engine yang digunakan untuk model - fungsi
set_mode
digunakan untuk menentukan apakah problem yang dihadapi merupakanclassification
atauregression
Pembagian Data
Tahap pembagian data ini sangat bergantung pada package rsample
(read more). Metode-metode yang ada di dalam rsample
adalah
- Holdout Sample dengan fungsi
initial_split
- Cross Validation dengan fungsi
vfold_cv
- Group Cross Validation dengan fungsi
group_vfold_cv
- Leave-One-Out Cross-Validation dengan fungsi
loo_cv
<- initial_split(data = df,
basic_split prop = 0.8,
strata = "class")
data = df
untuk menentukan data yang akan dilakukan pembagianprop=0.8
proporsi pembagian yang dialokasikan ke data trainingstrata = "class"
teknik sampling yang digunakan untuk melakukan pembagian adalah Stratified Random Sampling dengan didasarkan stratifikasi pada peubah responclass
.
Berikut adalah hasil pembagianya
tidy(basic_split) %>%
count(Data)
Training (Analysis) data yang kita dapatkan adalah 800 amatan atau \(0.8 \times 1000\), sedangkan Testing (Assessment) data yang didapatkan adalah 200 amatan atau \((1-0.8)*1000\).
Berikut adalah sintaks untuk memesiahkan training data dan testing data.
<- training(basic_split)
train_df dim(train_df)
[1] 800 21
<- testing(basic_split)
test_df dim(test_df)
[1] 200 21
- fungsi
training
berguna memisahkan training data dari data awal - fungsi
testing
berguna memisahkan testing data dari data awal
Model Training
Model training bisa dilakukan dengan memanfaatkan fungsi workflow
seperti dibawah ini:
<- workflow() %>%
tree_mod_trained add_recipe(recipe = no_preproc) %>%
add_model(spec = tree_mod) %>%
fit(data=train_df)
- fungsi
add_recipe
digunakan untuk menambahkan tahap praproses data menggunakan packagerecipe
- fungsi
add_model
digunakan untuk menambahkan model yang akan dilakukan training. - fungsi
fit
digunakan untuk menjalankan training.
Model Evaluation
Prediksi Testing Data
Berikut adalah sintaks mendapatkan prediksi testing data dalam bentuk kategori (factor
)
<- tree_mod_trained %>%
pred_tree_mod predict(new_data = test_df,type = "class")
pred_tree_mod
type = "class"
argumen untuk mendapatkan prediksi dalam bentuk kategori (factor
)- Pada dasarnya hasil prediksi dari tree berbentuk peluang, secara otomatis diubah menjadi kategori variabel respon dengan threshold=0.5
Berikut adalah sintaks mendapatkan prediksi testing data dalam bentuk peluang
<- tree_mod_trained %>%
prob_tree_mod predict(new_data = test_df,type = "prob")
prob_tree_mod
type = "prob"
argumen untuk mendapatkan prediksi dalam bentuk [kategori (factor
) peluang
Confussion Matrix
Berikut adalah sintaks untuk menambahkan kolom variabel respon dari testing data
<- pred_tree_mod %>%
pred_tree_mod #menambahkan kolom truth
mutate(truth=test_df$class)
pred_tree_mod
Selanjutnya, kita akan mengeluarkan confussion matriks
<- pred_tree_mod %>%
confussion_matrix conf_mat(truth=truth,estimate=.pred_class)
Confusion matriks dapat ditampilkan dalam bentuk chart sebagai berikut:
autoplot(confussion_matrix,type = "heatmap")+
scale_fill_gradient(low = "#F4AFAB",high = "#EE847E")
Scale for fill is already present.
Adding another scale for fill, which will replace the existing scale.
- fungsi
autoplot
digunakan untuk mennampilkan confussion matrix - fungsi
scale_fill_gradient
digunakan untuk memberi warna pada confussion matrix - Berdasarkan output confussion matrix, terlihat bahwa sebagai hasil prediksi dari kategori
bad
banyak yang salah prediksi dibandingkan dengan hasil prediksi dari kategorigood
.
Evaluasi model dengan metric
Pertama-tama, kita harus definsikan terlebih dahulu metrics yang kita gunakan. Metrics-metrics ini didapatkan dengan menggunakan package yardstick
(read more).
<- metric_set(accuracy,
multi_metric
sensitivity,
specificity,
bal_accuracy, f_meas)
- fungsi
metric_set
digunakan untuk menyatukan beberapa metrik evaluasi. f_meas
adalah metrik f1-score
Berikut adalah hasil evaluasi prediksi pada testing data menggunakan 5 metrik yang sudah didefinisikan
%>%
pred_tree_mod #menambahkan kolom truth
mutate(truth=test_df$class) %>%
# evaluasi prediksi berdasarkan metrik
multi_metric(truth = truth,estimate = .pred_class)
Kemudian, metrik auc
dibawah ini digunakan untuk mengevaluasi prediksi dalam bentuk peluang.
%>%
prob_tree_mod mutate(truth=test_df$class) %>%
roc_auc(truth = truth,.pred_bad)
Model Selection
Pada tahap ini kita bisa memilih model yang terbaik untuk kasus data kita. Beberapa langkah di tahap Model Selection sudah dijelaskan di Model Training and Evaluation. Sebagai ilustrasi kita akan membandingkan hasil model pohon, random forest dan regresi logistik.
Mendefinisikan model
Seperti yang dijelaskan sebelumnya, model-model yang ada di package parsnip
berasal dari package-package yang berbeda, berikut rinciannya:
- Decision tree menggunakan package
rpart
- Random Forest menggunakan package
ranger
- Regresi Logistik menggunakan fungsi
glm
dari packagestats
Berikut adalah sintaks untuk mendefinsikan model, penjelasan detailnya sama seperti yang sebelumnya:
<- decision_tree() %>%
tree_mod set_engine(engine = "rpart") %>%
set_mode(mode = "classification")
<- rand_forest() %>%
rf_mod set_engine(engine = "ranger",importance="impurity") %>%
set_mode(mode = "classification")
importance="impurity"
digunakan untuk mengekstrak variable importance dari random forest
<- logistic_reg() %>%
lr_mod set_engine(engine = "glm") %>%
set_mode(mode = "classification")
Pembagian Data
Pembagian data dilakukan dengan menggunakan metode Cross Validation dengan fungsi vfold_cv
. Berikut sintaksnya:
<- vfold_cv(data = df,v = 10,strata = "class") folds
v = 10
untuk menentukan banyaknya fold yang digunakan dalam Cross Validation adalah 10.strata = "class"
metode sampling yang digunakan adalah Stratified Random Sampling dengan stratifikasi berdasarkan kolomclass
yang berperan sebagai variabel respon.
Model Training and Evaluation
Model Training and Evaluation akan dilakukan dengan bantuan fungsi workflow_set
dan workflow_map
. Kedua fungsi ini memungkinkan kita untuk melakukan pemilihan model terbaik berdasarkan metrik-metrik tertentu.
Fungsi workflow_set
digunakan untuk menginput tahap praproses data dan model apa yang digunakan. Sementara itu, fungsi workflow_map
digunakan untuk menginputkan metode pembagian data dan metrik sekaligus melakukan model training and evaluation. Berikut adalah sintaksnya:
<- workflow_set(preproc = list(no=no_preproc,basic=basic_prepoc),
mod_selection_trained models = list(tree_mod,rf_mod,lr_mod),
cross = TRUE ) %>%
workflow_map(fn = "fit_resamples",
resamples= folds,
metrics = multi_metric,
control = control_resamples(save_workflow = TRUE),
seed = 2045)
- argumen
preproc
digunakan untuk menginputkan tahap praproses data - sintaks
no=
danbasic=
digunakan untuk memberi nama pada tahap praproses data - argumen
models
digunakan untuk menginputkan model - argumen
cross=TRUE
menandakan bahwa tahap praproses data dan model dipasangkan secara kombinasi. Sebagai ilustrasi tahap praproses databasic
akan dipasangkan dengan model decision tree, random forest dan regresi logistik. - argumen
cross=TRUE
menandakan bahwa tahap praproses data dan model dipasangkan sesuai dengan urutanyan. Sebgai ilustrasi tahap praproses datano
dipasangkan dengan decision. tree dan tahap praproses databasic
akan dipasangkan dengan random forest. Semetara model regresi logistik tidak punya tahap praproses data sehingga akan menyebabkanerror
. - argumen
fn
digunakan untuk menentukan fungsi tidymodels yang akan digunakan. - argumen
resamples
digunakan untuk menginputkan metode pembagian data - argumen
metrics
digunakan untuk menginputkan metrik-metrik. - untuk argumen
control
bisa melihat help untuk lebih jelas.
Hasil training and evaluation pada sintaks sebelumnya disimpan dalam objek mod_selection_trained
. Selanjutnya kita akan menampilkan hasilnya dengan menggunakan ranking.
<- function(data){
custom_output %>%
data mutate(method = map_chr(wflow_id, ~ str_split(.x, "_",simplify = TRUE)[1])) %>%
select(method,model,.metric,mean,std_err,rank)
}
<- rank_results(mod_selection_trained,
mod_selection_result rank_metric = "bal_accuracy") %>%
custom_output()
- argumen
rank_metric
digunakan untuk menentukan metrik apa yang digunakan sebagai ranking. Dalam hal ini metrik yang digunakan adalah balanced accuracy - fungsi
custom_output
digunakan untuk mengkustomisasi output yang dihasilkan. Fungsi ini bisa tidak perlu dirubah-rubah.
mod_selection_result
%>%
mod_selection_result ggplot(aes(x = rank, y = mean, pch = method, col = model)) +
geom_point(cex = 3)+
facet_wrap(~.metric)+
theme_bw()
Berdasarkan output diatas, kombinasi praproses data dan model yang menempati ranking 1 berdasarkan metrik balanced accuracy adalah no
+logistic_regression
. Sehingga model terbaik yang kita peroleh adalah no
+logistic_regression
.
Setelah mendapatkan model terbaik kita bisa mengekstraknya model tersebut kemudian melakukan training ulang dengan seluruh data yang dimiliki menggunakan fungsi fit_best
berikut ini
<- fit_best(x = mod_selection_trained,
best_mod metric="bal_accuracy")
best_mod
══ Workflow [trained] ══════════════════════════════════════════════════════════
Preprocessor: Recipe
Model: logistic_reg()
── Preprocessor ────────────────────────────────────────────────────────────────
2 Recipe Steps
• step_pca()
• step_other()
── Model ───────────────────────────────────────────────────────────────────────
Call: stats::glm(formula = ..y ~ ., family = stats::binomial, data = data)
Coefficients:
(Intercept)
-1.19590
checking_status'>=200'
1.09701
checking_status'0<=X<200'
0.42800
checking_status'no checking'
1.70474
credit_history'critical/other existing credit'
1.36426
credit_history'delayed previously'
0.81750
credit_history'existing paid'
0.69582
credit_history'no credits/all paid'
-0.03157
purpose'used car'
1.59416
purposebusiness
0.64537
purposeeducation
-0.04216
purposefurniture/equipment
0.79538
purposeradio/tv
0.84234
purposeother
0.77353
savings_status'>=1000'
1.21196
savings_status'100<=X<500'
0.31533
savings_status'500<=X<1000'
0.53504
savings_status'no known savings'
0.94762
employment'>=7'
0.41620
employment'1<=X<4'
0.20199
employment'4<=X<7'
0.81710
employmentunemployed
0.16957
personal_status'male div/sep'
-0.18748
...
and 42 more lines.
untuk memastikan training data yang digunakan adalah seluruh data yang kita miliki, kita bisa menggunakan fungsi dibawah ini:
extract_recipe(best_mod)
── Recipe ──────────────────────────────────────────────────────────────────────
── Inputs
Number of variables by role
outcome: 1
predictor: 20
── Training information
Training data contained 1000 data points and no incomplete rows.
── Operations
• PCA extraction with: duration and credit_amount, ... | Trained
• Collapsing factor levels for: purpose | Trained
Model Interpretability (Explainability)
Tahap ini meruapakan tahap untuk mengerti bagaimana variabel-variabel prediktor berpengaruh terhadap prediksi berdasarkan model terbaik yang diperoleh pada tahap model selection.
Model Terbaik
Karena model terbaik adalah regresi logistik maka kita bisa menggunakan nilai koefisien dari regresi logistik untuk memahami bagaimana variabel-variabel prediktor berpengaruh terhadap prediksi.
tidy(best_mod,exponentiate=TRUE) %>%
mutate(across(where(is.numeric),~round(.x,3)))
Tambahan
Dibawah ini adalah ilustrasi tambahan model interpretability untuk decision tree dan random forest.
# Retraining decision tree dengan seluruh data
<- workflow() %>%
tree_mod_trained add_recipe(recipe = no_preproc) %>%
add_model(spec = tree_mod) %>%
fit(data=df)
extract_fit_engine(tree_mod_trained) %>%
rpart.plot(type = 2,extra = 106,
faclen = -1,
box.palette =blues9[-8:-9] ,
tweak = 1.4)
Warning: Cannot retrieve the data used to build the model (so cannot determine roundint and is.binary for the variables).
To silence this warning:
Call rpart.plot with roundint=FALSE,
or rebuild the rpart model with model=TRUE.
# Retraining Random Forest dengan seluruh data
<- workflow() %>%
rf_mod_trained add_recipe(recipe = no_preproc) %>%
add_model(spec = rf_mod) %>%
fit(data=df)
fungsi plot_importance
merupakan fungsi bantuan yang tidak perlu dirubah-rubah.
<- function(rf){
plot_importance%>%
rf ::importance() %>%
rangeras.data.frame() %>%
rownames_to_column("Variables") %>%
rename("impurity"=".") %>%
arrange(impurity) %>%
mutate(Variables=factor(Variables,levels=Variables)) %>%
ggplot(aes(Variables,impurity))+
geom_col(fill="#03A9F4")+
coord_flip()+
theme_classic()+
theme(axis.line.y = element_blank(),
axis.ticks.y = element_blank(),
axis.title.y = element_blank() )+
scale_y_continuous(expand = c(0,0))
}
extract_fit_engine(rf_mod_trained) %>%
plot_importance()
Model Deployment
Pada tahap ini kita akan menggunakan model untuk keperluan prediksi data baru. Hal pertama yang mungkin kita bisa lakukan adalah menyimpan model terbaik ke file berbentuk rds
sehingga kita bisa menggunakanya tanpa perlu running sintaks dari awal. Tahap penyimpanan ini tidak wajib untuk dilakukan
saveRDS(best_mod,file = "credit_model.rds")
Sintaks diatas berarti kita menyimpan model terbaik dalam file bernama credit_model.rds
.
Prediksi Data Baru
set.seed(2045)
<- df %>%
data_baru_dummy slice_sample(n=7) %>%
select(-class)
data_baru_dummy
<- readRDS("credit_model.rds") %>%
new_pred predict(new_data = data_baru_dummy,type = "class")
new_pred
sintaks readRDS("credit_model.rds")
untuk meload model terbaik yang sudah kita simpan.
write.csv(x = new_pred,file = "submission.csv",row.names = F)