Regresi Logistik dan Kurva ROC dengan mlr3

Informasi

Tutorial ini merupakan kelanjutan dari tutorial https://rpubs.com/gdito/KNN-mlr3. Silahkan kunjungi laman tersebut jika belum familiar dengan mlr3.

Package

Silahkan install jika belum ada

install.packages("tidyverse")
install.packages("mlr3viz") # baru
install.packages("precrec") # baru
install.packages("mlr3")
install.packages("mlr3learners")
library(mlr3)
library(mlr3viz) #baru
library(mlr3learners)

Deskripsi singkat data

Data yang digunakan pada praktikum kali ini adalah data yang bernama Pima Indian Diabetes yang sudah sedikit diedit. Berikut adalah informasi singkat mengenai data

This dataset is originally from the National Institute of Diabetes and Digestive and Kidney Diseases. The objective of the dataset is to diagnostically predict whether or not a patient has diabetes, based on certain diagnostic measurements included in the dataset. Several constraints were placed on the selection of these instances from a larger database. In particular, all patients here are females at least 21 years old of Pima Indian heritage.

Content The datasets consists of several medical predictor variables and one target variable, Outcome. Predictor variables includes the number of pregnancies the patient has had, their BMI, insulin level, age, and so on.

Acknowledgements Smith, J.W., Everhart, J.E., Dickson, W.C., Knowler, W.C., & Johannes, R.S. (1988). Using the ADAP learning algorithm to forecast the onset of diabetes mellitus. In Proceedings of the Symposium on Computer Applications and Medical Care (pp. 261–265). IEEE Computer Society Press.

data ini bisa diperoleh di link berikut ini https://github.com/gerrydito/Model-Klasifikasi/tree/master/Praktikum/KNN

Regresi Logistik menggunakan mlr3

Pada bagian ini akan dibahas bagaimana menerapkan regresi logistik pada package mlr3. Adapun langkah-langkah pemodelannya mirip dengan KNN pada tutorial sebelumnya, yaitu:

  1. Import data di R
  2. Import data ke ekosistem mlr3
  3. Menentukan model yang digunakan
  4. Menentukan cara pembagian data
  5. Melakukan training dan menghitung performa model

Pada tutorial ini, kita tidak akan melakukan tuning hiperparameter karena regresi logistik tidak memiliki hiperparameter bisa bisa di optimasi untuk meningkatkan performa model.

Import data di R

data_diabetes <- read.csv("diabetes.csv",stringsAsFactors = TRUE)
head(data_diabetes)
##   Pregnancies Glucose BloodPressure SkinThickness Insulin  BMI
## 1           6     148            72            35       0 33.6
## 2           1      85            66            29       0 26.6
## 3           8     183            64             0       0 23.3
## 4           1      89            66            23      94 28.1
## 5           0     137            40            35     168 43.1
## 6           5     116            74             0       0 25.6
##   DiabetesPedigreeFunction Age Outcome
## 1                    0.627  50    Case
## 2                    0.351  31 Control
## 3                    0.672  32    Case
## 4                    0.167  21 Control
## 5                    2.288  33    Case
## 6                    0.201  30 Control

Khusus yang menggunakan R versi 4.00 keatas, argumen stringsAsFactors = TRUE disertakan agar data yang berbentuk string bisa berubah menjadi factor.

Import data ke ekosistem mlr3

Pada tahap ini fungsi TaskClassif digunakan untuk import data dari R ke mlr3. Karena target/peubah respon dari data ini adalah peubah biner maka termasuk dalam masalah klasifikasi.

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

Menentukan model yang digunakan

Model regresi logistik bisa dipanggil dalam package mlr3 dengan menggunakan fungsi lrn yang diisi dengan argumen "classif.log_reg". Jika kita ingin melihat argumen-argumen apa saja yang bisa diakses pada model regresi logistik, maka bisa dilakukan dengan menjalankan sintaks dibawah ini

