Introduction to Data Science

TUGAS : Classification II : Evaluation and Tuning

Kontak : \(\downarrow\)
Email :
Instagram : https://www.instagram.com/ferd_nw/
RPubs : https://rpubs.com/ferdnw/

Introduction

Melanjutkan Proses Klasifikasi pada materi sebelumnya, di chapter ini akan membahas dalam melakukan Predicting Data. Mengevaluasi dan memaksimalkan tingkat akurasinya.

Evaluating the Accuracies

Hasil Classification terkadang bisa memberikan sebuah prediksi yang salah, tidak bisa berhasil menebak 100% tetapi tidak ada salahnya meningkatkan akurasi prediksi kita tersebut. Bagaimana mengukur level akurasinya? Dengan mengunakan data breast cancer images data yang diperoleh dari proses biopsi kepada pasien lalu hasilnya dilakukan analisa dan diklasifikasi level tumornya .

Caranya dengan membagi dataset menjaddi Training Set dan Test Set Lalu, gunakan data di Training Set untuk melakukan level klasifikasi sesuai faktor yang ditentukan. Hapus Label hasil Klasifikasi yang ada di Test Set, lalu gunakan metode Klasifikasi hasil hitung dari Training Set untuk mengklasifikasikan Data pada Test Set Setelah di lakukan hal tersebut, Bandingkan dengan Data Original yang sudah diklasifikasi (Sebelum DihapusLabel Klasifikasinya).

Setelah membandingkan kecocokan Label Klasifikasi di Test Set, kita dapat menghitung persentase prediksi benarnya

\[ Accuracy = correct prediction / total prediction \]

Randomness and Seeds

Randomize digunakan untuk mengolah data supaya adil dan tidak ada campur tangan manusia yang bisa mencurangi data. Contohnya dalam melakukan splitting data seperti sebelumnya, Training Set dan Test Set. Tentunya, kita tidak melakukan splitting secara manual, tapi oleh R baik itu Subset atau Grouping.

But, Randomization di R tidaklah sepenuhnya acak, tapi ditentukan oleh sebuah Seed. Menggunakan set.seed kita bisa menciptakan kembali sequence yang kita dapatkan asalkan seed valuenya sama.

set.seed(1)
random_numbers <- sample(0:9, 10, replace=TRUE)
random_numbers
##  [1] 8 3 6 0 1 6 1 2 0 4

10 angka random tersebut akan diacak kembali di chunk selanjutnya

random_numbers <- sample(0:9, 10, replace=TRUE)
random_numbers
##  [1] 4 9 5 9 6 8 4 4 8 8

Menggunakan set.seed kita bisa memanggil sequence angka yang sama dengan argument sama

set.seed(1)
random_numbers <- sample(0:9, 10, replace=TRUE)
random_numbers
##  [1] 8 3 6 0 1 6 1 2 0 4
random_numbers <- sample(0:9, 10, replace=TRUE)
random_numbers
##  [1] 4 9 5 9 6 8 4 4 8 8

Dengan seed yang berbeda, sequence angkanya juga berbeda

set.seed(4235)
random_numbers <- sample(0:9, 10, replace=TRUE)
random_numbers
##  [1] 8 3 1 4 6 8 8 4 1 7
random_numbers <- sample(0:9, 10, replace=TRUE)
random_numbers
##  [1] 3 7 8 2 8 8 6 3 3 8

Dalam melakukan Data Analizing, gunakan set.seed agar data yang kita punya dapat di panggil lagi dan tidak kena re-random. Argument dan Seed Value yang sama bisa membuat R Produce Data yang Sama dengan sebelumnya.

Evaluating Accuracy with tidyverse

Di R, tidymodels digunakan tidak hanya untuk melakukan K-Nearest Neighbour (KNN) tapi juga menjelaskan bagaimana klasifikasi kita bekerja.

