Loading the Packages

#install.packages("mlr3pipelines")
library(mlr3pipelines)
library(mlr3verse)
library(mlr3learners)
library(data.table)

Diabetes Data Set

Data yang digunakan pada modul ini adalah data tentang kasus penyakit Diabetes, yang telah digunakan pada ilustrasi modul sebelumnya.

data_diabetes<-read.csv("https://raw.githubusercontent.com/gerrydito/Model-Klasifikasi/master/Praktikum/KNN/diabetes.csv", stringsAsFactors = TRUE)

Kita akan jalankan syntax berikut untuk mengingat kembali informasi tentang data tersebut.

dim(data_diabetes)
## [1] 752   9
head(data_diabetes)
skimr::skim(data_diabetes)
Data summary
Name data_diabetes
Number of rows 752
Number of columns 9
_______________________
Column type frequency:
factor 1
numeric 8
________________________
Group variables None

Variable type: factor

skim_variable n_missing complete_rate ordered n_unique top_counts
Outcome 0 1 FALSE 2 Con: 490, Cas: 262

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
Pregnancies 0 1 3.86 3.37 0.00 1.00 3.00 6.00 17.00 ▇▃▂▁▁
Glucose 0 1 120.70 31.75 0.00 99.00 117.00 140.00 199.00 ▁▁▇▆▂
BloodPressure 0 1 69.08 19.36 0.00 62.00 72.00 80.00 122.00 ▁▁▇▇▁
SkinThickness 0 1 20.51 15.96 0.00 0.00 23.00 32.00 99.00 ▇▇▂▁▁
Insulin 0 1 79.84 114.69 0.00 0.00 34.00 128.25 846.00 ▇▁▁▁▁
BMI 0 1 32.01 7.80 0.00 27.30 32.00 36.60 67.10 ▁▃▇▂▁
DiabetesPedigreeFunction 0 1 0.47 0.33 0.08 0.24 0.37 0.63 2.42 ▇▃▁▁▁
Age 0 1 33.21 11.74 21.00 24.00 29.00 41.00 81.00 ▇▃▁▁▁

Defining The Task

Pada ilustrasi ini, peubah yang diamati adalah peubah outcome yang menyatakan seseorang terkena kasus penyakit diabetes atau tidak. Pada ekosistem mlr3, kita perlu mendefinisikan task yang akan digunakan, seperti pada syntax berikut ini.

task_diabetes = TaskClassif$new(id="diabetes",backend = data_diabetes,
                                target = "Outcome",positive ="Case")

Artificial Neural Network (ANN)

Metode ini memproses informasi dari data sebagai input layer, proses tersebut dilanjutkan pada layer berikutnya yaitu hidden layer, dimana setiap hidden layer dapat memuat beberapa nodes. Gambar berikut diperoleh dari Yolanda (2019) menunjukkan ilustrasi arsitektur metode ANN.

Neural network dapat dilakukan menggunakan fungsi nnet() yang terdapat pada package nnet, atau dapat pula dipanggil dari package mlr3extralearners. Daftar metode yang terdapat pada package ini dapat dilihat pada link berikut: https://mlr3extralearners.mlr-org.com/articles/learners/list_learners.html

#remotes::install_github("mlr-org/mlr3extralearners")
library(mlr3extralearners)
## 
## Attaching package: 'mlr3extralearners'
## The following objects are masked from 'package:mlr3':
## 
##     lrn, lrns
as.data.table(lrn("classif.nnet")$param_set)

Pada ilustrasi ini dimisalkan kita akan memodelkan data diabetes menggunakan metode ANN dengan banyaknya nodes pada hidden layer adalah 8.

learner_nn<-lrn("classif.nnet", size=8)

learner_nn
## <LearnerClassifNnet:classif.nnet>
## * Model: -
## * Parameters: size=8
## * Packages: nnet
## * Predict Type: prob
## * Feature types: numeric, factor, ordered
## * Properties: multiclass, twoclass, weights

Seperti yang dapat dilihat pada output di atas, algoritma nn yang digunakan di sini hanya menerima tipe peubah numeric, factor, dan ordered, sebagai input. Oleh karenanya, beberapa peubah integer pada data diabetes akan diubah menjadi tipe numeric terlebih dahulu sebelum menerapkan algoritma tersebut pada data.