as.data.table(lrn("classif.log_reg")$param_set)
##              id    class lower upper      levels nlevels is_bounded
##  1: singular.ok ParamLgl    NA    NA  TRUE,FALSE       2       TRUE
##  2:           x ParamLgl    NA    NA  TRUE,FALSE       2       TRUE
##  3:           y ParamLgl    NA    NA  TRUE,FALSE       2       TRUE
##  4:       model ParamLgl    NA    NA  TRUE,FALSE       2       TRUE
##  5:    etastart ParamUty    NA    NA                 Inf      FALSE
##  6:     mustart ParamUty    NA    NA                 Inf      FALSE
##  7:       start ParamUty    NA    NA                 Inf      FALSE
##  8:      offset ParamUty    NA    NA                 Inf      FALSE
##  9:     epsilon ParamDbl  -Inf   Inf                 Inf      FALSE
## 10:       maxit ParamDbl  -Inf   Inf                 Inf      FALSE
## 11:       trace ParamLgl    NA    NA  TRUE,FALSE       2       TRUE
## 12:      se.fit ParamLgl    NA    NA  TRUE,FALSE       2       TRUE
## 13:  dispersion ParamUty    NA    NA                 Inf      FALSE
##     special_vals     default storage_type          tags
##  1:       <list>        TRUE      logical         train
##  2:       <list>       FALSE      logical         train
##  3:       <list>        TRUE      logical         train
##  4:       <list>        TRUE      logical         train
##  5:       <list> <NoDefault>         list         train
##  6:       <list> <NoDefault>         list         train
##  7:       <list>                     list         train
##  8:       <list> <NoDefault>         list         train
##  9:       <list>       1e-08      numeric train,control
## 10:       <list>          25      numeric train,control
## 11:       <list>       FALSE      logical train,control
## 12:       <list>       FALSE      logical       predict
## 13:       <list>                     list       predict

Hal lain yang perlu menjadi catatan adalah hasil prediksi dari regresi logistik berupa nilai peluang, sehingga biasanya diperlukan suatu threshold untuk mengatur hasil prediksi itu masuk ke kelas positif atau negatif. Di dalam mlr3, kita bisa mengatur apakah hasil prediksi dari regresi logistik bisa berupa prediksi kelas atau nilai peluang dengan menggunakan argumen predict_type="prob". Secara default mlr3 mengatur argumen predict_type="response" yang berarti nilai prediksi akan berupa kelas dengan threshold=0.5.

learner_logreg <- lrn("classif.log_reg",predict_type="prob")

Menentukan cara pembagian data

Pada tutorial ini, kita akan mencoba dua tipe pembagian data yaitu holdout dan cross-validation(validasi silang)

resample_diabetes_hld = rsmp("holdout",ratio = 0.8)
resample_diabetes_cv = rsmp("cv",folds=10)

Pada pembagian data holdout, data training yang digunakan adalah sebanyak 80% dari data asal. Sementara itu, pada cross-validation fold/lipatan yang digunakan sebanyak 10 folds.

Melakukan training dan menghitung performa model

Pada tahap ini, training dilakukan berdasarkan pembagian data yang telah ditentukan sebelumnya dengan menggunakan fungsi resample.

set.seed(10)
holdout_diabetes_logreg = resample(task = task_diabetes,
                               learner = learner_logreg,
                               resampling = resample_diabetes_hld,
                               store_models = TRUE
                               )
## INFO  [07:49:54.723] Applying learner 'classif.log_reg' on task 'diabetes' (iter 1/1)
set.seed(123)
cv_diabetes_logreg = resample(task = task_diabetes,
                               learner = learner_logreg,
                               resampling = resample_diabetes_cv,
                              store_models = TRUE
                               )
## INFO  [07:49:54.996] Applying learner 'classif.log_reg' on task 'diabetes' (iter 1/10) 
## INFO  [07:49:55.099] Applying learner 'classif.log_reg' on task 'diabetes' (iter 2/10) 
## INFO  [07:49:55.159] Applying learner 'classif.log_reg' on task 'diabetes' (iter 3/10) 
## INFO  [07:49:55.222] Applying learner 'classif.log_reg' on task 'diabetes' (iter 4/10) 
## INFO  [07:49:55.301] Applying learner 'classif.log_reg' on task 'diabetes' (iter 5/10) 
## INFO  [07:49:55.365] Applying learner 'classif.log_reg' on task 'diabetes' (iter 6/10) 
## INFO  [07:49:55.425] Applying learner 'classif.log_reg' on task 'diabetes' (iter 7/10) 
## INFO  [07:49:55.498] Applying learner 'classif.log_reg' on task 'diabetes' (iter 8/10) 
## INFO  [07:49:55.571] Applying learner 'classif.log_reg' on task 'diabetes' (iter 9/10) 
## INFO  [07:49:55.635] Applying learner 'classif.log_reg' on task 'diabetes' (iter 10/10)