# load packages
library(tidyverse)
## Warning: package 'tidyverse' was built under R version 4.1.2
## -- Attaching packages --------------------------------------- tidyverse 1.3.1 --
## v ggplot2 3.3.5     v purrr   0.3.4
## v tibble  3.1.4     v dplyr   1.0.7
## v tidyr   1.2.0     v stringr 1.4.0
## v readr   2.0.1     v forcats 0.5.1
## Warning: package 'tidyr' was built under R version 4.1.2
## -- Conflicts ------------------------------------------ tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag()    masks stats::lag()
library(tidymodels)
## Warning: package 'tidymodels' was built under R version 4.1.2
## Registered S3 method overwritten by 'tune':
##   method                   from   
##   required_pkgs.model_spec parsnip
## -- Attaching packages -------------------------------------- tidymodels 0.1.4 --
## v broom        0.7.9      v rsample      0.1.1 
## v dials        0.1.0      v tune         0.1.6 
## v infer        1.0.0      v workflows    0.2.4 
## v modeldata    0.1.1      v workflowsets 0.1.0 
## v parsnip      0.1.7      v yardstick    0.0.9 
## v recipes      0.1.17
## Warning: package 'dials' was built under R version 4.1.2
## Warning: package 'infer' was built under R version 4.1.2
## Warning: package 'modeldata' was built under R version 4.1.2
## Warning: package 'parsnip' was built under R version 4.1.2
## Warning: package 'recipes' was built under R version 4.1.2
## Warning: package 'rsample' was built under R version 4.1.2
## Warning: package 'tune' was built under R version 4.1.2
## Warning: package 'workflows' was built under R version 4.1.2
## Warning: package 'workflowsets' was built under R version 4.1.2
## Warning: package 'yardstick' was built under R version 4.1.2
## -- Conflicts ----------------------------------------- tidymodels_conflicts() --
## x scales::discard() masks purrr::discard()
## x dplyr::filter()   masks stats::filter()
## x recipes::fixed()  masks stringr::fixed()
## x dplyr::lag()      masks stats::lag()
## x yardstick::spec() masks readr::spec()
## x recipes::step()   masks stats::step()
## * Use suppressPackageStartupMessages() to eliminate package startup messages
# set the seed
set.seed(1)

# load data
cancer <- read_csv("C:/Users/5/Documents/Semester2/Input/unscaled_wdbc.csv") |>
  # convert the character Class variable to the factor datatype
  mutate(Class = as_factor(Class)) 
## Rows: 569 Columns: 12
## -- Column specification --------------------------------------------------------
## Delimiter: ","
## chr  (1): Class
## dbl (11): ID, Radius, Texture, Perimeter, Area, Smoothness, Compactness, Con...
## 
## i Use `spec()` to retrieve the full column specification for this data.
## i Specify the column types or set `show_col_types = FALSE` to quiet this message.
# create scatter plot of tumor cell concavity versus smoothness,
# labeling the points be diagnosis class
perim_concav <- cancer |>
  ggplot(aes(x = Smoothness, y = Concavity, color = Class)) +
  geom_point(alpha = 0.5) +
  labs(color = "Diagnosis") +
  scale_color_manual(labels = c("Malignant", "Benign"), 
                     values = c("orange2", "steelblue2")) + 
  theme(text = element_text(size = 12))

perim_concav

Create the train / test split

Kita akan mencoba melakukan metode split training test dan test set dengan ratio 75-25 menggunakan initial_split. Command tersebut akan mengshuffle data dan mengambil data sesuai proporsi kelas, 63% of the training data adalah benign, 37% of the training data adalah malignant, dan sama halnya dengan testing data.

