Introduction to Data Science

Email             :
RPubs            : https://rpubs.com/Calvinriswandy/
Jurusan          : Statistika
Address         : ARA Center, Matana University Tower
                         Jl. CBD Barat Kav, RT.1, Curug Sangereng, Kelapa Dua, Tangerang, Banten 15810.


Anggota Kelompok

Statistika 2021 1. Ferdinand Nathaniel Widjaya 2. Calvin Riswandi 3. Sausan Ramadhani

Chapter 6 (Classification 2)

Latar Belakang

di chapter ini kita melanjutkan pengenalan permodelan prediktif dengan klasifikasi. Jadi, di bab sebelumnya kita membahas tentang bagai mana cara memproses data, sekarang kita akan berfokus pada mengevaluasi akurasi dan cara meningkatkan akura si dalam pengklasifikasian.

Evaluasi akurasi

Dalam membuat suatu pengklasifikasian, hasil prediksi tidak akan selalu 100%. Contohnya Biopsi yang di lakukan pada pasien, tujuannya untuk mengetahui jenis tumor yang di derita pasien. Untuk menentukannya kita harus melakukan pengklasifikasian untuk memutuskan apakah tumor yang diderita jinak atau ganas.Namun, kita tetap memerlukan beberapa sampel untuk melakukan klasifikasi. Caranya adalah dengan membagi data menjadi training set dan test set dan menggunakan training set saat membuat classifier.Lalu untuk mengeveluasi akurasi classifiernya, pertama kita pisahkan label yang sebenarnya dari test set, dan gunakan classifier untuk memprediksi labelnya yang ada di test set. Jika prediksi cocok dengan label maka untuk pengamatan diset pengujian, kita akan memiliki beberapa keyakinan bahwa pengklasifikasian yang kita lakukan mungkin akurat.

Randomness dan seeds

Di chapter ini analisis data kita akan lebih sering menggunakan data yang acak. Setiap kali kita membuat suatu keputusan dalam analisis kita harus adil dan tidak memihak siapa pun.

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

kita bisa lihat bahwa random_numbers adalah daftar 10 angka dari 0 hingga 9, jika kita menjalankan fungsi lagi akan menghasilkan nilai random lainnya.

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

Jika, kita memilih nilai seeds yang berbeda, kita akan memperoleh nilai acak yang berbeda pula.

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

Evakuasi akurasi menggunakan tidymodels

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()
## * Learn how to get started at https://www.tidymodels.org/start/
# 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

membuat test split atau train

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~

bisa kita lihat training set nya berisi 426 observasi,sedangkan test set berisi 143 observasi.

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

cancer_proportions

bisa kita lihat dengan menggunakan group_by kita bisa melihat presentase sebanyak 63% Benign dan 37% adalah malingnant.Ini menunjukkan bahwa proporsi kelas secara kasar dipertahankan saat membagi data.

Praproses Data

Pertimbangan tambahan yang perlu kita ambil saat melakukan ini adalah bahwa kita harus membuat praprosesor standarisasi hanya dengan menggunakan data pelatihan.Karena, saat menggunakan K-nearest neighbors sensitif terhadap skala prediktor dan kita harus melakukan proses awal untuk membuatnya menjadi standar. Berikut kami membuat prediksi hanya menggunakan training data dengan menggunakan cancer_train.

cancer_recipe <- recipe(Class ~ Smoothness + Concavity, data = cancer_train) |>
  step_scale(all_predictors()) |>
  step_center(all_predictors())
cancer_recipe
## Recipe
## 
## Inputs:
## 
##       role #variables
##    outcome          1
##  predictor          2
## 
## Operations:
## 
## Scaling for all_predictors()
## Centering for all_predictors()

melatih pengklasifikasian

sekarang kita akan membagi dari data asli menjadi training set dan test sets. kita akan membuat K-nearest neighbors classifier hanya dengan menggunakan training sets. pertama, kita harus membuat spesifikasi model, lalu menggabungkan spesifikasi model dengan recipe menjadi workflow,dan terakhir menggunakan fit dengan training data cancer_train 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

memprediksi label yang ada di test sets

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

menghitung akurasi

cancer_test_predictions |>
  metrics(truth = Class, estimate = .pred_class) |>
  filter(.metric == "accuracy")
confusion <- cancer_test_predictions |>
             conf_mat(truth = Class, estimate = .pred_class)
confusion
##           Truth
## Prediction  M  B
##          M 39  6
##          B 14 84

Analisis kinerja secara kritis

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)
cancer_irrelevant

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