Setelah melakukan proses training kita bisa langsung menghitung performa model seperti biasa. Namun, package mlr3 juga memungkinkan untuk mengakses output model yang telah dilakukan training. Hal ini mengakibatkan kita bisa mengakses nilai-nilai koefisien dan p-value dari regresi logistik. Berikut adalah sintaks untuk mengakses output model pada pembagian data holdout.

model_logreg_hld <- as.data.table(holdout_diabetes_logreg)$learner[[1]]$model

Setelah diakses dan kemudian disimpan dalam objek model_baru_hld, maka fungsi-fungsi R yang biasanya digunakan pada regresi logistik bisa dijalankan. Fungsi-fungsi tersebut contohnya adalah summary dan coef.

summary(model_logreg_hld)
## 
## Call:
## stats::glm(formula = task$formula(), family = "binomial", data = task$data(), 
##     model = FALSE)
## 
## Deviance Residuals: 
##     Min       1Q   Median       3Q      Max  
## -2.7939  -0.7194   0.4109   0.7199   2.6256  
## 
## Coefficients:
##                           Estimate Std. Error z value Pr(>|z|)    
## (Intercept)               8.414583   0.820967  10.250  < 2e-16 ***
## Age                      -0.017384   0.010873  -1.599 0.109856    
## BMI                      -0.086843   0.016652  -5.215 1.84e-07 ***
## BloodPressure             0.015935   0.006046   2.635 0.008403 ** 
## DiabetesPedigreeFunction -0.982903   0.340604  -2.886 0.003905 ** 
## Glucose                  -0.035772   0.004256  -8.405  < 2e-16 ***
## Insulin                   0.000869   0.001041   0.835 0.403732    
## Pregnancies              -0.136710   0.038256  -3.574 0.000352 ***
## SkinThickness             0.000461   0.008001   0.058 0.954054    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 769.56  on 601  degrees of freedom
## Residual deviance: 556.62  on 593  degrees of freedom
## AIC: 574.62
## 
## Number of Fisher Scoring iterations: 5
#extract coefficient
coef(model_logreg_hld)
##              (Intercept)                      Age                      BMI 
##             8.4145831380            -0.0173835527            -0.0868428655 
##            BloodPressure DiabetesPedigreeFunction                  Glucose 
##             0.0159352023            -0.9829029417            -0.0357718026 
##                  Insulin              Pregnancies            SkinThickness 
##             0.0008690127            -0.1367103637             0.0004609629
#extract pvalue
summary(model_logreg_hld)$coefficients[,4]
##              (Intercept)                      Age                      BMI 
##             1.188330e-24             1.098562e-01             1.836886e-07 
##            BloodPressure DiabetesPedigreeFunction                  Glucose 
##             8.403213e-03             3.904613e-03             4.282151e-17 
##                  Insulin              Pregnancies            SkinThickness 
##             4.037316e-01             3.521093e-04             9.540539e-01

Selanjutnya pada pembagian data cross-validation, lamgkah yang dilakukan sama, yaitu mengases output model dan menyimpan dalam sebuah objek.

model_logreg_cv <- as.data.table(cv_diabetes_logreg)$learner

Namun untuk menjalankan fungsi seperti summary dan coef tidak bisa digunakan secara langsung karena terdapat 10 model yang terbentuk pada masing-masing lipatan/folds (ini disesuaikan dengan banyaknya lipatan yang dipilih). Dalam kasus ini, fungsi map dari package purrr yang berada dalam ekosistem tidyverse digunakan untuk menampilkan 10 output sekaligus.

purrr::map(.x = model_logreg_cv,.f =  ~ summary(.x$model))

