Introduction to Data Science
TUGAS : Classification II : Evaluation and Tuning
| Kontak | : \(\downarrow\) |
| : ferd.widjaya@gmail.com | |
| : 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_concavCreate 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_proportionsPreprocess 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_predictionsCompute 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_proportionsBenign 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_vfoldLalu 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_fitMenggunakan 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_metricsParameter 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")
accuraciesMenggunakan 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_kK=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_lotsUnderfitting : 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
- Menggunakan
initial_splituntuk membagi data menjadi training dan test set denganstratasebagai kelas pembagi nya - Gunakan
vfold_cvuntuk split data untuk melakukan cross-validation - Mmebuat
recipeyang menspesifikasi class labels dan prediktonya serta melakukan preprocessing data. Masukkan Training Data sebagaidatadi recipe. - Membuat
nearest_neighbormodel denganneighbor = true () - Menggabungkan Recipe dan Model ke
workflow()dengantune_griduntuk mengestimasi nilai akurasi dari nilai K - Memilih nilai K dengan Akurasi tertinggi
- membuat model baru untuk mencari Parameter
- 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_subsetMenggunakan 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]
}
accuraciesDari hasilnya, dilihat bahwa kombinasi Class, Concativity dan Smoothness Memiliki nilai akurasi paling tinggi sehingga ketiga variabel itulah yang akan kita gunakan dalam membuat Classifier.