Algoritma K-Nearest Neighbors (KNN) dengan R


Konsep K-Nearest Neighbors (KNN)
K-Nearest Neighbors (KNN) merupakan metode populer dalam bidang machine learning. Konsep dasar algoritma KNN adalah mencari k-nearest neighbors atau k tetangga terdekat dari suatu observasi berdasarkan jarak euclidean ataupun ukuran jarak lainnya. KNN umumnya digunakan untuk pemodelan klasifikasi namun dapat digunakan juga pada pemodelan regresi.
Dalam model klasifikasi, algoritma KNN menghitung jarak antara amatan yang akan diklasifikasikan dengan dataset yang sudah memiliki label kelas, dan memilih k tetangga terdekat dengan amatan tersebut berdasarkan jarak tersebut. Setelah itu, dari k tetangga tersebut, dilihat kelas apa yang paling banyak (mayoritas) menjadi tetangga terdekatnya. Hasil akhir yaitu mengklasifikasikan amatan tersebut masuk ke dalam kelas mayoritas yang diperoleh.
Prinsip Dasar dan Proses KNN
- Jarak: KNN mengukur kesamaan antara data dengan menghitung jarak antara titik data dalam ruang fitur. Jarak ini dapat diukur menggunakan berbagai metrik, seperti Euclidean, Manhattan, atau Minkowski distance.
- K-Neighbors: “K” dalam KNN menunjukkan jumlah tetangga terdekat yang akan digunakan untuk membuat prediksi. Algoritma ini memeriksa label k tetangga terdekat suatu titik data dan menentukan label mayoritas sebagai prediksi.
Langkah-Langkah KNN
- Menentukan Parameter k: Pemilihan nilai k adalah bagian kritis dari algoritma KNN. Nilai k yang terlalu kecil dapat menyebabkan model rentan terhadap noise, sedangkan nilai k yang besar dapat mengaburkan batas keputusan yang sebenarnya.
- Menghitung Jarak: Algoritma menghitung jarak antara titik data yang akan diprediksi dengan semua titik data dalam set pelatihan.
- Menentukan Tetangga Terdekat: Algoritma memilih k tetangga terdekat berdasarkan jarak yang dihitung sebelumnya.
- Menentukan Kelas Prediksi: kelas mayoritas dari tetangga terdekat digunakan sebagai prediksi untuk titik data yang dipertanyakan.