argumen utama dalam fungsi map ada dua yaitu .x yang harus diisi dengan object berbentuk list atau vector dan .f yang harus diisi dengan fungsi di R yang diawali dengan function(). Fungsi tersebut hanya bisa memiliki satu input. Selain itu, pada fungsi map, kata function() bisa diganti dengan simbol ~. Penggantian ini berdampak pada input yang digunkan selalu berupa .x.

#extract coefficient
purrr::map_dfc(model_logreg_cv, ~ coef(.x$model))
## New names:
## * NA -> ...1
## * NA -> ...2
## * NA -> ...3
## * NA -> ...4
## * NA -> ...5
## * ...
## # A tibble: 9 x 10
##       ...1     ...2     ...3     ...4     ...5     ...6     ...7     ...8
##      <dbl>    <dbl>    <dbl>    <dbl>    <dbl>    <dbl>    <dbl>    <dbl>
## 1  8.27e+0  8.14     8.03     8.76e+0  8.50     8.17e+0  8.35     8.62e+0
## 2 -2.02e-2 -0.0129  -0.0186  -1.94e-2 -0.0137  -1.10e-2 -0.0173  -1.85e-2
## 3 -8.82e-2 -0.0820  -0.0832  -1.06e-1 -0.0872  -9.19e-2 -0.0866  -9.47e-2
## 4  1.38e-2  0.0127   0.0128   1.40e-2  0.0156   1.31e-2  0.0150   1.26e-2
## 5 -9.16e-1 -1.01    -0.980   -7.80e-1 -1.00    -9.42e-1 -0.728   -1.10e+0
## 6 -3.38e-2 -0.0346  -0.0331  -3.40e-2 -0.0374  -3.34e-2 -0.0364  -3.48e-2
## 7  9.64e-4  0.00211  0.00122  1.01e-3  0.00138  1.07e-3  0.00132  1.26e-3
## 8 -1.13e-1 -0.126   -0.116   -1.14e-1 -0.132   -1.28e-1 -0.110   -9.70e-2
## 9  2.34e-4 -0.00644 -0.00125  9.48e-4 -0.00305 -9.30e-4 -0.00401  9.77e-4
## # ... with 2 more variables: ...9 <dbl>, ...10 <dbl>
#extract pvalue
purrr::map_dfc(model_logreg_cv, ~ summary(.x$model)$coefficients[,4])
## New names:
## * NA -> ...1
## * NA -> ...2
## * NA -> ...3
## * NA -> ...4
## * NA -> ...5
## * ...
## # A tibble: 9 x 10
##       ...1     ...2     ...3     ...4     ...5     ...6     ...7     ...8
##      <dbl>    <dbl>    <dbl>    <dbl>    <dbl>    <dbl>    <dbl>    <dbl>
## 1 3.16e-27 2.79e-27 4.16e-27 8.34e-29 6.88e-28 1.08e-27 4.84e-28 2.40e-28
## 2 4.39e- 2 1.89e- 1 5.99e- 2 5.39e- 2 1.65e- 1 2.73e- 1 7.87e- 2 5.80e- 2
## 3 2.53e- 8 2.44e- 7 6.50e- 8 3.29e-10 3.87e- 8 1.65e- 8 6.25e- 8 4.22e- 9
## 4 1.01e- 2 2.35e- 2 2.18e- 2 1.20e- 2 5.04e- 3 1.64e- 2 6.22e- 3 2.69e- 2
## 5 3.19e- 3 1.48e- 3 1.50e- 3 1.63e- 2 1.94e- 3 2.75e- 3 2.31e- 2 5.35e- 4
## 6 6.95e-18 1.02e-18 1.04e-17 3.08e-18 8.31e-20 1.45e-17 2.01e-19 5.16e-19
## 7 3.08e- 1 3.74e- 2 2.11e- 1 3.01e- 1 1.48e- 1 2.58e- 1 1.63e- 1 1.86e- 1
## 8 7.04e- 4 1.86e- 4 6.39e- 4 8.30e- 4 1.13e- 4 1.72e- 4 1.40e- 3 4.23e- 3
## 9 9.74e- 1 3.80e- 1 8.64e- 1 8.98e- 1 6.80e- 1 8.98e- 1 5.87e- 1 8.95e- 1
## # ... with 2 more variables: ...9 <dbl>, ...10 <dbl>