data_diabetes2<-data_diabetes
data_diabetes2[,c(1:5, 8)]<-lapply(data_diabetes2[,c(1:5, 8)], as.numeric)

task_diabetes2<-TaskClassif$new(id="diabetes2",backend = data_diabetes2,
                                target = "Outcome",positive ="Case")

set.seed(1)
learner_nn$train(task = task_diabetes2)
## # weights:  81
## initial  value 515.874029 
## iter  10 value 476.914808
## iter  20 value 452.378542
## iter  30 value 434.710869
## iter  40 value 428.549449
## iter  50 value 423.438192
## iter  60 value 417.964064
## iter  70 value 417.640296
## iter  80 value 416.113716
## iter  90 value 415.721111
## iter 100 value 414.506888
## final  value 414.506888 
## stopped after 100 iterations

Seandainya kita menginginkan untuk membagi data menjadi dua bagian, data training data data testing, maka kita dapat menentukan terlebih dulu dengan fungsi rsmp() seperti yang telah dibahas pada modul sebelumnya.

resample_diabetes1 = rsmp("holdout", ratio = 0.8)

set.seed(2020)
train_test_diabetes1 = resample(task = task_diabetes2,
                               learner = learner_nn,
                               resampling = resample_diabetes1,
                               store_models = TRUE
)
## INFO  [18:35:10.943] Applying learner 'classif.nnet' on task 'diabetes2' (iter 1/1) 
## # weights:  81
## initial  value 392.161360 
## iter  10 value 360.435858
## iter  20 value 351.832591
## iter  30 value 343.310332
## iter  40 value 332.644844
## iter  50 value 322.557773
## iter  60 value 317.666203
## iter  70 value 313.414293
## iter  80 value 310.834335
## iter  90 value 310.130739
## iter 100 value 310.125650
## final  value 310.125650 
## stopped after 100 iterations
prediksi_test = as.data.table(train_test_diabetes1$prediction())

head(prediksi_test)

Model Evaluation

Selanjutnya evaluasi dapat dilakukan pada hasil validasi menggunakan data testing.

train_test_diabetes1$prediction()$confusion
##          truth
## response  Case Control
##   Case      19      14
##   Control   40      77
train_test_diabetes1$aggregate(list(msr("classif.acc"),
                                   msr("classif.specificity"),
                                   msr("classif.sensitivity"),
                                   msr("classif.auc")
))
##         classif.acc classif.specificity classif.sensitivity         classif.auc 
##           0.6400000           0.8461538           0.3220339           0.6164090

AUC (area under curve) merupakan luas daerah dibawah kurva ROC (receiver operating characteristics), yang akan diperlihatkan pada subbagian berikut ini.

ROC (Receiver Operating Characteristics) Curve

“Beberapa algoritma, selain dapat memprediksi kelas, juga dapat memprediksi peluang suatu pengamatan termasuk ke dalam salah satu kelas. Terkadang, batas 0.5 digunakan sebagai threshold untuk menentukan kelas prediksi untuk pengamatan tersebut. Namun, hal ini tidak selalu tepat untuk dilakukan. Improvement dilakukan menggunakan kurva ROC yang mempertimbangkan semua kemungkinan nilai threshold tersebut, serta memvisualisasikan trade-off antara sensitivity (true positive rate) dan specitivity (true negative rate).”, (Baumer et al., 2017).

Selain itu, kurva ROC juga mencerminkan performa model. Bentuk kurva yang cenderung melengkung ke pojok kiri atas menunjukkan performa yang lebih baik. Oleh karenanya, semakin besar luas di bawah kurva ROC menunjukkan performa model yang semakin baik. Hal ini disebut dengan istilah area under curve (AUC).

library(mlr3viz)

pred=train_test_diabetes1$prediction()

# TPR vs FPR / Sensitivity vs (1 - Specificity)
ggplot2::autoplot(pred, type = "roc")

Introduction to mlr3pipelines

Becker et al. (2020) menjelaskan mlr3pipelines sebagai suatu perangkat pemrograman dataflow. Alur kerja dalam suatu machine learning dapat dituliskan dalam bentuk “Graphs” atau “Pipelines” yang menunjukkan flow data antara prapemrosesan, model fitting, dan ensemble learning. Berikut adalah ilustrasi linear preprocessing ( Bischl et al.,2020).