cancer_split <- initial_split(cancer, prop = 0.75, strata = Class)
cancer_train <- training(cancer_split)
cancer_test <- testing(cancer_split) 
glimpse(cancer_train)
## Rows: 426
## Columns: 12
## $ ID                <dbl> 8510426, 8510653, 8510824, 857373, 857810, 858477, 8~
## $ Class             <fct> B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B~
## $ Radius            <dbl> 13.540, 13.080, 9.504, 13.640, 13.050, 8.618, 10.170~
## $ Texture           <dbl> 14.36, 15.71, 12.44, 16.34, 19.31, 11.79, 14.88, 20.~
## $ Perimeter         <dbl> 87.46, 85.63, 60.34, 87.21, 82.61, 54.34, 64.55, 54.~
## $ Area              <dbl> 566.3, 520.0, 273.9, 571.8, 527.2, 224.5, 311.9, 221~
## $ Smoothness        <dbl> 0.09779, 0.10750, 0.10240, 0.07685, 0.08060, 0.09752~
## $ Compactness       <dbl> 0.08129, 0.12700, 0.06492, 0.06059, 0.03789, 0.05272~
## $ Concavity         <dbl> 0.066640, 0.045680, 0.029560, 0.018570, 0.000692, 0.~
## $ Concave_Points    <dbl> 0.047810, 0.031100, 0.020760, 0.017230, 0.004167, 0.~
## $ Symmetry          <dbl> 0.1885, 0.1967, 0.1815, 0.1353, 0.1819, 0.1683, 0.27~
## $ Fractal_Dimension <dbl> 0.05766, 0.06811, 0.06905, 0.05953, 0.05501, 0.07187~
glimpse(cancer_test)
## Rows: 143
## Columns: 12
## $ ID                <dbl> 84501001, 846381, 84799002, 849014, 852763, 853401, ~
## $ Class             <fct> M, M, M, M, M, M, M, B, M, M, M, B, B, B, B, B, B, M~
## $ Radius            <dbl> 12.460, 15.850, 14.540, 19.810, 14.580, 18.630, 16.7~
## $ Texture           <dbl> 24.04, 23.95, 27.54, 22.15, 21.53, 25.11, 21.59, 18.~
## $ Perimeter         <dbl> 83.97, 103.70, 96.73, 130.00, 97.41, 124.80, 110.10,~
## $ Area              <dbl> 475.9, 782.7, 658.8, 1260.0, 644.8, 1088.0, 869.5, 5~
## $ Smoothness        <dbl> 0.11860, 0.08401, 0.11390, 0.09831, 0.10540, 0.10640~
## $ Compactness       <dbl> 0.23960, 0.10020, 0.15950, 0.10270, 0.18680, 0.18870~
## $ Concavity         <dbl> 0.22730, 0.09938, 0.16390, 0.14790, 0.14250, 0.23190~
## $ Concave_Points    <dbl> 0.085430, 0.053640, 0.073640, 0.094980, 0.087830, 0.~
## $ Symmetry          <dbl> 0.2030, 0.1847, 0.2303, 0.1582, 0.2252, 0.2183, 0.18~
## $ Fractal_Dimension <dbl> 0.08243, 0.05338, 0.07077, 0.05395, 0.06924, 0.06197~

Dengan menggunakan fungsi glimpse untuk melihat data dengan skala yang besar, kita bisa tahu bahwa jumlah data masing-masing set. 426 di Training dan 143 di Test sesuai dengan pembagian 75-25 yang diinginkan.

Lalu menggunakan group_by dan summarize untuk melihat proporsi antara malignant dan benign.

cancer_proportions <- cancer_train |>
                      group_by(Class) |>
                      summarize(n = n()) |>
                      mutate(percent = 100*n/nrow(cancer_train))

cancer_proportions

Preprocess the data

Metode KNN Sangat sensitive terhadap hasil predictor, harus dilakukan standarize terhadap Training data menggunakan recipe dari package tidymodels

cancer_recipe <- recipe(Class ~ Smoothness + Concavity, data = cancer_train) |>
  step_scale(all_predictors()) |>
  step_center(all_predictors())

Train the Classifier

Kita akan membuat Classification menggunakan K-Nearest Neighbour dengan Training Set menggunakan K=3 dengan concavity dan smoothness sebagai predictor. Pertama kita membuat model spesifiknya lalu mengkombinasikan dengan recipe lalu gunakan fit pada training data untuk membuat classifier.

knn_spec <- nearest_neighbor(weight_func = "rectangular", neighbors = 3) |>
  set_engine("kknn") |>
  set_mode("classification")

knn_fit <- workflow() |>
  add_recipe(cancer_recipe) |>
  add_model(knn_spec) |>
  fit(data = cancer_train)

knn_fit
## == Workflow [trained] ==========================================================
## Preprocessor: Recipe
## Model: nearest_neighbor()
## 
## -- Preprocessor ----------------------------------------------------------------
## 2 Recipe Steps
## 
## * step_scale()
## * step_center()
## 
## -- Model -----------------------------------------------------------------------
## 
## Call:
## kknn::train.kknn(formula = ..y ~ ., data = data, ks = min_rows(3,     data, 5), kernel = ~"rectangular")
## 
## Type of response variable: nominal
## Minimal misclassification: 0.1150235
## Best kernel: rectangular
## Best k: 3