Jika kita ingin mengeluarkan hasil prediksi pada data testing bisa menggunakan sintaks dibawah ini.

prediksi_holdout = as.data.table(holdout_diabetes_logreg$prediction())
prediksi_holdout
##      row_id   truth response  prob.Case prob.Control
##   1:      1    Case     Case 0.71906241   0.28093759
##   2:     14    Case     Case 0.64633984   0.35366016
##   3:     16    Case  Control 0.33275902   0.66724098
##   4:     23    Case  Control 0.28146109   0.71853891
##   5:     24    Case     Case 0.70667080   0.29332920
##  ---                                                
## 146:    731 Control  Control 0.31923110   0.68076890
## 147:    743 Control  Control 0.14246992   0.85753008
## 148:    744    Case     Case 0.90376412   0.09623588
## 149:    745 Control  Control 0.08772812   0.91227188
## 150:    746    Case     Case 0.93512455   0.06487545
# prediksi overall dari CV
prediksi_cv_all = as.data.table(cv_diabetes_logreg$prediction())
prediksi_cv_all
##      row_id   truth response prob.Case prob.Control
##   1:     16    Case  Control 0.3754384    0.6245616
##   2:     24    Case     Case 0.6998322    0.3001678
##   3:     32 Control  Control 0.0501965    0.9498035
##   4:     40 Control     Case 0.7239262    0.2760738
##   5:     44 Control     Case 0.6227529    0.3772471
##  ---                                               
## 748:    678 Control  Control 0.4395452    0.5604548
## 749:    703 Control  Control 0.2118383    0.7881617
## 750:    737 Control  Control 0.1020013    0.8979987
## 751:    739    Case     Case 0.7416002    0.2583998
## 752:    740    Case  Control 0.4489742    0.5510258
# setiap fold/lipatan dari CV
prediksi_cv_fold = cv_diabetes_logreg$predictions()

Jika ditampilkan hasil prediksi diatas juga menampilkan nilai peluang pada setiap kelas.

Selanjutnya, Confusion matrix bisa dikeluarkan dengan sintaks dibawah ini

holdout_diabetes_logreg$prediction()$confusion
##          truth
## response  Case Control
##   Case      35       9
##   Control   24      82
# menghitung confusion matrix overall dari CV
cv_diabetes_logreg$prediction()$confusion
##          truth
## response  Case Control
##   Case     149      56
##   Control  113     434
# menghitung confusion matrix setiap fold/lipatan dari CV
purrr::map(prediksi_cv_fold,~ .x$confusion)
## [[1]]
##          truth
## response  Case Control
##   Case      12       5
##   Control   10      49
## 
## [[2]]
##          truth
## response  Case Control
##   Case      16       5
##   Control   10      45
## 
## [[3]]
##          truth
## response  Case Control
##   Case      15       5
##   Control    5      50
## 
## [[4]]
##          truth
## response  Case Control
##   Case      14       7
##   Control   12      42
## 
## [[5]]
##          truth
## response  Case Control
##   Case      16       5
##   Control   13      41
## 
## [[6]]
##          truth
## response  Case Control
##   Case      18       4
##   Control   12      41
## 
## [[7]]
##          truth
## response  Case Control
##   Case      17       5
##   Control   13      40
## 
## [[8]]
##          truth
## response  Case Control
##   Case      10       5
##   Control   12      48
## 
## [[9]]
##          truth
## response  Case Control
##   Case      14       5
##   Control   15      41
## 
## [[10]]
##          truth
## response  Case Control
##   Case      17      10
##   Control   11      37

Ukuran kebaikan model bisa dihitung dengan sintaks dibawah ini. Ingat bahwa jika ukuran kebaikan model yang dihitung lebih dari satu maka harus disatukan dengan menggunakan list.

holdout_diabetes_logreg$aggregate(list(msr("classif.acc"),
                                   msr("classif.specificity"),
                                   msr("classif.sensitivity")
                                   ))