Ilustrasi di atas menunjukkan data historis mengenai karakteristik anak ayam yang baru menetas menurut dua kriteria yaitu tinggi dan bobot. Warna biru menunjukkan anak ayam betina dan orange anak ayam jantan. Secara visual dapat dilihat bahwa kecenderungan anak ayam jantan memiliki bobot dan tinggi yang lebih besar dibandingkan anak ayam betina. Pertanyaannya adalah jika kita memiliki 3 anak ayam yang baru menetas (misal amatan denganw arna merah), dan belum diketahui jenis kelaminnya bagaimana kita dapat memprediksi jenis kelamin dari ketiga anak ayam tersebut.
Penentuan kelas prediksi pada algoritma KNN diukur dari kedekatan jarak data baru tersebut dengan tetangga terdekatnya. Sebagai contoh, berdasarkan k=3 tetangga terdekat, anak ayam a kemungkinan akan diprediksi sebagai pejantan karena tiga tetangga terdekatnya adalah pejantan. Begitu pula anak ayam b akan diprediksi sebagai betina. Untuk anak ayam c, 2 dari 3 tetangga terdekatnya adalah pejantan maka akan diprediksi sebagai pejantan.
Untuk memperoleh model KNN yang baik, parameter penting yang perlu ditentukan adalah nilai k, atau jumlah tetangga terdekat yang akan digunakan. Nilai k tentu saja akan berbeda tergantung dari permasalahan dan data yang dihadapi. Penentuan nilai k optimal ini dapat dilakukan melalui proses tuning hyperparameter.
Penyiapan Data
Dataset yang digunakan memiliki format csv sehingga kita dapat membacanya menggunakan fungsi read.csv. Peubah respon atau kelas pada dataset tersimpan pada kolom quality dengan nilai LOW atau HIGH. Sementara kolom lainnya seluruhnya bertipe numerik.
R
data <- read.csv("wine-quality-binary.csv")
str(data)# OUTPUT 'data.frame': 1143 obs. of 13 variables: $ id : int 1 2 3 4 5 6 7 8 9 10 ... $ fixed.acidity : num 7.4 7.8 7.8 11.2 7.4 7.4 7.9 7.3 7.8 6.7 ... $ volatile.acidity : num 0.7 0.88 0.76 0.28 0.7 0.66 0.6 0.65 0.58 0.58 ... $ citric.acid : num 0 0 0.04 0.56 0 0 0.06 0 0.02 0.08 ... $ residual.sugar : num 1.9 2.6 2.3 1.9 1.9 1.8 1.6 1.2 2 1.8 ... $ chlorides : num 0.076 0.098 0.092 0.075 0.076 0.075 0.069 0.065 0.073 0.097 ... $ free.sulfur.dioxide : num 11 25 15 17 11 13 15 15 9 15 ... $ total.sulfur.dioxide: num 34 67 54 60 34 40 59 21 18 65 ... $ density : num 0.998 0.997 0.997 0.998 0.998 ... $ pH : num 3.51 3.2 3.26 3.16 3.51 3.51 3.3 3.39 3.36 3.28 ... $ sulphates : num 0.56 0.68 0.65 0.58 0.56 0.56 0.46 0.47 0.57 0.54 ... $ alcohol : num 9.4 9.8 9.8 9.8 9.4 9.4 9.4 10 9.5 9.2 ... $ quality : chr "LOW" "LOW" "LOW" "HIGH" ...
Dari struktur di atas dapat pula kita lihat terdapat kolom id. kolom ini hanya berisi urutan data dari 1, 2… sampai 1143 sesuai banyaknya data dan bukanlah peubah yang berkaitan dengan kelas data sehingga bisa kita hapus saja. Kita juga sebaiknya merubah tipe dari peubah respon menjadi factor. Hal ini nantinya dapat mempermudah pengukuran pada proses-proses selanjutnya.
Pada kode di bawah ini, kita juga menampilkan banyaknya data serta komposisinya menurut peubah quality. Dari total 1143 observasi, terdapat 621 yang masuk sebagai kelas "HIGH" dan 522 sebagai kelas "LOW". Berdasarkan proporsinya kedua kelas relatif seimbang yaitu dengan komposisi sekitar 54% data dengan kelas "HIGH" berbanding 46% data dengan kelas "LOW".
R
# menghapus kolom `id` data$id <- NULL # mengubah tipe kolom `quality` menjadi factor data$quality <- as.factor(data$quality) # melihat jumlah dan komposisi masing-masing kategori quality <- data.frame(table(data$quality)) quality$Prop <- round(quality$Freq/sum(quality$Freq), 3) print(quality)
# OUTPUT Var1 Freq Prop 1 HIGH 621 0.543 2 LOW 522 0.457
Pembagian Data Latih dan Data Uji
Membagi data menjadi data latih dan data uji merupakan tahapan penting dalam algoritma machine learning termasuk KNN. Pembagian ini diperlukan agar algoritma dapat diuji menggunakan data yang belum pernah dilihat selama proses pelatihan. Pada saat pelatihan, data yang digunakan hanya data latih saja. Adapun data uji nantinya digunakan untuk mengukur performa algoritma. Hal ini penting agar pengukuran performa lebih “fair” karena menggunakan data baru yang belum pernah digunakan untuk proses pelatihan.
Pembagian data pada bahasa R dapat dilakukan menggunakan fungsi createDataPartition dari pustaka caret. Proporsi banyaknya data untuk pelatihan dan pengujian dapat ditentukan dengan mengatur parameter p. Pada contoh ini, kita akan menggunakan 70% dataset sebagai data latih dan 30% sisanya menjadi data uji.
R
# Membagi data sebagai data Latih dan data uji
library(caret)
set.seed(100) # mengatur seed tertentu untuk hasil yang dapat direproduksi
# data latih = 70%, data uji = 30%
trainIndex <- createDataPartition(data$quality, p = 0.70, list = FALSE, times = 1)
# Buat data latih dan data uji berdasarkan indeks yang dihasilkan
data.train <- data[trainIndex, ]
data.test <- data[-trainIndex, ]
# melihat komposisi setiap kelas pada data train dan test
cbind("train" = table(data.train$quality), "test" = table(data.test$quality))# OUTPUT train test HIGH 435 186 LOW 366 156
Features Scaling
KNN merupakan model berbasis jarak sehingga ukuran jarak merupakan hal penting. Perbedaan skala data antar fitur akan mempengaruhi performa model yang dihasilkan. Untuk menghindari hal tersebut, disarankan untuk selalu melakukan scaling terhadap fitur, khususnya ketika perbedaan skala sangat besar. Metode scaling yang dapat digunakan salah satunya adalah normalisasi (MinMax Scaling), yaitu membuat setiap fitur memiliki nilai minimum 0 dan maksimum 1.
Proses scaling pada R dapat menggunakan fungsi preProcess dari pustaka caret. Parameter method="range" menunjukkan scaling dengan metode normalisasi. Dapat dilihat dari output di bawah ini, bahwa fitur hasil scaling seluruhnya memiliki nilai minimum 0 dan maksimum 1.
R
# Menerapkan scaling menggunakan preProcess untuk semua fitur numerik preproc.params <- preProcess(data.train[, -12], method = "range") scaled.data.train <- predict(preproc.params, data.train[, -12]) scaled.data.test <- predict(preproc.params, data.test[, -12]) summary(scaled.data.train)
# OUTPUT fixed.acidity volatile.acidity citric.acid ... alcohol Min. :0.0000 Min. :0.0000 Min. :0.000 ... Min. :0.0000 1st Qu.:0.2091 1st Qu.:0.1849 1st Qu.:0.090 ... 1st Qu.:0.1846 Median :0.2818 Median :0.2740 Median :0.260 ... Median :0.2769 Mean :0.3143 Mean :0.2838 Mean :0.271 ... Mean :0.3124 3rd Qu.:0.3818 3rd Qu.:0.3562 3rd Qu.:0.420 ... 3rd Qu.:0.4154 Max. :1.0000 Max. :1.0000 Max. :1.000 ... Max. :1.0000
KNN dengan paket ‘class’
Untuk membuat prediksi berdasarkan algoritma KNN kita dapat menggunakan fungsi knn dari pustaka class. Fungsi knn langsung menghasilkan output berupa prediksi dari kelas pada data uji yang diberikan. Pada contoh berikut, kita melakukan prediksi data uji berdasarkan data latih dengan mengambil nilai k=5.
R
library(class)
pred.knn <- knn(train=scaled.data.train, test=scaled.data.test,
cl=data.train$quality, k=5)
# Menampilkan hasil prediksi
print(pred.knn)
# Evaluasi hasil prediksi pada data uji
conf_matrix <- confusionMatrix(pred.knn, data.test$quality)
print(conf_matrix)# OUTPUT
[1] LOW LOW LOW LOW LOW LOW LOW LOW LOW LOW LOW LOW HIGH HIGH LOW
[16] LOW LOW LOW LOW HIGH LOW LOW LOW HIGH LOW LOW LOW HIGH LOW HIGH
[31] LOW LOW HIGH HIGH LOW LOW LOW LOW LOW LOW LOW HIGH LOW LOW HIGH
... ...
[301] LOW LOW HIGH LOW HIGH HIGH HIGH HIGH HIGH HIGH LOW HIGH HIGH HIGH HIGH
[316] HIGH LOW HIGH HIGH LOW HIGH HIGH LOW HIGH LOW LOW HIGH HIGH HIGH HIGH
[331] LOW HIGH LOW HIGH LOW HIGH LOW HIGH HIGH HIGH LOW HIGH
Levels: HIGH LOW
Confusion Matrix and Statistics
Reference
Prediction HIGH LOW
HIGH 136 48
LOW 50 108
Accuracy : 0.7135
95% CI : (0.6624, 0.7608)
No Information Rate : 0.5439
P-Value [Acc > NIR] : 9.525e-11
Kappa : 0.4231
Mcnemar's Test P-Value : 0.9195
Sensitivity : 0.7312
Specificity : 0.6923
Pos Pred Value : 0.7391
Neg Pred Value : 0.6835
Prevalence : 0.5439
Detection Rate : 0.3977
Detection Prevalence : 0.5380
Balanced Accuracy : 0.7117
'Positive' Class : HIGH Berdasarkan output di atas, disajikan prediksi kelas dari data uji. Misalkan pada data uji yang pertama diprediksi masuk kelas LOW, data uji kedua masuk kelas LOW sampai dengan data uji terakhir diprediksi masuk sebagai kelas HIGH. Hasil ini selanjutnya dapat dibandingkan dengan kelas sebenarnya pada data uji melalui confusion matrix.
Secara keseluruhan, nilai akurasi prediksi sebesar 0.7135 atau algoritma KNN berhasil memprediksi benar 71,35% dari data uji. Jika dilihat menurut masing-masing kelas, dari 186 data uji dengan kelas HIGH, 136 diprediksi benar, sementara 50 salah. Hasil ini memberikan nilai sensitivity (prediksi benar kelas positif) sebesar 0.7312. Selanjutnya, dari 156 data uji dengan kelas LOW, 108 diprediksi benar dan 48 salah atau memiliki nilai spesifisitas sebesar 0.6923.
KNN dengan paket ‘caret’
Pustaka caret memiliki fungsi train yang dapat dimanfaatkan untuk melakukan iterasi berbagai nilai k. Selain melakukan iterasi, fungsi train juga memungkinkan kita melakukan validasi silang sehingga hasil yang diperoleh bisa lebih dapat dipercaya dan dapat mengurangi kecenderungan overfitting.
Kode berikut ini menunjukkan bagaimana penggunaan fungsi train untuk mencari nilai k terbaik pada algoritma KNN.
R
set.seed(100) # mengatur seed tertentu untuk hasil yang dapat direproduksi
# proses pengukuran menggunakan k-fold cv dengan 5 fold
control = trainControl(method = "cv", number = 5)
# pencarian dilakukan untuk k=1,2,...30
grid = expand.grid(k = 1:30)
knn.grid <- train(x=scaled.data.train,
y=data.train$quality,
method = "knn",
trControl = control,
tuneGrid = grid)
# Menampilkan hasil model
print(knn.grid)# OUTPUT k-Nearest Neighbors 801 samples 11 predictor 2 classes: 'HIGH', 'LOW' No pre-processing Resampling: Cross-Validated (5 fold) Summary of sample sizes: 641, 641, 641, 641, 640 Resampling results across tuning parameters: k Accuracy Kappa 1 0.7116149 0.4161999 2 0.6629037 0.3182158 3 0.6891693 0.3700351 4 0.7054037 0.4034003 5 0.7278882 0.4459112 6 0.7191304 0.4296876 7 0.7315994 0.4553879 8 0.7340994 0.4596629 9 0.7366149 0.4665516 10 0.7291071 0.4512970 11 0.7353649 0.4633416 12 0.7316071 0.4548386 13 0.7341071 0.4596765 14 0.7428804 0.4784521 15 0.7378571 0.4695540 16 0.7341071 0.4616210 17 0.7315916 0.4561245 18 0.7390839 0.4724295 19 0.7378416 0.4698100 20 0.7366071 0.4671681 21 0.7291149 0.4515492 22 0.7303339 0.4536458 23 0.7340683 0.4610520 24 0.7353106 0.4632360 25 0.7240683 0.4405751 26 0.7365683 0.4657745 27 0.7290761 0.4510499 28 0.7278416 0.4488364 29 0.7290994 0.4518120 30 0.7378494 0.4699030 Accuracy was used to select the optimal model using the largest value. The final value used for the model was k = 14.
Hasil di atas menunjukkan bahwa nilai k yang menghasilkan akurasi tertinggi berdasarkan validasi silang adalah k=14 yaitu sebesar 0.74288. Namun, perlu diingat bahwa nilai tersebut adalah berdasarkan data latih. Kita perlu mengukur performa sebenarnya menggunakan data uji seperti sebelumnya. Evaluasi pada data uji menunjukkan nilai akurasi sebesar 0,7251 sementara nilai sensitivity sebesar 0,8280 dan specificity sebesar 0,6026.
R
# Membuat prediksi untuk data uji predictions <- predict(knn.grid, newdata = scaled.data.test) # Evaluasi model conf_matrix <- confusionMatrix(predictions, data.test$quality) print(conf_matrix)
# OUTPUT
Confusion Matrix and Statistics
Reference
Prediction HIGH LOW
HIGH 154 62
LOW 32 94
Accuracy : 0.7251
95% CI : (0.6746, 0.7718)
No Information Rate : 0.5439
P-Value [Acc > NIR] : 4.308e-12
Kappa : 0.4373
Mcnemar's Test P-Value : 0.00278
Sensitivity : 0.8280
Specificity : 0.6026
Pos Pred Value : 0.7130
Neg Pred Value : 0.7460
Prevalence : 0.5439
Detection Rate : 0.4503
Detection Prevalence : 0.6316
Balanced Accuracy : 0.7153
'Positive' Class : HIGH
Selamat mencoba!
API
- Fungsi
knn: knn function – RDocumentation (class) - Fungsi
train: train function – RDocumentation (caret)
Tulisan Lainnya