Predict the labels in the test set

Setelah memiliki classifier dari K-nearest neighbors, kita akan mencoba mengujinya untuk memprediksi dan melabeli data menggunakan test set. Menggunakan bind_cols untuk menambahkan kolom prediksi ke test data membuat dataframe bernama cancer_test_prediction Dengan variabel Class yang berisi diagnosa sebenarnya dan .pred_class adalah diagnosa menggunakan classifier KNN

cancer_test_predictions <- predict(knn_fit, cancer_test) |>
  bind_cols(cancer_test)

cancer_test_predictions

Compute the accuracy

Menghitung accuracy dari classifier menggunakan metric dari package tidyverse dengan perhitungan truth dengan argument sebagai perhitungan akurasi.

cancer_test_predictions |>
  metrics(truth = Class, estimate = .pred_class) |>
  filter(.metric == "accuracy")

Dari hasil metric kita hanya mengambil accuracy karena itu yang dicari, lalu jika melihat .estimate menunjukkan akurasi sebesar 86% Kita juga bisa melihat spesifikasi hasil prediksi dari KNN menggunakan conf_mat

confusion <- cancer_test_predictions |>
             conf_mat(truth = Class, estimate = .pred_class)

confusion
##           Truth
## Prediction  M  B
##          M 39  6
##          B 14 84

Hasil cpnfusion tersebut menunjukkan 39 data berhasil diprediksi Magnant dan 84 sebagai Benign sesuai dengan diasgnosa aslinya. Tapi masih ada ruang kecil untuk kesalahan, dimana Prediksi mengatakan 14 sebagai Magnant, walau aslinya adalah Benign dan 6 yang Sebaliknya.

Critically analyze performance

Tingkat AKurasi 86% sudah cukup tinggi, apakah bisa lebih akurat lagi? Umumnya, level akurasi ditentukan oleh aplikasi prediksi tersebut. Jika ingin memprediksikan klasifikasi tumor dengan level aurasi 99% mungkin masih kurang akurat ditambah jika ada faktor Error dan kesalahan yang dibuat oleh AI. Efeknya adalah kesalahan penanganan dan pengobatan pada pengidap tumor yang menerima treatment, seperti Pasien dengan kelas Malignant yang dilabeli Benign tidak menerima pengobatan seperti yang harusnya seorang pengidap tumor Malignant jalani.

KNN juga dipengaruhi oleh Kelas Mayoritas, setelah menginput data seperti diatas kita berharap agar KNN dapat memiliki prediksi yang akurat , bisa dilihat proporsi data cancer data proportions

cancer_proportions

Benign merupakan kelas mayoritas di dataset tersebut, expectationnya adalah KNN memiliki accuracy diatas persentase kelas mayoritas (63%) yang ternyata bisa lebih akurat daripada harapan (86%). Tapi efek kelas mayoritas tersebut mempengaruhi beberapa Malignant Tumors yang salah di Diagnosis menjadi Benign sebanyak 14 dari 53 data (26%) error rate yang cukup besar apalagi mempengaruhi pennanganan medis dan nyawa seseorang.

Tuning the classifier

Kebanyakan Machine Learning dan statistics memiliki Parameter, sebuah batasan yang kita pilih untuk menentukan model bekerja. Di KNN kita memilih parameter K untuk menentukan berapa banyak neighbor yang masuk dalam kelas. Beda nilai K beda juga hasil prediksi.

Bagaimana cara memilih nilai K yang paling efektif untuk memaksimalkan peformance dari data classifier yang kita punya? Menggunakan metode Split yang sama seperti sebelumnya lalu melakukan step-by-step sampai mendapatkan parameter yang tepat untuuk melakukan klasifikasi.

P.S. : Jangan menyentuh apa yang ada di Test Set selama proses tuning, gunakan Test Set saat proses pengujian

Cross-validation

Pertama, kita melakkan perbandingan dari hasil setiap nilai dari K dan memilih yang paling cocok dengan menggunakan Training Set (Validation set) Berbeda dengan sebelumnya, kita hanya membuat single split dari data. Karena in the end hanya ada 1 classifier yang akan digunakan. Tapi selama proses tuning, kita bebas menciptakan banyak classifier dengan berbagai faktor untuk menentukan parameter value yang paling tepat dan akurasi yang lebih baik .