graph_pp = po("scale") %>>%
po("encode") %>>%
po("imputemedian") %>>%
lrn("classif.rpart")

plot(graph_pp)

PipeOps (PO’s)

PO adalah blok penyusun pada mlr3pipelines. Contoh penggunaannya adalah sebagai berikut.

pca=mlr_pipeops$get("pca")

Atau dapat pula dilakukan dengan cara berikut.

pca=po("pca")

Kita dapat menginput metode pra-pemrosesan data seperti PCA, imputasi, dan juga algoritma pemodelan. Untuk mengetahui daftar object yang dapat diakses sebagai po, kita dapat mengaksesnya dengan cara berikut.

library("mlr3pipelines")
as.data.table(mlr_pipeops)

Pipeline Operator : %>>%

Operator %>>% digunakan untuk menghubungkan antar po, seperti pada contoh berikut ini.

library("magrittr")

po1=po("scale")
po2=po("pca")

gr = po1 %>>% po2

gr$plot(html = FALSE)

Pada ilustrasi tersebut, kita memiliki 2 po, yaitu operasi scale, kemudian dilanjutkan dengan pca.

Ensemble Learning

Bagging

single_path=po("subsample") %>>% lrn("classif.rpart", predict_type="prob")

graph_bag=ppl("greplicate", single_path, n=3) %>>%
  po("classifavg")

plot(graph_bag)

as.data.table(mlr_pipeops)
#learn_graphbag=GraphLearner$new(graph_bag)

train_test_diabetes2 = resample(task = task_diabetes,
                               learner = graph_bag,
                               resampling = resample_diabetes1,
                               store_models = TRUE)
## INFO  [18:35:14.624] Applying learner 'subsample_1.subsample_2.subsample_3.classif.rpart_1.classif.rpart_2.classif.rpart_3.classifavg' on task 'diabetes' (iter 1/1)
pred2=train_test_diabetes2$prediction()
ggplot2::autoplot(pred2, type = "roc")

train_test_diabetes2$prediction()$confusion
##          truth
## response  Case Control
##   Case      30      19
##   Control   26      75
train_test_diabetes2$aggregate(list(msr("classif.acc"),
                                   msr("classif.specificity"),
                                   msr("classif.sensitivity"),
                                   msr("classif.auc")
))
##         classif.acc classif.specificity classif.sensitivity         classif.auc 
##           0.7000000           0.7978723           0.5357143           0.7847644

Stacking

graph_stack=gunion(list(
  po("learner_cv", learner=lrn("regr.lm")),
  po("learner_cv", learner=lrn("regr.svm")),
  po("nop"))) %>>%
  po("featureunion") %>>%
  lrn("regr.ranger")

plot(graph_stack)

Applying Stacking Method on Diabetes Dataset

stacking=gunion(list(
  po("learner_cv", learner=lrn("classif.ranger", predict_type="prob")),
  po("learner_cv", learner=lrn("classif.kknn", predict_type="prob")))) %>>%
  po("featureunion") %>>%
  lrn("classif.log_reg", predict_type="prob")

stacking$plot()

Comparing the Performance of Individual versus Ensemble Model

set.seed(20202311)
cv10_instance = rsmp("cv")$instantiate(task_diabetes)
bmr = benchmark(data.table(
  task = list(task_diabetes),
  learner = list(
    stacking,
    lrn("classif.ranger", predict_type="prob"),
    lrn("classif.kknn", predict_type="prob"),
    lrn("classif.log_reg", predict_type="prob")),
  resampling = list(cv10_instance)))
result=bmr$aggregate(list(msr("classif.acc"),
                   msr("classif.auc")
                   ))

result[,c("learner_id", "classif.acc", "classif.auc")]

References

Becker, M., Binder, M.,Bischl, B., Lang, M., Pfisterer, F.,Reich, N.G., Richter, J., Schratz, P., and Sonabend, R. (2020, November 22). mlr3 Book. https://mlr3book.mlr-org.com

Bischl, B., Pfisterer, F., and Binder, M. (2020, May 28). Pipelines and AutoML with mlr3. https://github.com/mlr-org/mlr-outreach/tree/master/2020_whyr

Yolanda, R. (2019, June 26). ANN classification with ‘nnet’ package in R. Medium. https://medium.com/@yolandawiyono98/ann-classification-with-nnet-package-in-r-3c4dc14d1f14