##         classif.acc classif.specificity classif.sensitivity 
##           0.7800000           0.9010989           0.5932203
# menghitung ukuran kebaikan overall dari CV
cv_diabetes_logreg$aggregate(list(msr("classif.acc"),
                                   msr("classif.specificity"),
                                   msr("classif.sensitivity")
                                   ))
##         classif.acc classif.specificity classif.sensitivity 
##           0.7751930           0.8849144           0.5712138
# menghitung ukuran kebaikan setiap fold/lipatan dari CV
cv_diabetes_logreg$score(list(msr("classif.acc"),
                                   msr("classif.specificity"),
                                   msr("classif.sensitivity")
                                   ))
##              task  task_id                learner      learner_id
##  1: <TaskClassif> diabetes <LearnerClassifLogReg> classif.log_reg
##  2: <TaskClassif> diabetes <LearnerClassifLogReg> classif.log_reg
##  3: <TaskClassif> diabetes <LearnerClassifLogReg> classif.log_reg
##  4: <TaskClassif> diabetes <LearnerClassifLogReg> classif.log_reg
##  5: <TaskClassif> diabetes <LearnerClassifLogReg> classif.log_reg
##  6: <TaskClassif> diabetes <LearnerClassifLogReg> classif.log_reg
##  7: <TaskClassif> diabetes <LearnerClassifLogReg> classif.log_reg
##  8: <TaskClassif> diabetes <LearnerClassifLogReg> classif.log_reg
##  9: <TaskClassif> diabetes <LearnerClassifLogReg> classif.log_reg
## 10: <TaskClassif> diabetes <LearnerClassifLogReg> classif.log_reg
##         resampling resampling_id iteration          prediction classif.acc
##  1: <ResamplingCV>            cv         1 <PredictionClassif>   0.8026316
##  2: <ResamplingCV>            cv         2 <PredictionClassif>   0.8026316
##  3: <ResamplingCV>            cv         3 <PredictionClassif>   0.8666667
##  4: <ResamplingCV>            cv         4 <PredictionClassif>   0.7466667
##  5: <ResamplingCV>            cv         5 <PredictionClassif>   0.7600000
##  6: <ResamplingCV>            cv         6 <PredictionClassif>   0.7866667
##  7: <ResamplingCV>            cv         7 <PredictionClassif>   0.7600000
##  8: <ResamplingCV>            cv         8 <PredictionClassif>   0.7733333
##  9: <ResamplingCV>            cv         9 <PredictionClassif>   0.7333333
## 10: <ResamplingCV>            cv        10 <PredictionClassif>   0.7200000
##     classif.specificity classif.sensitivity
##  1:           0.9074074           0.5454545
##  2:           0.9000000           0.6153846
##  3:           0.9090909           0.7500000
##  4:           0.8571429           0.5384615
##  5:           0.8913043           0.5517241
##  6:           0.9111111           0.6000000
##  7:           0.8888889           0.5666667
##  8:           0.9056604           0.4545455
##  9:           0.8913043           0.4827586
## 10:           0.7872340           0.6071429

Output confussion matrix diatas dihitung berdasarkan threshold 0.5, artinya saat prediksi dari regresi logistik >0.5 maka hasil prediksi itu akan di atur ke kelas positif. Sebaliknya jika <0.5 maka akan diatur ke kelas negatif.

Pengaturan nilai threshold dimungkinkan dalam package mlr3, dengan menggunakan sintaks-sintaks dibawah ini.

holdout_diabetes_logreg$prediction()$set_threshold(0.8)$confusion
##          truth
## response  Case Control
##   Case      15       2
##   Control   44      89
# menghitung confusion matrix overall dari CV
cv_diabetes_logreg$prediction()$set_threshold(0.8)$confusion
##          truth
## response  Case Control
##   Case      60      10
##   Control  202     480
# menghitung confusion matrix setiap fold/lipatan dari CV
purrr::map(prediksi_cv_fold,~ .x$set_threshold(0.8)$confusion)
holdout_diabetes_logreg$prediction()$
  set_threshold(0.8)$
  score(list(msr("classif.acc"),
             msr("classif.specificity"),
             msr("classif.sensitivity")
              ))