Contohnya, kita akan menguji 5 splits atau hitungan yang berbeda selama proses tuning dan membandingkan dengan yang hanya 1 kali splits. Mulai dengan Single Split

# create the 25/75 split of the training data into training and validation
cancer_split <- initial_split(cancer_train, prop = 0.75, strata = Class)
cancer_subtrain <- training(cancer_split)
cancer_validation <- testing(cancer_split)

# recreate the standardization recipe from before 
# (since it must be based on the training data)
cancer_recipe <- recipe(Class ~ Smoothness + Concavity, 
                        data = cancer_subtrain) |>
  step_scale(all_predictors()) |>
  step_center(all_predictors())

# fit the knn model (we can reuse the old knn_spec model from before)
knn_fit <- workflow() |>
  add_recipe(cancer_recipe) |>
  add_model(knn_spec) |>
  fit(data = cancer_subtrain)

# get predictions on the validation data
validation_predicted <- predict(knn_fit, cancer_validation) |>
  bind_cols(cancer_validation)

# compute the accuracy
acc <- validation_predicted |>
  metrics(truth = Class, estimate = .pred_class) |>
  filter(.metric == "accuracy") |>
  select(.estimate) |>
  pull()

acc
## [1] 0.8598131

Dalam Sekali hitung atau dengan sekali split, akurasi berada di 88%. Kita lakukan ulang coding tersebt sebanyak 4 kali untuk mendapatkan 5 jenis data dengan 5 level akurasi berbeda : 88.8%, 86.9%, 83.2%, 88.8%, 87.9% . Nilai Akurasi tersebut tidaklah jauh berbeda dengan yang lainnya, kelimanya hanyalah estimasi nilai akurasi dari Classifier yang kita miliki dengan rata-rata 87%.

Dalam prakteknya, kita tidak menggunakan random splits, tapi meggunakan procedure split dimana satu data/amatan hanya muncul satu kali di Validation Set atau Test Set. Taktik ini bernama Cross-Validation. Dimana kita meng-split data menjadi C bagian sama besar dan menggunakan 1 bagian msebagai Validation Set dan Sisanya sebagai Training Set