##         classif.acc classif.specificity classif.sensitivity 
##           0.6933333           0.9780220           0.2542373
# menghitung ukuran kebaikan overall dari CV
cv_diabetes_logreg$prediction()$
  set_threshold(0.8)$
  score(list(msr("classif.acc"),
             msr("classif.specificity"),
             msr("classif.sensitivity")
              ))
##         classif.acc classif.specificity classif.sensitivity 
##           0.7180851           0.9795918           0.2290076
# menghitung ukuran kebaikan setiap fold/lipatan dari CV
purrr::map(prediksi_cv_fold,~ .x$
  set_threshold(0.8)$
  score(list(msr("classif.acc"),
             msr("classif.specificity"),
             msr("classif.sensitivity")
              )))

Kurva ROC

Kurva ROC hanya bisa dihitung jika model yang digunakan menghasilkan nilai prediksi berupa peluang. Oleh karena itu, model seperti KNN tidak tepat menggunakan kurva ROC karena akan dianggap nilai peluangnya hanya 0 dan 1 saja. Untuk menampilkan kurva ROC bisa menggunakan fungsi autoplot dari package mlr3viz.

# Kurva ROC dari holdout 
autoplot(holdout_diabetes_logreg$prediction(),type="roc")

# Kurva ROC dari CV 
autoplot(cv_diabetes_logreg$prediction(),type="roc")

P dan N diatas grafik menunjukkan banyaknya kelas postive dan juga negatif. Jika diperhatikan nilai P dan N dari cross-validation jika dijumlahkan akan sama seperti banyaknya amatan pada data asal. Hal ini dikarenakan semua amatan memiliki kesempaatan untuk menjadi data testing.

Kemudian ukuran kebaikan model yang bisa diturunkan dari kurva ROC adalah nilai AUC atau Area Under Curve, yang didapat dengan menghitung luas area dibawah kurva AUC.

holdout_diabetes_logreg$aggregate(msr("classif.auc"))
## classif.auc 
##   0.8210095
# menghitung ukuran kebaikan overall dari CV
cv_diabetes_logreg$aggregate(msr("classif.auc"))
## classif.auc 
##    0.827726
# menghitung ukuran kebaikan setiap fold/lipatan dari CV
cv_diabetes_logreg$score(msr("classif.auc"))
##              task  task_id                learner      learner_id
##  1: <TaskClassif> diabetes <LearnerClassifLogReg> classif.log_reg
##  2: <TaskClassif> diabetes <LearnerClassifLogReg> classif.log_reg
##  3: <TaskClassif> diabetes <LearnerClassifLogReg> classif.log_reg
##  4: <TaskClassif> diabetes <LearnerClassifLogReg> classif.log_reg
##  5: <TaskClassif> diabetes <LearnerClassifLogReg> classif.log_reg
##  6: <TaskClassif> diabetes <LearnerClassifLogReg> classif.log_reg
##  7: <TaskClassif> diabetes <LearnerClassifLogReg> classif.log_reg
##  8: <TaskClassif> diabetes <LearnerClassifLogReg> classif.log_reg
##  9: <TaskClassif> diabetes <LearnerClassifLogReg> classif.log_reg
## 10: <TaskClassif> diabetes <LearnerClassifLogReg> classif.log_reg
##         resampling resampling_id iteration          prediction classif.auc
##  1: <ResamplingCV>            cv         1 <PredictionClassif>   0.8855219
##  2: <ResamplingCV>            cv         2 <PredictionClassif>   0.8969231
##  3: <ResamplingCV>            cv         3 <PredictionClassif>   0.9227273
##  4: <ResamplingCV>            cv         4 <PredictionClassif>   0.7708006
##  5: <ResamplingCV>            cv         5 <PredictionClassif>   0.7871064
##  6: <ResamplingCV>            cv         6 <PredictionClassif>   0.8429630
##  7: <ResamplingCV>            cv         7 <PredictionClassif>   0.8229630
##  8: <ResamplingCV>            cv         8 <PredictionClassif>   0.7967410
##  9: <ResamplingCV>            cv         9 <PredictionClassif>   0.7893553
## 10: <ResamplingCV>            cv        10 <PredictionClassif>   0.7621581