Dengan R, Cross-Validation 5 Splits bisa dilakulkan dengan package tidymodels dengan function vfold_cv yang membagi data kita mnenjadi v bagian. Lalu strata untuk membedakan label memastikan masing-masing splits memiliki proporsi yang sama dengan label atau kelasnta `

cancer_vfold <- vfold_cv(cancer_train, v = 5, strata = Class)
cancer_vfold

Lalu menggunakan fit_resamples untuk melakukan cross validation di tiap splits

# recreate the standardization recipe from before 
# (since it must be based on the training data)
cancer_recipe <- recipe(Class ~ Smoothness + Concavity, 
                        data = cancer_train) |>
  step_scale(all_predictors()) |>
  step_center(all_predictors())

# fit the knn model (we can reuse the old knn_spec model from before)
knn_fit <- workflow() |>
  add_recipe(cancer_recipe) |>
  add_model(knn_spec) |>
  fit_resamples(resamples = cancer_vfold)
## Warning: package 'kknn' was built under R version 4.1.2
knn_fit

Menggunakan collect_metrics untuk mendapatkan agregate dari mean dan standard error setiap classifier. Nilai accuracy akan tampil di accuracy di kolom .metric . Mean (mean) dijadikan sebagai perkiraan akurasi dan standard error (std_err) menyatakan nilai error dari Mean. Jika Mean 0.88 dan Standard Error 0.02 maka nilai akurasinya berkisar antara 86%-90% Untuk smentara, kita bisa mengabaikan baris roc_auc

knn_fit |> 
  collect_metrics() 

Kita bisa melakukan dengan berbagai jumlah splits yang pastinya meningkatkan average akurasi tapi semakin memberatkan system dan waktu proses semakin lama. DAlam melakukan hak ini, perhatikan ukuran dan jumlah data juga kemampuan hardware dan algoritma. Biasanya nilai C adalah 5 atau 10. Contoh Cross-Validation dengan 10 Splits

cancer_vfold <- vfold_cv(cancer_train, v = 10, strata = Class)

vfold_metrics <- workflow() |>
                  add_recipe(cancer_recipe) |>
                  add_model(knn_spec) |>
                  fit_resamples(resamples = cancer_vfold) |>
                  collect_metrics()

vfold_metrics

Parameter Value Selection

Di tahap sebelumnyaa, setelah perhitungan diestimasikan tingkat akurasi dari classifier tersebut sekitar 89% Dalam kondisi tertentu, itu sudah cukup tapi untuk data Cancer yang berhubungan dengan resiko tinggi bahkan sampai melibatkan Nyawa seseorang, kit aperlu meningkatkan tingkat akurasinya.

Untuk menongkatkan level akurasinya, kita bisa menentukan parameter jumlah neighbor, K. Dengan metode Cross-Validation kta bisa menentukan akurasi dari masing-masing nilai K dalam range yang ditentukan lalu memilih K yang punya akurasi terbaik. tidymodels menyediakan function yang bisa digunakan yaitu tune()

knn_spec <- nearest_neighbor(weight_func = "rectangular", 
                             neighbors = tune()) |>
  set_engine("kknn") |>
  set_mode("classification")

Menggunakan tune_grid untuk mencocokkan model tiap nilai K. Pertama-tama buat dataframe neighbor variabel yang terdapat squence dari nilai K dalam dataframe bernama k_vals dari 1-100 dengan kelipatan 5 lalu memasukkan data ke grid dalam tune_grid

k_vals <- tibble(neighbors = seq(from = 1, to = 100, by = 5))

knn_results <- workflow() |>
  add_recipe(cancer_recipe) |>
  add_model(knn_spec) |>
  tune_grid(resamples = cancer_vfold, grid = k_vals) |>
  collect_metrics() 

accuracies <- knn_results |>
  filter(.metric == "accuracy")

accuracies

Menggunakan plot, kita bisa melihat nilai K mana yang memberikan tingkat akurasi paling tinggi

accuracy_vs_k <- ggplot(accuracies, aes(x = neighbors, y = mean)) +
  geom_point() +
  geom_line() +
  labs(x = "Neighbors", y = "Accuracy Estimate") + 
  theme(text = element_text(size = 12))

accuracy_vs_k

K=41 memiliki akurasi tertinggi sebesar 89,17% dan nilai K antara 30 sampai 60 bisa menjadi pilihan yang cocokk. Tapi apa yang ada di plot tersebut hanyalah estimasi, bukan brarti classifiernya akan super akurat dengan nilai K sekian. Yang dicari adalah

  • Akurasi yang Optimal supaya model classifiernya akan akurat
  • Jike nilai K diganti dengan nilai K yang berbeda sedikit (Misalnya menjumlahkan atau mengurangi dengan angka kecil) tidak merubah tingkat akurasi secara signifikan
  • Tidak terlalu memakan banyak effort (Cost, Resources dll)

Kita mengetahui bahwa K=41 memnerikan tingkat akurasi tertinggi dan tidak memiliki perbedaan signifikan jika diganti sedikit (Poin 2) dan tidak terlalu memakan banyak Cost di proses komputasi (poin 3 ). Maka dipilihlah K=41

Under/Overfitting

Apa yang terjadi jika nilai K semakin membersar ? Akurasi akan menurun. Dengan grid di tune_grid menampilkan plot dengan nilai K dari 1 sampai jumlah total amatan dalam dataset.

k_lots <- tibble(neighbors = seq(from = 1, to = 385, by = 10))

knn_results <- workflow() |>
  add_recipe(cancer_recipe) |>
  add_model(knn_spec) |>
  tune_grid(resamples = cancer_vfold, grid = k_lots) |>
  collect_metrics()
## ! Fold01: preprocessor 1/1, model 1/1: 381 samples were requested but there were 3...
## ! Fold02: preprocessor 1/1, model 1/1: 381 samples were requested but there were 3...
## ! Fold03: preprocessor 1/1, model 1/1: 381 samples were requested but there were 3...
## ! Fold04: preprocessor 1/1, model 1/1: 381 samples were requested but there were 3...
## ! Fold05: preprocessor 1/1, model 1/1: 381 samples were requested but there were 3...
## ! Fold06: preprocessor 1/1, model 1/1: 381 samples were requested but there were 3...
## ! Fold07: preprocessor 1/1, model 1/1: 381 samples were requested but there were 3...
## ! Fold08: preprocessor 1/1, model 1/1: 381 samples were requested but there were 3...
## ! Fold09: preprocessor 1/1, model 1/1: 381 samples were requested but there were 3...
## ! Fold10: preprocessor 1/1, model 1/1: 381 samples were requested but there were 3...
accuracies <- knn_results |>
  filter(.metric == "accuracy")

accuracy_vs_k_lots <- ggplot(accuracies, aes(x = neighbors, y = mean)) +
  geom_point() +
  geom_line() +
  labs(x = "Neighbors", y = "Accuracy Estimate") + 
  theme(text = element_text(size = 12))

accuracy_vs_k_lots

Underfitting : Semakin meningkat nilai K, maka semakin banyak data yang salah masuk kelas, perbatasan antara klasifikasi Benign dan Malignant menjadi tidak jelas, dimana semakin banyak amatan yang malah masuk kelas mayoritas.

Overfitting : Ketika nilai K menurun, dan karena Data yang angkanya berbeda-beda, Classifier akan menyamakan kelasnya dengan amatan yang didekatnya, membuat batas dimana Klasifikasi menjadi tidak jelas atau berantakan.

Summary

Algoritma Klasifikasi seperti K-Nearest Neighbor membandingkan data dengan amatan terdekatnya lalu mengklasifikan kelasnya. Mengevaluasi tingkat akurasi dari classifier bisa dengan Split Training Set dan test set atau dengan melakukan Cross-Validation.

Cara Kerja K-Nearest Neighbor dari tidymodels

  1. Menggunakan initial_split untuk membagi data menjadi training dan test set dengan strata sebagai kelas pembagi nya
  2. Gunakan vfold_cv untuk split data untuk melakukan cross-validation
  3. Mmebuat recipe yang menspesifikasi class labels dan prediktonya serta melakukan preprocessing data. Masukkan Training Data sebagai data di recipe.
  4. Membuat nearest_neighbor model dengan neighbor = true ()
  5. Menggabungkan Recipe dan Model ke workflow() dengan tune_grid untuk mengestimasi nilai akurasi dari nilai K
  6. Memilih nilai K dengan Akurasi tertinggi
  7. membuat model baru untuk mencari Parameter
  8. Evaluasi nilai akurasi yang terlah diestimasi dengan predict

Plus Side K -nearest neighbors classification + Algoritma yang Simple + Membutuhkan asumsi seperti apa bentukannyadata + Bekerja untuk klasifikasi binary (2) dan multi class

Down Side dari K-nearest neighbors classification - Melambat ketika Datanya Besar - Tidak terlalu optimal dengan jumlah predictor yang besar - Tidak terlalu optimal apabila proporsi kelas tidak sama.

Predictor variable selection

Anda bisa memilih variabel apapun dari data sebagai variabel yang akan digunakan untuk memprediksi. Semakin banyak predictor bukan berarti semakin akurat jika memilih Predictor yang salah bisa merusak klasifikasi yang ada.

The effect of irrelevant predictors

Sebagai contoh, di data Breast cancer akan menggunakan variabel predictor yaitu Smoothness Concavity dan Perimeter dengan menambahkan Data angka random 0 dan 1 yang dusebut sebagai irrelevant1 dan Irrelevant2

cancer_irrelevant = cancer
cancer_irrelevant$Irrelevant1 = sample(c(0,1), replace=TRUE, size=569)
cancer_irrelevant$Irrelevant2 = sample(c(0,1), replace=TRUE, size=569)
cancer_irrelevant$Irrelevant3 = sample(c(0,1), replace=TRUE, size=569)
cancer_irrelevant |> 
      select(Class, Smoothness, Concavity, Perimeter, Irrelevant1, Irrelevant2)

Selanjutnya, membuat KNN dengan melibatkan variabel-variabel tersebut. Semakin banyak Irrelevant variables, semakin turun pula nilai akurasi dari classifier tersebut karena kehadiran variabel tersebut menghadirkan influence yang bisa merusak jumlah neighbor yang mempernaruhi proses dan hasil klasifikasi.

Finding a good subset of predictors

Bagaimana memilih variabel yang cocok untuk melakukan klasifikasi? Bisa menggunakan proses visualisasii data untuk menunjukkan kira-kira mana variabel yang relevan untuk digunakan.

Cara pertama dengan menggunakan semua subset yang mungkin, melakukan proses trial dan error berulang kali sampai mendapatkan klasifikasi yang terbaik. Disebut juga best subset selection (Beale, Kendall, and Mann 1967; Hocking and Leslie 1967) Kelemahannya adalah memperlambat kinerja system dan cenderung menghabiskan banyak waktu serta biaya, karena kita menggunakan semua kombinasi yang mungkin terjaid. Contohnya ada 3 variabel (A,B,C) maka kita melakuan subset and trial sebanyak 7 kali (A,B,C AB, AC, BC, ABC)

Cara Kedua bisa dengan membuat model klasifikasi lalu menambahkan satu-persatu variabel disebut juga forward selection (Eforymson 1966; Draper and Smith 1966) Dimulai dengan membuat model dengan jumlah predictor = 0 lalu menambahkan satu persatu variabel tersebut ke dalam model sampai menghasilkan model yanhg memiliki tingkat akurasi tertinggi.

Forward selection in R

Di R tepatnya tidyverse tidak ada cara yang fully automatic dalam melakukan ini. Tapi bisa dengan manual, pertama-tama select untuk mengekstrak predictors.

cancer_subset <- cancer_irrelevant |> 
  select(Class, 
         Smoothness, 
         Concavity, 
         Perimeter, 
         Irrelevant1, 
         Irrelevant2, 
         Irrelevant3)

names <- colnames(cancer_subset |> select(-Class))

cancer_subset

Menggunakan fungsi paste untuk menciptakan model. Lalu collapse akan menentukan paste apa yang harus ditaruh di antara items . Untuk membuat formula =nya

example_formula <- paste("Class", "~", paste(names, collapse="+"))
example_formula
## [1] "Class ~ Smoothness+Concavity+Perimeter+Irrelevant1+Irrelevant2+Irrelevant3"

Lalu, membuat code dimana akan mencari prediktor terbaik untuk dipakai di model akhir. Setiap predictor dibuatkan model formula, dimasukkan ke recipe , membuat workflow dengan K-NN classifier menggunakan Cross-Validation dengan 5 Splits lalu mencatat nilai estimasi akurasinya.

# create an empty tibble to store the results
accuracies <- tibble(size = integer(), 
                     model_string = character(), 
                     accuracy = numeric())

# create a model specification
knn_spec <- nearest_neighbor(weight_func = "rectangular", 
                             neighbors = tune()) |>
     set_engine("kknn") |>
     set_mode("classification")

# create a 5-fold cross-validation object
cancer_vfold <- vfold_cv(cancer_subset, v = 5, strata = Class)

# store the total number of predictors
n_total <- length(names)

# stores selected predictors
selected <- c()

# for every size from 1 to the total number of predictors
for (i in 1:n_total) {
    # for every predictor still not added yet
    accs <- list()
    models <- list()
    for (j in 1:length(names)) {
        # create a model string for this combination of predictors
        preds_new <- c(selected, names[[j]])
        model_string <- paste("Class", "~", paste(preds_new, collapse="+"))

        # create a recipe from the model string
        cancer_recipe <- recipe(as.formula(model_string), 
                                data = cancer_subset) |>
                          step_scale(all_predictors()) |>
                          step_center(all_predictors())

        # tune the KNN classifier with these predictors, 
        # and collect the accuracy for the best K
        acc <- workflow() |>
          add_recipe(cancer_recipe) |>
          add_model(knn_spec) |>
          tune_grid(resamples = cancer_vfold, grid = 10) |>
          collect_metrics() |>
          filter(.metric == "accuracy") |>
          summarize(mx = max(mean))
        acc <- acc$mx |> unlist()

        # add this result to the dataframe
        accs[[j]] <- acc
        models[[j]] <- model_string
    }
    jstar <- which.max(unlist(accs))
    accuracies <- accuracies |> 
      add_row(size = i, 
              model_string = models[[jstar]], 
              accuracy = accs[[jstar]])
    selected <- c(selected, names[[jstar]])
    names <- names[-jstar]
}

accuracies

Dari hasilnya, dilihat bahwa kombinasi Class, Concativity dan Smoothness Memiliki nilai akurasi paling tinggi sehingga ketiga variabel itulah yang akan kita gunakan dalam membuat Classifier.