BAB I PENDAHULUAN

1.1 Latar Belakang

Pada praktikum sebelumnya, klasifikasi dan prediksi dilakukan menggunakan CART, Bagging, Random Forest, dan Artificial Neural Network (ANN). Metode-metode tersebut membangun model terlebih dahulu dari data training, misalnya berupa aturan pemisahan atau bobot jaringan, lalu model tersebut digunakan untuk memprediksi data baru. K-Nearest Neighbor (K-NN) bekerja dengan cara yang berbeda. K-NN tidak membangun model secara eksplisit, tetapi menyimpan seluruh data training dan baru melakukan perhitungan ketika ada data yang akan diklasifikasikan (Hastie dkk., 2009; Cunningham & Delany, 2021). Kelas suatu observasi baru ditentukan berdasarkan kelas mayoritas dari \(k\) observasi training yang paling dekat dengannya (Fix & Hodges, 1951; Cover & Hart, 1967). Karena keputusan diambil berdasarkan jarak, hasil K-NN sangat dipengaruhi oleh skala variabel dan pemilihan nilai \(k\) (James dkk., 2021).

Kanker payudara merupakan kanker yang paling banyak didiagnosis pada perempuan di dunia (Bray dkk., 2024). Salah satu cara untuk menentukan apakah suatu tumor payudara bersifat jinak (benign) atau ganas (malignant) adalah pemeriksaan sitologi dari sampel aspirasi jarum halus, di mana beberapa karakteristik sel diberi skor 1 sampai 10 (Wolberg & Mangasarian, 1990). Dalam diagnosis, kedua jenis kesalahan tidak memiliki akibat yang sama. Tumor ganas yang diprediksi jinak (false negative) dapat membuat pasien tidak segera mendapat penanganan, sedangkan tumor jinak yang diprediksi ganas (false positive) masih dapat dikoreksi melalui pemeriksaan lanjutan. Oleh karena itu, model klasifikasi tidak cukup dinilai dari accuracy saja, tetapi juga dari sensitivity, yaitu kemampuan model mengenali tumor ganas (Altman & Bland, 1994a).

Data yang digunakan pada praktikum ini adalah Wisconsin Breast Cancer Database (BreastCancer) dari paket mlbench (Leisch & Dimitriadou, 2021). Data terlebih dahulu melalui tahap pra-pemrosesan, kemudian dibagi menjadi 80% data training dan 20% data testing dengan set.seed(12308). Prediktor diskalakan menggunakan normalisasi min-max dan hasilnya dibandingkan dengan tanpa penskalaan dan standardisasi z-score. Model K-NN dibangun menggunakan fungsi knn() dari paket class (Venables & Ripley, 2002) untuk \(k\) = 3, 5, 7, 9, dan 11, lalu dievaluasi menggunakan confusion matrix dari paket caret (Kuhn, 2008) dengan ukuran accuracy, sensitivity, specificity, dan positive predictive value. Selain itu, nilai \(k\) dieksplorasi dari 1 sampai 25 dan kurva performanya divisualisasikan menggunakan paket ggplot2 (Wickham, 2016). Nilai \(k\) optimal ditentukan dengan mempertimbangkan banyaknya false negative. Berdasarkan hal tersebut, pada praktikum Pertemuan 7 ini dilakukan klasifikasi K-NN pada data BreastCancer menggunakan RStudio.

1.2 Rumusan Masalah

Berdasarkan latar belakang di atas, rumusan masalah dalam praktikum ini adalah sebagai berikut:

  1. Bagaimana konsep fundamental, formulasi matematis, dan prinsip kerja algoritma K-Nearest Neighbors (\(k\)-NN) sebagai metode non-parametrik supervised learning?
  2. Mengapa penskalaan fitur (feature scaling) penting dalam komputasi berbasis metrik jarak (distance metrics)?
  3. Bagaimana implementasi algoritma \(k\)-NN secara terstruktur dan mandiri menggunakan bahasa pemrograman R dengan pustaka class dan caret?
  4. Bagaimana performa model klasifikasi \(k\)-NN berdasarkan Confusion Matrix, Akurasi (Accuracy), Sensitivitas (Sensitivity), Spesifisitas (Specificity), dan Positive Predictive Value?
  5. Bagaimana hasil eksplorasi optimasi hiperparameter nilai \(k\) (hyperparameter tuning) serta visualisasi kurva performanya menggunakan paket ggplot2?

1.3 Tujuan Penelitian

Berdasarkan rumusan masalah di atas, tujuan praktikum ini adalah sebagai berikut:

  1. Memahami konsep fundamental, formulasi matematis, dan prinsip kerja algoritma K-Nearest Neighbors (\(k\)-NN) sebagai metode non-parametrik supervised learning.
  2. Memahami pentingnya penskalaan fitur (feature scaling) dalam komputasi berbasis metrik jarak (distance metrics).
  3. Mengimplementasikan algoritma \(k\)-NN secara terstruktur dan mandiri menggunakan bahasa pemrograman R dengan pustaka class dan caret.
  4. Mengevaluasi performa model klasifikasi menggunakan Confusion Matrix, Akurasi (Accuracy), Sensitivitas (Sensitivity), Spesifisitas (Specificity), dan Positive Predictive Value.
  5. Melakukan eksplorasi optimasi hiperparameter nilai \(k\) (hyperparameter tuning) serta memvisualisasikan kurva performanya menggunakan paket ggplot2.

1.4 Manfaat Penelitian

Adapun manfaat pada penelitian ini yaitu:

  1. Bagi penulis
    1. Memberikan informasi serta pengetahuan tentang metode K-Nearest Neighbor dalam Machine Learning.
    2. Mengembangkan dan menerapkan wawasan ilmu yang telah diperoleh dalam bidang statistika khususnya tentang klasifikasi K-NN dengan RStudio.
  2. Bagi pembaca
    Menambah ilmu pengetahuan dan pemahaman yang berkaitan tentang klasifikasi K-NN, penskalaan fitur, serta pengaruh nilai \(k\) terhadap kesalahan diagnosis dengan RStudio.

1.5 Batasan Masalah

Adapun batasan masalah pada praktikum ini adalah lakukan pemodelan klasifikasi K-NN untuk nilai \(k \in \{3, 5, 7, 9, 11\}\) dengan data training 80% dan testing 20% menggunakan set.seed(12308). Kemudian susun tabel perbandingan metrik evaluasi (Accuracy, Sensitivity, Specificity) dan simpulkan nilai \(k\) paling optimal dengan mempertimbangkan pentingnya meminimalkan kesalahan diagnosis sel kanker ganas (False Negative). Data yang digunakan adalah data Wisconsin Breast Cancer Database (BreastCancer) dari paket mlbench dengan variabel respon Class.

1.6 Sistematika Penulisan

Adapun sistematika penulisan dari praktikum ini adalah:

BAB IPENDAHULUAN

Bab I terdiri dari latar belakang, rumusan masalah, tujuan penelitian, manfaat penelitian, batasan masalah, dan sistematika penulisan.

BAB IITINJAUAN PUSTAKA

Bab ini berisi kajian pustaka dari jurnal, buku, dan modul praktikum tentang konsep dasar dan karakteristik asimtotik K-Nearest Neighbor, kompromi bias dan varians, metrik jarak, penskalaan fitur, splitting data, dan evaluasi model klasifikasi.

BAB IIIMETODE PENELITIAN

Bab ini terdiri dari sumber data, variabel penelitian, langkah-langkah analisis, dan diagram alir.

BAB IVHASIL DAN PEMBAHASAN

Bab ini merupakan tahapan pencapaian hasil yang diperoleh dari analisis data yang dilakukan serta penjelasan dari hasil tersebut di bagian pembahasan.

BAB VKESIMPULAN DAN SARAN

Bab ini merupakan bagian penutup dalam laporan ini berupa penarikan kesimpulan mengenai hasil analisis dari penelitian serta penyampaian saran oleh penulis.

DAFTAR PUSTAKA

LAMPIRAN

BAB II TINJAUAN PUSTAKA

2.1 Konsep Dasar dan Karakteristik Asimtotik K-NN

Algoritma K-Nearest Neighbors (K-NN) pertama kali digagas oleh Fix dan Hodges (1951) sebagai metode klasifikasi nonparametrik dalam laporan penelitian untuk USAF School of Aviation Medicine. Landasan teoretis konvergensinya kemudian dibuktikan secara analitis oleh Cover dan Hart (1967). Berbeda dengan metode parametrik seperti analisis diskriminan linear atau regresi logistik yang mengasumsikan bentuk distribusi data tertentu, K-NN termasuk instance-based learning atau lazy learning. K-NN tidak membentuk model eksplisit pada tahap pelatihan, tetapi menyimpan seluruh data training dan menunda perhitungan sampai terdapat data baru (query point) yang akan diprediksi (Hastie dkk., 2009; Cunningham & Delany, 2021).

Misalkan data training terdiri dari \(n\) observasi berpasangan \[ D = \{(\mathbf{x}_1, y_1), (\mathbf{x}_2, y_2), \ldots, (\mathbf{x}_n, y_n)\} \tag{2.1} \] dengan \(\mathbf{x}_i \in \mathbb{R}^p\) adalah vektor prediktor berdimensi \(p\) dan \(y_i \in \{1, 2, \ldots, C\}\) adalah label kelas. Untuk observasi baru \(\mathbf{x}_0\), algoritma mencari himpunan \(N_k(\mathbf{x}_0)\) yang berisi \(k\) observasi training paling dekat dengan \(\mathbf{x}_0\) berdasarkan suatu ukuran jarak. Peluang posterior bahwa \(\mathbf{x}_0\) termasuk kelas \(j\) diduga dengan proporsi kelas \(j\) di antara tetangga terdekatnya, yaitu \[ \hat{P}(Y = j \mid X = \mathbf{x}_0) = \frac{1}{k}\sum_{i \in N_k(\mathbf{x}_0)} I(y_i = j) \tag{2.2} \] dengan \(I(\cdot)\) adalah fungsi indikator \[ I(y_i = j) = \begin{cases} 1, & \text{jika } y_i = j \\ 0, & \text{jika } y_i \neq j \end{cases} \tag{2.3} \] Keputusan klasifikasi akhir diambil berdasarkan suara terbanyak (majority voting), yaitu \[ \hat{G}(\mathbf{x}_0) = \underset{j \in \{1, 2, \ldots, C\}}{\arg\max}\ \hat{P}(Y = j \mid X = \mathbf{x}_0) \tag{2.4} \] Pada data dengan dua kelas, Persamaan (2.4) sama dengan memilih kelas yang paling banyak muncul di antara \(k\) tetangga. Ilustrasi cara kerja K-NN dapat dilihat pada Gambar 1.

Gambar 1. Ilustrasi klasifikasi K-NN dengan $k$ = 3 dan $k$ = 7

Gambar 1. Ilustrasi klasifikasi K-NN dengan \(k\) = 3 dan \(k\) = 7

Pada Gambar 1, titik hitam \(\mathbf{x}_0\) merupakan observasi baru. Dengan \(k\) = 3, dua dari tiga tetangga terdekat termasuk kelas ganas sehingga \(\mathbf{x}_0\) diklasifikasikan sebagai ganas. Dengan \(k\) = 7, lima dari tujuh tetangga termasuk kelas jinak sehingga \(\mathbf{x}_0\) diklasifikasikan sebagai jinak. Ilustrasi ini menunjukkan bahwa observasi yang sama dapat memperoleh kelas yang berbeda jika nilai \(k\) berubah.

2.1.1 Teorema Batas Kesalahan Cover-Hart

Cover dan Hart (1967) membuktikan bahwa ketika ukuran data training mendekati tak hingga (\(n \to \infty\)), peluang kesalahan klasifikasi aturan satu tetangga terdekat (\(k\) = 1), yang dinotasikan \(R\), dibatasi oleh peluang kesalahan pengklasifikasi Bayes optimal \(R^{*}\) sebagai berikut. \[ R^{*} \leq R \leq R^{*}\left(2 - \frac{C}{C-1}R^{*}\right) \leq 2R^{*} \tag{2.5} \] Teorema ini menjamin bahwa secara asimtotik kesalahan aturan tetangga terdekat paling buruk tidak lebih dari dua kali kesalahan pengklasifikasi optimal teoretis. Untuk dua kelas (\(C\) = 2), batas atasnya menjadi \(2R^{*}(1 - R^{*})\). Namun, jaminan ini berlaku untuk ukuran sampel yang sangat besar, sehingga pada data berukuran terbatas performa K-NN tetap bergantung pada nilai \(k\), ukuran jarak, dan penskalaan prediktor.

2.2 Kompromi Bias dan Varians (Bias-Variance Tradeoff)

Pemilihan hiperparameter \(k\) menentukan keseimbangan antara bias dan varians (James dkk., 2021; Laboratorium Matematika FMIPA Universitas Bengkulu, 2026).

  1. Nilai \(k\) kecil (misalnya \(k\) = 1) menghasilkan batas keputusan yang sangat fleksibel dan rumit. Biasnya sangat rendah, tetapi variansnya sangat tinggi, sehingga model sensitif terhadap noise dan rentan mengalami overfitting.
  2. Nilai \(k\) besar (misalnya \(k \to n\)) menghasilkan batas keputusan yang sangat halus (oversmoothing). Variansnya rendah, tetapi biasnya tinggi. Jika \(k\) terlalu besar, model dapat mengalami underfitting karena keputusan lokal terdistorsi oleh kelas mayoritas pada data secara keseluruhan.

Pada klasifikasi dua kelas, nilai \(k\) biasanya dipilih ganjil agar banyaknya suara kedua kelas tidak sama. Namun, nilai \(k\) ganjil tidak selalu menghilangkan hasil seri. Jika terdapat beberapa observasi training dengan jarak yang sama dengan jarak tetangga ke-\(k\), fungsi knn() dengan argumen use.all = TRUE mengikutsertakan seluruh observasi tersebut dalam voting, sehingga banyaknya tetangga yang memberikan suara dapat lebih dari \(k\) dan dapat berjumlah genap. Jika suara kedua kelas sama banyak, kelas dipilih secara acak (Venables & Ripley, 2002). Oleh karena itu, set.seed() perlu diberikan sebelum knn() agar hasilnya dapat direproduksi.

2.3 Metrik Jarak (Distance Metrics)

Kedekatan antara dua observasi \(\mathbf{x} = (x_1, x_2, \ldots, x_p)^\top\) dan \(\mathbf{y} = (y_1, y_2, \ldots, y_p)^\top\) dapat diukur menggunakan beberapa metrik jarak (Cunningham & Delany, 2021; Laboratorium Matematika FMIPA Universitas Bengkulu, 2026).

  1. Jarak Euclidean (\(L_2\) norm), yaitu metrik yang paling umum untuk variabel numerik kontinu. \[ d(\mathbf{x}, \mathbf{y}) = \sqrt{\sum_{i=1}^{p}\left(x_i - y_i\right)^2} \tag{2.6} \]
  2. Jarak Manhattan (\(L_1\) norm atau city block distance), yaitu jumlah selisih mutlak yang lebih tahan terhadap pencilan. \[ d(\mathbf{x}, \mathbf{y}) = \sum_{i=1}^{p}\left|x_i - y_i\right| \tag{2.7} \]
  3. Jarak Minkowski (\(L_m\) norm), yaitu bentuk umum dari dua jarak sebelumnya. Nilai \(m\) = 1 menghasilkan jarak Manhattan dan \(m\) = 2 menghasilkan jarak Euclidean. \[ d(\mathbf{x}, \mathbf{y}) = \left(\sum_{i=1}^{p}\left|x_i - y_i\right|^m\right)^{1/m}, \quad m \geq 1 \tag{2.8} \]
  4. Jarak Mahalanobis, yaitu jarak yang memperhitungkan matriks kovarians \(\boldsymbol{\Sigma}\), sehingga mengoreksi korelasi antarvariabel sekaligus perbedaan skala. \[ d(\mathbf{x}, \mathbf{y}) = \sqrt{(\mathbf{x} - \mathbf{y})^\top \boldsymbol{\Sigma}^{-1} (\mathbf{x} - \mathbf{y})} \tag{2.9} \]
  5. Jarak Hamming, yaitu ukuran ketidaksamaan untuk data biner atau kategorik. \[ d(\mathbf{x}, \mathbf{y}) = \frac{1}{p}\sum_{i=1}^{p} I(x_i \neq y_i) \tag{2.10} \]

Fungsi knn() pada paket class yang digunakan dalam praktikum ini menggunakan jarak Euclidean pada Persamaan (2.6) (Venables & Ripley, 2002). Jarak Euclidean memberikan bobot yang sama pada setiap variabel, sehingga jika dua variabel berkorelasi kuat, informasi yang sama ikut terhitung dua kali. Hal inilah yang dikoreksi oleh jarak Mahalanobis.

2.4 Penskalaan Fitur (Feature Scaling)

Jarak Euclidean dan Manhattan menghitung selisih nilai secara langsung, sehingga variabel dengan rentang nilai yang besar akan mendominasi perhitungan jarak. Oleh karena itu, tahap pra-pemrosesan pada K-NN perlu menyertakan penskalaan fitur (Han dkk., 2012; Laboratorium Matematika FMIPA Universitas Bengkulu, 2026). Dua cara yang umum digunakan adalah sebagai berikut.

  1. Normalisasi min-max, yaitu mengubah nilai variabel ke dalam selang \([0, 1]\). \[ x_{scaled} = \frac{x - x_{min}}{x_{max} - x_{min}} \tag{2.11} \]
  2. Standardisasi z-score, yaitu mengubah variabel agar memiliki rata-rata \(\mu\) = 0 dan simpangan baku \(\sigma\) = 1. \[ z = \frac{x - \mu}{\sigma} \tag{2.12} \]

Normalisasi min-max menyamakan rentang setiap variabel, sedangkan standardisasi z-score menyamakan simpangan bakunya. Akibatnya, pada z-score variabel dengan simpangan baku kecil memperoleh bobot yang lebih besar dalam jarak untuk setiap satu satuan perbedaan nilai aslinya. Parameter penskalaan, yaitu \(x_{min}\), \(x_{max}\), \(\mu\), dan \(\sigma\), harus dihitung dari data training saja, lalu digunakan juga untuk data testing. Jika dihitung dari seluruh data, informasi dari data testing ikut masuk ke tahap pelatihan sehingga hasil evaluasi menjadi terlalu optimis (Kuhn & Johnson, 2013). Selain penskalaan, K-NN juga mensyaratkan seluruh prediktor bertipe numerik dan tidak memiliki missing value, karena jarak tidak dapat dihitung pada nilai yang kosong.

2.5 Splitting Data

Data dibagi menjadi data training sebagai tempat mencari tetangga dan data testing untuk menguji kemampuan model pada data yang belum pernah dilihat (Muraina, 2022). Pada praktikum ini pembagian dilakukan menggunakan fungsi createDataPartition() dari paket caret yang mengambil sampel acak di dalam setiap kelas, sehingga proporsi benign dan malignant pada data training dan testing tetap mendekati proporsi data asli (Kuhn, 2008).

2.6 Evaluasi Model Klasifikasi

Hasil klasifikasi dua kelas diringkas dalam confusion matrix yang membandingkan kelas prediksi dengan kelas aktual (Fawcett, 2006). Pada praktikum ini kelas positif adalah malignant karena tujuan pemodelan adalah mendeteksi tumor ganas. Bentuk confusion matrix dapat dilihat pada Tabel 1.

Tabel 1. Confusion matrix dengan malignant sebagai kelas positif
Prediksi Aktual malignant Aktual benign
Malignant True Positive (TP) False Positive (FP)
Benign False Negative (FN) True Negative (TN)

Berdasarkan Tabel 1, ukuran evaluasi yang digunakan adalah sebagai berikut (Altman & Bland, 1994a, 1994b; Fawcett, 2006). \[ \text{Accuracy} = \frac{TP + TN}{TP + TN + FP + FN} \tag{2.13} \] \[ \text{Sensitivity} = \frac{TP}{TP + FN} \tag{2.14} \] \[ \text{Specificity} = \frac{TN}{TN + FP} \tag{2.15} \] \[ \text{PPV} = \frac{TP}{TP + FP} \tag{2.16} \]

Accuracy menyatakan proporsi seluruh observasi yang diklasifikasikan dengan benar. Sensitivity menyatakan proporsi tumor ganas yang berhasil dideteksi sebagai ganas, sedangkan specificity menyatakan proporsi tumor jinak yang berhasil diklasifikasikan sebagai jinak (Altman & Bland, 1994a). Positive Predictive Value (PPV) menyatakan proporsi observasi yang diprediksi ganas yang memang benar-benar ganas. Berbeda dengan sensitivity dan specificity, nilai PPV juga dipengaruhi oleh proporsi kelas positif pada data (Altman & Bland, 1994b). Berdasarkan Persamaan (2.14), meminimalkan FN sama dengan memaksimalkan sensitivity. Pada data yang kelasnya tidak seimbang, accuracy dapat tetap tinggi walaupun banyak observasi kelas minoritas salah diklasifikasikan, sehingga accuracy sebaiknya tidak digunakan sendirian (Fawcett, 2006).

2.7 Fungsi knn() dan confusionMatrix()

Model K-NN dibangun menggunakan fungsi knn() dari paket class (Venables & Ripley, 2002), sedangkan evaluasi dilakukan menggunakan fungsi confusionMatrix() dari paket caret (Kuhn, 2008). Argumen yang digunakan dan perannya dapat dilihat pada Tabel 2.

Tabel 2. Argumen fungsi knn() dan confusionMatrix() yang digunakan
Fungsi Argumen Nilai Peran
knn() train Prediktor data training hasil penskalaan Data tempat mencari tetangga terdekat
test Prediktor data testing hasil penskalaan Data yang akan diklasifikasikan
cl train$Class Kelas aktual data training
k 3, 5, 7, 9, 11 (eksplorasi 1 sampai 25) Banyaknya tetangga terdekat
prob TRUE Menyimpan proporsi suara kelas pemenang pada atribut prob
use.all TRUE (default) Seluruh observasi yang jaraknya sama dengan tetangga ke-\(k\) ikut voting
confusionMatrix() data Kelas prediksi Hasil klasifikasi model
reference test$Class Kelas aktual data testing
positive “malignant” Kelas positif, default-nya adalah level pertama, yaitu benign

Hal yang perlu diperhatikan adalah argumen positive. Jika tidak diisi, confusionMatrix() menjadikan level pertama faktor sebagai kelas positif. Pada data BreastCancer level pertama adalah benign, sehingga nilai sensitivity, specificity, dan PPV yang ditampilkan tidak sesuai dengan yang dimaksud pada Persamaan (2.14) sampai (2.16).

BAB III METODE PENELITIAN

3.1 Sumber Data

Data yang digunakan adalah data sekunder berupa dataset BreastCancer yang tersedia pada paket mlbench (Leisch & Dimitriadou, 2021). Data ini merupakan Wisconsin Breast Cancer Database yang dikumpulkan oleh Dr. William H. Wolberg di University of Wisconsin Hospitals, Madison (Wolberg & Mangasarian, 1990). Data terdiri dari 699 observasi sampel jaringan payudara dengan 11 variabel, yaitu satu variabel kode sampel, sembilan karakteristik sitologi sel yang diberi skor 1 sampai 10, dan satu variabel kelas tumor.

3.2 Variabel Penelitian

Variabel yang digunakan terdiri dari satu variabel respon dan sembilan variabel prediktor. Variabel respon (Y) adalah Class dengan dua kategori, yaitu benign dan malignant. Variabel Id hanya berupa kode sampel sehingga tidak digunakan sebagai prediktor. Seluruh prediktor berupa skor 1 sampai 10, dengan skor yang lebih besar menunjukkan kondisi sel yang semakin tidak normal. Rincian variabel dapat dilihat pada Tabel 3.

Tabel 3. Variabel penelitian
Variabel Keterangan Skala Peran
Class Kelas tumor: benign (jinak) dan malignant (ganas) Nominal Respon (Y)
Cl.thickness Ketebalan gumpalan sel (clump thickness) Skor 1–10 Prediktor (X1)
Cell.size Keseragaman ukuran sel Skor 1–10 Prediktor (X2)
Cell.shape Keseragaman bentuk sel Skor 1–10 Prediktor (X3)
Marg.adhesion Perlekatan sel pada tepi (marginal adhesion) Skor 1–10 Prediktor (X4)
Epith.c.size Ukuran sel epitel tunggal Skor 1–10 Prediktor (X5)
Bare.nuclei Inti sel tanpa sitoplasma (bare nuclei) Skor 1–10 Prediktor (X6)
Bl.cromatin Tekstur kromatin (bland chromatin) Skor 1–10 Prediktor (X7)
Normal.nucleoli Nukleolus normal Skor 1–10 Prediktor (X8)
Mitoses Aktivitas pembelahan sel (mitosis) Skor 1–10 Prediktor (X9)

3.3 Langkah-langkah Analisis

Langkah-langkah analisis yang dilakukan adalah sebagai berikut.

  1. Mengimpor data BreastCancer dari paket mlbench dan melihat struktur datanya.
  2. Melakukan pra-pemrosesan data, yaitu memeriksa dan menghapus data duplikat dan missing value, menghapus variabel Id, serta mengubah prediktor menjadi numerik.
  3. Melakukan eksplorasi data melalui proporsi kelas, rata-rata skor setiap kelas, dan korelasi antarprediktor.
  4. Membagi data menjadi 80% data training dan 20% data testing secara terstratifikasi dengan set.seed(12308).
  5. Melakukan penskalaan fitur menggunakan normalisasi min-max berdasarkan nilai minimum dan maksimum data training, lalu membandingkan hasilnya dengan tanpa penskalaan dan standardisasi z-score.
  6. Membangun model K-NN menggunakan knn() untuk \(k\) = 3, 5, 7, 9, dan 11, lalu mengklasifikasikan data testing.
  7. Menghitung confusion matrix dengan malignant sebagai kelas positif, kemudian menghitung accuracy, sensitivity, specificity, PPV, dan banyaknya FN.
  8. Melakukan eksplorasi nilai \(k\) dari 1 sampai 25 pada pembagian data utama dan pada 100 pembagian data, lalu memvisualisasikan kurva performanya menggunakan ggplot2.
  9. Membandingkan kelima nilai \(k\) pada batasan masalah dan menentukan nilai \(k\) optimal berdasarkan FN.
  10. Menginterpretasikan output dan menarik kesimpulan.

3.4 Diagram Alir Penelitian

Gambar 2. Diagram alir penelitian

Gambar 2. Diagram alir penelitian

Pada Gambar 2, data BreastCancer terlebih dahulu melalui pra-pemrosesan dan eksplorasi, kemudian dibagi menjadi data training dan testing dan diskalakan. Untuk setiap nilai \(k\), data testing diklasifikasikan menggunakan K-NN, lalu dihitung confusion matrix dan ukuran evaluasinya. Proses tersebut diulang sampai kelima nilai \(k\) selesai. Selanjutnya, kelima nilai \(k\) dibandingkan bersama kurva performa untuk \(k\) = 1 sampai 25, terutama berdasarkan FN, untuk menentukan nilai \(k\) optimal.

BAB IV HASIL DAN PEMBAHASAN

4.1 Library dan Import Data

Library yang digunakan adalah mlbench, class, caret, dan ggplot2. Paket mlbench digunakan untuk memuat data, class untuk membangun K-NN melalui fungsi knn(), caret untuk membagi data secara terstratifikasi dan menghitung confusion matrix, serta ggplot2 untuk visualisasi.

library(mlbench)
library(class)
library(caret)
library(ggplot2)
data(BreastCancer, package = "mlbench")
str(BreastCancer)
## 'data.frame':    699 obs. of  11 variables:
##  $ Id             : chr  "1000025" "1002945" "1015425" "1016277" ...
##  $ Cl.thickness   : Ord.factor w/ 10 levels "1"<"2"<"3"<"4"<..: 5 5 3 6 4 8 1 2 2 4 ...
##  $ Cell.size      : Ord.factor w/ 10 levels "1"<"2"<"3"<"4"<..: 1 4 1 8 1 10 1 1 1 2 ...
##  $ Cell.shape     : Ord.factor w/ 10 levels "1"<"2"<"3"<"4"<..: 1 4 1 8 1 10 1 2 1 1 ...
##  $ Marg.adhesion  : Ord.factor w/ 10 levels "1"<"2"<"3"<"4"<..: 1 5 1 1 3 8 1 1 1 1 ...
##  $ Epith.c.size   : Ord.factor w/ 10 levels "1"<"2"<"3"<"4"<..: 2 7 2 3 2 7 2 2 2 2 ...
##  $ Bare.nuclei    : Factor w/ 10 levels "1","2","3","4",..: 1 10 2 4 1 10 10 1 1 1 ...
##  $ Bl.cromatin    : Factor w/ 10 levels "1","2","3","4",..: 3 3 3 3 3 9 3 3 1 2 ...
##  $ Normal.nucleoli: Factor w/ 10 levels "1","2","3","4",..: 1 2 1 7 1 7 1 1 1 1 ...
##  $ Mitoses        : Factor w/ 9 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 5 1 ...
##  $ Class          : Factor w/ 2 levels "benign","malignant": 1 1 1 1 1 2 1 1 1 1 ...
table(BreastCancer$Class)
## 
##    benign malignant 
##       458       241

Data BreastCancer terdiri dari 699 observasi dan 11 variabel. Variabel Id bertipe karakter, lima prediktor pertama bertipe faktor berurutan (ordered factor), dan empat prediktor lainnya bertipe faktor. Karena K-NN menghitung jarak, seluruh prediktor perlu diubah menjadi numerik. Kelas terdiri dari 458 benign dan 241 malignant, sehingga banyaknya tumor jinak hampir dua kali tumor ganas.

4.2 Pra-pemrosesan Data

colSums(is.na(BreastCancer))
##              Id    Cl.thickness       Cell.size      Cell.shape   Marg.adhesion 
##               0               0               0               0               0 
##    Epith.c.size     Bare.nuclei     Bl.cromatin Normal.nucleoli         Mitoses 
##               0              16               0               0               0 
##           Class 
##               0
table(BreastCancer$Class[!complete.cases(BreastCancer)])
## 
##    benign malignant 
##        14         2
sum(duplicated(BreastCancer))
## [1] 8
BreastCancer[duplicated(BreastCancer), c("Id", "Cl.thickness", "Cell.size", "Class")]
##          Id Cl.thickness Cell.size     Class
## 209 1218860            1         1    benign
## 254 1100524            6        10 malignant
## 255 1116116            9        10 malignant
## 259 1198641            3         1    benign
## 273  320675            3         3 malignant
## 339  704097            1         1    benign
## 562 1321942            5         1    benign
## 685  466906            1         1    benign
levels(BreastCancer$Mitoses)
## [1] "1"  "2"  "3"  "4"  "5"  "6"  "7"  "8"  "10"

Terdapat 16 missing value yang seluruhnya berada pada Bare.nuclei, yaitu 14 observasi benign dan 2 observasi malignant. Selain itu, terdapat 8 baris yang sama persis dengan baris lain pada seluruh variabel, termasuk Id, sehingga baris tersebut merupakan sampel yang tercatat dua kali. Pada K-NN, data duplikat seperti ini perlu dihapus. Jika satu salinan masuk data training dan salinan lainnya masuk data testing, observasi testing tersebut akan menemukan tetangga dengan jarak nol dan kelas yang sama, sehingga hasil evaluasi menjadi terlalu baik.

Observasi dengan missing value juga dihapus karena jumlahnya hanya 16 dari 699 observasi (2,29%) dan hanya terdapat pada satu variabel, sedangkan K-NN tidak dapat menghitung jarak jika ada nilai yang kosong. Variabel Id dihapus karena hanya berupa kode sampel. Prediktor diubah menjadi numerik menggunakan as.numeric(as.character()), bukan as.numeric() langsung. Hal ini karena level Mitoses tidak memuat nilai 9, sehingga as.numeric() langsung akan mengubah skor 10 menjadi 9 sesuai urutan levelnya.

bc <- BreastCancer[!duplicated(BreastCancer), ]
bc <- na.omit(bc)
bc$Id <- NULL
bc[, 1:9] <- lapply(bc[, 1:9], function(x) as.numeric(as.character(x)))
dim(bc)
## [1] 675  10
str(bc)
## 'data.frame':    675 obs. of  10 variables:
##  $ Cl.thickness   : num  5 5 3 6 4 8 1 2 2 4 ...
##  $ Cell.size      : num  1 4 1 8 1 10 1 1 1 2 ...
##  $ Cell.shape     : num  1 4 1 8 1 10 1 2 1 1 ...
##  $ Marg.adhesion  : num  1 5 1 1 3 8 1 1 1 1 ...
##  $ Epith.c.size   : num  2 7 2 3 2 7 2 2 2 2 ...
##  $ Bare.nuclei    : num  1 10 2 4 1 10 10 1 1 1 ...
##  $ Bl.cromatin    : num  3 3 3 3 3 9 3 3 1 2 ...
##  $ Normal.nucleoli: num  1 2 1 7 1 7 1 1 1 1 ...
##  $ Mitoses        : num  1 1 1 1 1 1 1 1 5 1 ...
##  $ Class          : Factor w/ 2 levels "benign","malignant": 1 1 1 1 1 2 1 1 1 1 ...
##  - attr(*, "na.action")= 'omit' Named int [1:16] 24 41 140 146 159 165 235 249 271 288 ...
##   ..- attr(*, "names")= chr [1:16] "24" "41" "140" "146" ...
table(bc$Class)
## 
##    benign malignant 
##       439       236
round(prop.table(table(bc$Class)), 4)
## 
##    benign malignant 
##    0.6504    0.3496

Setelah pra-pemrosesan, data terdiri dari 675 observasi dengan 9 prediktor numerik dan 1 variabel respon. Banyaknya kelas benign 439 observasi (65,04%) dan malignant 236 observasi (34,96%), sehingga proporsinya hampir sama dengan data awal.

4.3 Eksplorasi Data

aggregate(. ~ Class, data = bc, FUN = function(x) round(mean(x), 2))
##       Class Cl.thickness Cell.size Cell.shape Marg.adhesion Epith.c.size Bare.nuclei
## 1    benign         2.97      1.31       1.42          1.35         2.11        1.35
## 2 malignant         7.20      6.56       6.54          5.64         5.31        7.61
##   Bl.cromatin Normal.nucleoli Mitoses
## 1        2.08            1.26    1.07
## 2        5.98            5.90    2.61
round(cor(bc[, 1:9]), 3)
##                 Cl.thickness Cell.size Cell.shape Marg.adhesion Epith.c.size Bare.nuclei
## Cl.thickness           1.000     0.641      0.653         0.489        0.519       0.594
## Cell.size              0.641     1.000      0.906         0.715        0.749       0.690
## Cell.shape             0.653     0.906      1.000         0.694        0.717       0.711
## Marg.adhesion          0.489     0.715      0.694         1.000        0.603       0.676
## Epith.c.size           0.519     0.749      0.717         0.603        1.000       0.583
## Bare.nuclei            0.594     0.690      0.711         0.676        0.583       1.000
## Bl.cromatin            0.556     0.759      0.738         0.672        0.623       0.679
## Normal.nucleoli        0.534     0.724      0.723         0.602        0.634       0.588
## Mitoses                0.351     0.462      0.443         0.418        0.484       0.340
##                 Bl.cromatin Normal.nucleoli Mitoses
## Cl.thickness          0.556           0.534   0.351
## Cell.size             0.759           0.724   0.462
## Cell.shape            0.738           0.723   0.443
## Marg.adhesion         0.672           0.602   0.418
## Epith.c.size          0.623           0.634   0.484
## Bare.nuclei           0.679           0.588   0.340
## Bl.cromatin           1.000           0.669   0.346
## Normal.nucleoli       0.669           1.000   0.433
## Mitoses               0.346           0.433   1.000
sum(duplicated(bc[, 1:9]))
## [1] 226
bc.long <- data.frame(Variabel = factor(rep(names(bc)[1:9], each = nrow(bc)), levels = names(bc)[1:9]),
                      Skor = unlist(bc[, 1:9]), Class = rep(bc$Class, 9))
ggplot(bc.long, aes(Class, Skor, fill = Class)) +
  geom_boxplot(width = 0.6, outlier.size = 0.8) +
  facet_wrap(~ Variabel, ncol = 3) +
  scale_fill_manual(values = c(benign = "#9AD1D4", malignant = "#F8CBA6")) +
  scale_y_continuous(breaks = c(1, 4, 7, 10)) +
  labs(x = NULL, y = "Skor") +
  theme_minimal() +
  theme(legend.position = "none")
Gambar 3. Sebaran skor setiap prediktor menurut kelas tumor

Gambar 3. Sebaran skor setiap prediktor menurut kelas tumor

Rata-rata skor seluruh prediktor pada kelas malignant lebih besar daripada kelas benign. Perbedaan terbesar terdapat pada Bare.nuclei (1,35 dan 7,61), Cell.size (1,31 dan 6,56), dan Cell.shape (1,42 dan 6,54), sedangkan perbedaan terkecil terdapat pada Mitoses (1,07 dan 2,61). Pada Gambar 3, sebagian besar skor kelas benign berada pada nilai 1 sampai 4, sedangkan skor kelas malignant menyebar lebar. Mitoses bernilai 1 pada sebagian besar observasi di kedua kelas sehingga kemampuannya membedakan kelas paling kecil. Hal ini menunjukkan bahwa kedua kelas umumnya cukup terpisah, sehingga observasi yang berdekatan cenderung berasal dari kelas yang sama. Kondisi ini sesuai dengan cara kerja K-NN.

Korelasi antarprediktor seluruhnya positif. Korelasi terkuat terdapat antara Cell.size dan Cell.shape (0,906), sedangkan Mitoses memiliki korelasi paling lemah dengan prediktor lainnya (0,340 sampai 0,484). Seperti dijelaskan pada subbab 2.3, jarak Euclidean memberi bobot yang sama pada setiap variabel, sehingga informasi keseragaman sel dari Cell.size dan Cell.shape yang hampir sama ikut terhitung dua kali dalam jarak. Selain itu, karena skor berupa bilangan bulat 1 sampai 10, terdapat 226 observasi yang nilai kesembilan prediktornya sama dengan observasi lain. Akibatnya, banyak observasi memiliki jarak yang sama, sehingga hasil seri pada penentuan tetangga ke-\(k\) akan sering terjadi.

4.4 Splitting Data

Sesuai teladan untuk NPM genap, data dibagi menjadi 80% data training dan 20% data testing dengan set.seed(12308), di mana 08 adalah dua digit terakhir NPM praktikan. Pembagian dilakukan secara terstratifikasi menggunakan createDataPartition() agar proporsi kelas malignant pada data testing tetap terjaga, karena kelas inilah yang menjadi fokus evaluasi.

set.seed(12308)
index <- createDataPartition(bc$Class, p = 0.8, list = FALSE)
train <- bc[index, ]; nrow(train)
## [1] 541
test <- bc[-index, ]; nrow(test)
## [1] 134
table(train$Class)
## 
##    benign malignant 
##       352       189
table(test$Class)
## 
##    benign malignant 
##        87        47
round(prop.table(table(test$Class)), 4)
## 
##    benign malignant 
##    0.6493    0.3507

Sebanyak 541 observasi menjadi data training, yaitu 352 benign dan 189 malignant, sedangkan 134 observasi menjadi data testing, yaitu 87 benign dan 47 malignant. Proporsi kelas pada data testing (64,93% dan 35,07%) hampir sama dengan data keseluruhan. Karena data testing hanya memuat 47 tumor ganas, setiap tambahan satu FN menurunkan sensitivity sebesar \(1/47\) atau sekitar 2,13 poin persen.

4.5 Penskalaan Fitur

Penskalaan utama dilakukan menggunakan normalisasi min-max sesuai Persamaan (2.11) dengan nilai minimum dan maksimum dari data training.

minmax <- function(data, mn, mx) as.data.frame(mapply(function(x, a, b) (x - a) / (b - a), data, mn, mx))
mn <- sapply(train[, 1:9], min)
mx <- sapply(train[, 1:9], max)
rbind(Minimum = mn, Maksimum = mx)
##          Cl.thickness Cell.size Cell.shape Marg.adhesion Epith.c.size Bare.nuclei
## Minimum             1         1          1             1            1           1
## Maksimum           10        10         10            10           10          10
##          Bl.cromatin Normal.nucleoli Mitoses
## Minimum            1               1       1
## Maksimum          10              10      10
train.n <- minmax(train[, 1:9], mn, mx)
test.n <- minmax(test[, 1:9], mn, mx)
summary(train.n[, 1:4])
##   Cl.thickness      Cell.size        Cell.shape     Marg.adhesion   
##  Min.   :0.0000   Min.   :0.0000   Min.   :0.0000   Min.   :0.0000  
##  1st Qu.:0.1111   1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.:0.0000  
##  Median :0.3333   Median :0.0000   Median :0.0000   Median :0.0000  
##  Mean   :0.3919   Mean   :0.2440   Mean   :0.2526   Mean   :0.2050  
##  3rd Qu.:0.5556   3rd Qu.:0.4444   3rd Qu.:0.4444   3rd Qu.:0.3333  
##  Max.   :1.0000   Max.   :1.0000   Max.   :1.0000   Max.   :1.0000

Pada data training, seluruh prediktor memiliki nilai minimum 1 dan maksimum 10, sehingga normalisasi min-max sama dengan mengubah setiap skor menjadi \((x - 1)/9\). Hasil ini juga sama dengan sintaks modul yang menormalisasi seluruh data sebelum splitting, karena nilai minimum dan maksimum seluruh data juga 1 dan 10. Untuk memahami pengaruh penskalaan, hasil K-NN dengan normalisasi min-max dibandingkan dengan tanpa penskalaan dan dengan standardisasi z-score sesuai Persamaan (2.12), menggunakan rata-rata dan simpangan baku data training.

mu <- sapply(train[, 1:9], mean)
sdv <- sapply(train[, 1:9], sd)
round(sdv, 3)
##    Cl.thickness       Cell.size      Cell.shape   Marg.adhesion    Epith.c.size 
##           2.794           3.123           3.032           2.866           2.193 
##     Bare.nuclei     Bl.cromatin Normal.nucleoli         Mitoses 
##           3.602           2.494           3.130           1.776
train.z <- as.data.frame(scale(train[, 1:9], center = mu, scale = sdv))
test.z <- as.data.frame(scale(test[, 1:9], center = mu, scale = sdv))

k <- c(3, 5, 7, 9, 11)
skala <- list("Tanpa penskalaan" = list(train[, 1:9], test[, 1:9]), "Min-max" = list(train.n, test.n),
              "Z-score" = list(train.z, test.z))
banding.skala <- t(sapply(skala, function(d) sapply(k, function(j) {
  set.seed(12308)
  p <- knn(d[[1]], d[[2]], cl = train$Class, k = j)
  paste(sum(p == "benign" & test$Class == "malignant"), "/", sum(p == "malignant" & test$Class == "benign"))
})))
colnames(banding.skala) <- paste("k =", k)
knitr::kable(banding.skala, align = "c", caption = "Tabel 4. Banyaknya FN / FP pada data *testing* menurut metode penskalaan")
Tabel 4. Banyaknya FN / FP pada data testing menurut metode penskalaan
k = 3 k = 5 k = 7 k = 9 k = 11
Tanpa penskalaan 3 / 3 3 / 3 3 / 2 3 / 2 3 / 2
Min-max 3 / 3 3 / 3 3 / 2 3 / 2 3 / 2
Z-score 3 / 3 3 / 2 3 / 2 3 / 2 3 / 3

Berdasarkan Tabel 4, hasil tanpa penskalaan dan dengan normalisasi min-max sama persis untuk seluruh nilai \(k\). Hal ini karena min-max mengubah semua variabel dengan cara yang sama, yaitu \((x - 1)/9\), sehingga jarak antarobservasi hanya mengecil menjadi \(1/9\) kali jarak awal dan urutan tetangga terdekat tidak berubah. Pada data ini seluruh prediktor memang sudah diukur pada skala yang sama, yaitu skor 1 sampai 10.

Sebaliknya, standardisasi z-score mengubah FP pada \(k\) = 5 (dari 3 menjadi 2) dan pada \(k\) = 11 (dari 2 menjadi 3), sedangkan FN tetap 3. Perbedaan ini muncul karena z-score membagi setiap variabel dengan simpangan bakunya, dan simpangan baku setiap variabel berbeda. Simpangan baku Mitoses paling kecil (1,776) dan Bare.nuclei paling besar (3,602), sehingga setelah standardisasi selisih satu skor pada Mitoses bernilai sekitar dua kali lipat selisih satu skor pada Bare.nuclei. Padahal, hasil eksplorasi menunjukkan Mitoses adalah prediktor yang paling lemah membedakan kelas, sedangkan Bare.nuclei paling kuat. Jadi, metode penskalaan menentukan bobot setiap variabel dalam perhitungan jarak. Karena seluruh prediktor sudah memiliki skala dan makna yang sama, normalisasi min-max lebih sesuai untuk data ini dan digunakan pada analisis selanjutnya.

4.6 Pemodelan K-NN

Model K-NN dibangun untuk kelima nilai \(k\). set.seed(12308) diberikan sebelum setiap knn() karena hasil seri pada voting ditentukan secara acak.

pred <- lapply(k, function(j) {
  set.seed(12308)
  knn(train = train.n, test = test.n, cl = train$Class, k = j, prob = TRUE)
})
names(pred) <- paste0("k=", k)
hasil <- data.frame(Aktual = test$Class, sapply(pred, as.character), check.names = FALSE, row.names = rownames(test))
head(hasil, 10)
##       Aktual       k=3       k=5       k=7       k=9      k=11
## 1     benign    benign    benign    benign    benign    benign
## 3     benign    benign    benign    benign    benign    benign
## 5     benign    benign    benign    benign    benign    benign
## 11    benign    benign    benign    benign    benign    benign
## 12    benign    benign    benign    benign    benign    benign
## 15 malignant malignant malignant malignant malignant malignant
## 18    benign    benign    benign    benign    benign    benign
## 19 malignant malignant malignant malignant malignant malignant
## 35    benign    benign    benign    benign    benign    benign
## 39 malignant malignant malignant malignant malignant malignant

Tabel hasil prediksi menunjukkan kelas aktual dan kelas prediksi setiap nilai \(k\) untuk sepuluh observasi pertama data testing, dengan nomor baris sebagai nomor observasi pada data BreastCancer. Pada sepuluh observasi tersebut, kelima nilai \(k\) menghasilkan prediksi yang sama dan seluruhnya sesuai dengan kelas aktual. Untuk melihat pengaruh hasil seri yang ditemukan pada eksplorasi data, dihitung banyaknya observasi training yang ikut voting untuk setiap observasi testing, serta banyaknya kesalahan klasifikasi jika seed sebelum knn() diganti dari 1 sampai 20.

D <- as.matrix(dist(rbind(test.n, train.n)))[seq_len(nrow(test.n)), -seq_len(nrow(test.n))]
voter <- sapply(k, function(j) apply(D, 1, function(d) sum(d <= sort(d)[j] + 1e-9)))
salah <- sapply(k, function(j) sapply(1:20, function(s) {
  set.seed(s)
  sum(knn(train.n, test.n, cl = train$Class, k = j) != test$Class)
}))
seri <- data.frame(k = k, Rata2 = colMeans(voter), Maks = apply(voter, 2, max),
                   Persen = 100 * colMeans(voter > rep(k, each = nrow(voter))),
                   Min_salah = apply(salah, 2, min), Maks_salah = apply(salah, 2, max))
knitr::kable(seri, digits = 2, align = "c", format.args = list(decimal.mark = ","),
             col.names = c("k", "Rata-rata tetangga yang voting", "Maksimum tetangga yang voting",
                           "Persentase observasi testing dengan tetangga > k (%)",
                           "Kesalahan minimum (20 seed)", "Kesalahan maksimum (20 seed)"),
             caption = "Tabel 5. Banyaknya tetangga yang ikut *voting* dan kesalahan klasifikasi dari 20 *seed*")
Tabel 5. Banyaknya tetangga yang ikut voting dan kesalahan klasifikasi dari 20 seed
k Rata-rata tetangga yang voting Maksimum tetangga yang voting Persentase observasi testing dengan tetangga > k (%) Kesalahan minimum (20 seed) Kesalahan maksimum (20 seed)
3 7,44 26 63,43 5 6
5 10,90 54 58,96 5 6
7 13,31 54 70,15 5 5
9 15,97 54 67,91 5 5
11 17,74 54 64,18 5 5

Berdasarkan Tabel 5, pada lebih dari separuh observasi testing banyaknya tetangga yang ikut voting lebih besar daripada \(k\). Pada \(k\) = 3, rata-rata tetangga yang ikut voting adalah 7,44 dan paling banyak 26 observasi, sedangkan pada \(k\) = 5 sampai 11 dapat mencapai 54 observasi. Hal ini terjadi karena banyak observasi training memiliki skor yang sama, sehingga jaraknya terhadap observasi testing juga sama dan seluruhnya ikut voting sesuai argumen use.all = TRUE. Akibatnya, perbedaan \(k\) yang dicoba tidak sebesar angkanya, karena pada banyak observasi \(k\) = 3 dan \(k\) = 11 sebenarnya menggunakan tetangga yang hampir sama.

Kolom kesalahan pada Tabel 5 menunjukkan bahwa pada \(k\) = 3 dan \(k\) = 5, banyaknya observasi yang salah diklasifikasikan berubah antara 5 dan 6 ketika seed diganti. Artinya, terdapat observasi dengan hasil voting seri yang kelasnya ditentukan secara acak. Pada \(k\) = 7, 9, dan 11, banyaknya kesalahan tetap 5 untuk seluruh seed. Hal ini perlu diingat ketika membandingkan hasil antarnilai \(k\) pada subbab berikutnya.

4.7 Confusion Matrix dan Evaluasi Model

Sebelum menghitung ukuran evaluasi seluruh model, terlebih dahulu dibandingkan output confusionMatrix() tanpa dan dengan argumen positive pada model \(k\) = 7.

confusionMatrix(pred[["k=7"]], test$Class)$byClass[c("Sensitivity", "Specificity", "Pos Pred Value")]
##    Sensitivity    Specificity Pos Pred Value 
##      0.9770115      0.9361702      0.9659091
cm <- lapply(pred, function(p) confusionMatrix(p, test$Class, positive = "malignant"))
cm[["k=7"]]
## Confusion Matrix and Statistics
## 
##            Reference
## Prediction  benign malignant
##   benign        85         3
##   malignant      2        44
##                                           
##                Accuracy : 0.9627          
##                  95% CI : (0.9151, 0.9878)
##     No Information Rate : 0.6493          
##     P-Value [Acc > NIR] : <2e-16          
##                                           
##                   Kappa : 0.9177          
##                                           
##  Mcnemar's Test P-Value : 1               
##                                           
##             Sensitivity : 0.9362          
##             Specificity : 0.9770          
##          Pos Pred Value : 0.9565          
##          Neg Pred Value : 0.9659          
##              Prevalence : 0.3507          
##          Detection Rate : 0.3284          
##    Detection Prevalence : 0.3433          
##       Balanced Accuracy : 0.9566          
##                                           
##        'Positive' Class : malignant       
## 

Tanpa argumen positive, sensitivity bernilai 0,9770, specificity 0,9362, dan PPV 0,9659. Nilai tersebut dihitung dengan benign sebagai kelas positif, sehingga sensitivity yang ditampilkan sebenarnya adalah kemampuan model mengenali tumor jinak. Dengan positive = “malignant”, sensitivity menjadi 0,9362, specificity 0,9770, dan PPV 0,9565, sesuai Persamaan (2.14) sampai (2.16). Jika argumen ini tidak diperhatikan, kemampuan model dalam mendeteksi tumor ganas akan terlihat lebih tinggi daripada yang sebenarnya.

Output confusionMatrix() untuk \(k\) = 7 menunjukkan bahwa dari 47 tumor ganas, 44 terdeteksi sebagai ganas (TP) dan 3 diprediksi jinak (FN). Dari 87 tumor jinak, 85 diprediksi jinak (TN) dan 2 diprediksi ganas (FP). Accuracy sebesar 96,27% dengan selang kepercayaan 95% antara 91,51% dan 98,78%. Nilai ini jauh lebih besar daripada No Information Rate (64,93%), yaitu accuracy yang diperoleh jika seluruh observasi diprediksi sebagai kelas terbanyak (benign), dengan p-value kurang dari \(2 \times 10^{-16}\). Nilai Kappa sebesar 0,9177 menunjukkan kesesuaian prediksi dan kelas aktual yang sangat tinggi setelah memperhitungkan kesesuaian karena kebetulan. PPV (Pos Pred Value) sebesar 95,65% berarti dari 46 tumor yang diprediksi ganas, 44 memang ganas. Ukuran evaluasi kelima nilai \(k\) disajikan pada Tabel 6.

eval.knn <- data.frame(k = k, t(sapply(cm, function(m) c(
  TP = m$table["malignant", "malignant"], FN = m$table["benign", "malignant"],
  FP = m$table["malignant", "benign"], TN = m$table["benign", "benign"],
  Accuracy = 100 * unname(m$overall["Accuracy"]),
  Sensitivity = 100 * unname(m$byClass["Sensitivity"]),
  Specificity = 100 * unname(m$byClass["Specificity"]),
  PPV = 100 * unname(m$byClass["Pos Pred Value"])))), row.names = NULL)
knitr::kable(eval.knn, digits = 2, align = "c", format.args = list(decimal.mark = ","),
             col.names = c("k", "TP", "FN", "FP", "TN", "Accuracy (%)", "Sensitivity (%)", "Specificity (%)", "PPV (%)"),
             caption = "Tabel 6. Perbandingan metrik evaluasi K-NN pada data *testing*")
Tabel 6. Perbandingan metrik evaluasi K-NN pada data testing
k TP FN FP TN Accuracy (%) Sensitivity (%) Specificity (%) PPV (%)
3 44 3 3 84 95,52 93,62 96,55 93,62
5 44 3 3 84 95,52 93,62 96,55 93,62
7 44 3 2 85 96,27 93,62 97,70 95,65
9 44 3 2 85 96,27 93,62 97,70 95,65
11 44 3 2 85 96,27 93,62 97,70 95,65

Berdasarkan Tabel 6, kelima nilai \(k\) menghasilkan FN yang sama, yaitu 3, sehingga sensitivity seluruh model sama sebesar 93,62%. Artinya, dari setiap 100 tumor ganas, sekitar 94 berhasil dideteksi dan sekitar 6 lolos sebagai tumor jinak. Perbedaan hanya terdapat pada FP. Model \(k\) = 3 dan \(k\) = 5 memiliki 3 FP dengan specificity 96,55%, PPV 93,62%, dan accuracy 95,52%, sedangkan model \(k\) = 7, 9, dan 11 memiliki 2 FP dengan specificity 97,70%, PPV 95,65%, dan accuracy 96,27%. Jadi, pada pembagian data ini, perubahan \(k\) dari 3 sampai 11 tidak mengubah kemampuan model dalam mendeteksi tumor ganas dan hanya mengubah satu prediksi tumor jinak.

Untuk mengetahui penyebabnya, observasi yang salah diklasifikasikan oleh setidaknya satu nilai \(k\) ditampilkan sebagai berikut. Kolom prob_k7 adalah proporsi suara untuk kelas pemenang pada \(k\) = 7.

r <- rownames(test)[rowSums(sapply(pred, function(p) p != test$Class)) > 0]
test[r, ]
##     Cl.thickness Cell.size Cell.shape Marg.adhesion Epith.c.size Bare.nuclei Bl.cromatin
## 223            4         1          1             3            1           5           2
## 253            6         3          3             5            3          10           3
## 260            5         7          7             1            5           8           3
## 357            5         3          3             1            3           3           3
## 490            6         3          2             1            3           4           4
## 658            5         4          5             1            8           1           3
##     Normal.nucleoli Mitoses     Class
## 223               1       1 malignant
## 253               5       3    benign
## 260               4       1    benign
## 357               3       3 malignant
## 490               1       1 malignant
## 658               6       1    benign
data.frame(hasil[r, ], prob_k7 = round(attr(pred[["k=7"]], "prob")[match(r, rownames(test))], 3), check.names = FALSE)
##        Aktual       k=3       k=5       k=7       k=9      k=11 prob_k7
## 223 malignant    benign    benign    benign    benign    benign   1.000
## 253    benign malignant malignant malignant malignant malignant   1.000
## 260    benign malignant malignant malignant malignant malignant   0.750
## 357 malignant    benign    benign    benign    benign    benign   0.818
## 490 malignant    benign    benign    benign    benign    benign   0.875
## 658    benign malignant malignant    benign    benign    benign   0.571

Terdapat enam observasi yang salah diklasifikasikan. Observasi 223, 357, dan 490 adalah tumor ganas yang diprediksi jinak oleh kelima nilai \(k\). Ketiganya memiliki skor Cell.size dan Cell.shape yang rendah (1 sampai 3), sehingga profil selnya lebih mirip tumor jinak. Proporsi suara untuk kelas benign pada \(k\) = 7 mencapai 1, 0,818, dan 0,875, sehingga tetangga terdekatnya hampir seluruhnya tumor jinak dan perubahan \(k\) tidak dapat memperbaikinya. Kasus seperti ini juga dilaporkan oleh Wolberg dan Mangasarian (1990), yaitu terdapat tumor ganas yang hasil sitologinya terlihat jinak dan diduga karena jaringan tumor tidak terambil saat aspirasi. Dengan kata lain, ketiga FN tersebut bukan berasal dari pemilihan \(k\), tetapi dari observasi ganas yang memang sulit dibedakan menggunakan sembilan skor sitologi ini.

Observasi 253 dan 260 adalah tumor jinak yang memiliki skor tinggi pada beberapa prediktor, misalnya Bare.nuclei sebesar 10 dan 8, sehingga diprediksi ganas oleh seluruh nilai \(k\). Satu-satunya observasi yang hasilnya berbeda antarnilai \(k\) adalah observasi 658, yaitu tumor jinak yang diprediksi ganas oleh \(k\) = 3 dan 5, tetapi diprediksi jinak oleh \(k\) = 7, 9, dan 11. Proporsi suara benign pada \(k\) = 7 hanya 0,571, yang berarti tetangganya bercampur antara kedua kelas. Berdasarkan Tabel 5, kelas observasi seperti ini pada \(k\) = 3 dan 5 dapat berubah jika seed berubah, sehingga selisih satu FP antara \(k\) = 3, 5 dan \(k\) = 7, 9, 11 belum cukup kuat untuk menyimpulkan bahwa nilai \(k\) yang lebih besar memang lebih baik.

4.8 Eksplorasi Nilai \(k\) (Hyperparameter Tuning)

Sesuai sintaks modul, nilai \(k\) dieksplorasi dari 1 sampai 25 untuk melihat kurva performanya. Eksplorasi pertama dilakukan pada pembagian data utama dengan set.seed(12308).

kurva <- do.call(rbind, lapply(1:25, function(j) {
  set.seed(12308)
  p <- knn(train.n, test.n, cl = train$Class, k = j)
  m <- confusionMatrix(p, test$Class, positive = "malignant")
  data.frame(k = j, Accuracy = 100 * m$overall[["Accuracy"]], Sensitivity = 100 * m$byClass[["Sensitivity"]],
             Specificity = 100 * m$byClass[["Specificity"]], PPV = 100 * m$byClass[["Pos Pred Value"]],
             FN = m$table["benign", "malignant"], FP = m$table["malignant", "benign"])
}))
print(kurva, digits = 4, row.names = FALSE)
##   k Accuracy Sensitivity Specificity   PPV FN FP
##   1    96.27       93.62       97.70 95.65  3  2
##   2    96.27       95.74       96.55 93.75  2  3
##   3    95.52       93.62       96.55 93.62  3  3
##   4    96.27       95.74       96.55 93.75  2  3
##   5    95.52       93.62       96.55 93.62  3  3
##   6    95.52       93.62       96.55 93.62  3  3
##   7    96.27       93.62       97.70 95.65  3  2
##   8    96.27       93.62       97.70 95.65  3  2
##   9    96.27       93.62       97.70 95.65  3  2
##  10    96.27       93.62       97.70 95.65  3  2
##  11    96.27       93.62       97.70 95.65  3  2
##  12    96.27       93.62       97.70 95.65  3  2
##  13    96.27       93.62       97.70 95.65  3  2
##  14    96.27       93.62       97.70 95.65  3  2
##  15    96.27       93.62       97.70 95.65  3  2
##  16    96.27       93.62       97.70 95.65  3  2
##  17    96.27       93.62       97.70 95.65  3  2
##  18    96.27       93.62       97.70 95.65  3  2
##  19    96.27       93.62       97.70 95.65  3  2
##  20    96.27       93.62       97.70 95.65  3  2
##  21    96.27       93.62       97.70 95.65  3  2
##  22    96.27       93.62       97.70 95.65  3  2
##  23    96.27       93.62       97.70 95.65  3  2
##  24    96.27       93.62       97.70 95.65  3  2
##  25    96.27       93.62       97.70 95.65  3  2

Pada pembagian data utama, model \(k\) = 1 memiliki 3 FN dan 2 FP. Model \(k\) = 2 dan 4 memiliki FN paling sedikit, yaitu 2, tetapi FP-nya 3. Nilai \(k\) genap pada dua kelas sangat mungkin menghasilkan suara seri yang kelasnya ditentukan secara acak, sehingga hasil ini tidak dapat dijadikan dasar pemilihan \(k\). Mulai \(k\) = 7 sampai \(k\) = 25, hasilnya tidak berubah sama sekali, yaitu 3 FN dan 2 FP. Jadi, pada satu pembagian data dengan 134 observasi testing, kurva performa hampir datar dan tidak memperlihatkan pola yang jelas. Hal ini sejalan dengan Tabel 5 dan hasil subbab 4.7, yaitu banyak observasi memiliki tetangga yang sama untuk berbagai nilai \(k\), sedangkan observasi yang salah diklasifikasikan memiliki lingkungan tetangga yang hampir seluruhnya dari kelas lain.

Karena satu pembagian data belum cukup untuk melihat pola, eksplorasi diulang pada 100 pembagian data 80% dan 20% dengan seed 1 sampai 100. Pada setiap pembagian, penskalaan min-max dihitung ulang dari data training pembagian tersebut.

ulang <- do.call(rbind, lapply(1:100, function(s) {
  set.seed(s)
  i <- createDataPartition(bc$Class, p = 0.8, list = FALSE)
  a <- bc[i, ]; b <- bc[-i, ]
  mn.s <- sapply(a[, 1:9], min); mx.s <- sapply(a[, 1:9], max)
  a.n <- minmax(a[, 1:9], mn.s, mx.s); b.n <- minmax(b[, 1:9], mn.s, mx.s)
  do.call(rbind, lapply(1:25, function(j) {
    set.seed(s)
    p <- knn(a.n, b.n, cl = a$Class, k = j)
    TP <- sum(p == "malignant" & b$Class == "malignant"); FP <- sum(p == "malignant" & b$Class == "benign")
    data.frame(seed = s, k = j, Accuracy = 100 * mean(p == b$Class),
               Sensitivity = 100 * mean(p[b$Class == "malignant"] == "malignant"),
               Specificity = 100 * mean(p[b$Class == "benign"] == "benign"),
               PPV = 100 * TP / (TP + FP), FN = sum(p == "benign" & b$Class == "malignant"))
  }))
}))
rata <- aggregate(cbind(Accuracy, Sensitivity, Specificity, PPV, FN) ~ k, data = ulang, FUN = mean)
print(rata, digits = 4, row.names = FALSE)
##   k Accuracy Sensitivity Specificity   PPV   FN
##   1    95.95       93.23       97.41 95.21 3.18
##   2    96.10       93.81       97.34 95.11 2.91
##   3    97.07       95.94       97.69 95.82 1.91
##   4    97.02       95.85       97.66 95.74 1.95
##   5    97.20       96.04       97.83 96.05 1.86
##   6    97.06       95.62       97.84 96.05 2.06
##   7    97.08       95.81       97.77 95.94 1.97
##   8    96.91       95.45       97.70 95.80 2.14
##   9    96.92       95.34       97.77 95.93 2.19
##  10    96.92       95.38       97.75 95.89 2.17
##  11    96.91       95.28       97.79 95.95 2.22
##  12    96.84       95.15       97.75 95.86 2.28
##  13    96.80       95.04       97.75 95.86 2.33
##  14    96.82       95.02       97.79 95.94 2.34
##  15    96.83       94.98       97.83 96.00 2.36
##  16    96.78       94.77       97.87 96.07 2.46
##  17    96.77       94.64       97.92 96.15 2.52
##  18    96.74       94.43       97.99 96.26 2.62
##  19    96.66       94.17       98.00 96.27 2.74
##  20    96.61       93.94       98.06 96.37 2.85
##  21    96.53       93.70       98.06 96.36 2.96
##  22    96.51       93.62       98.08 96.40 3.00
##  23    96.46       93.45       98.08 96.39 3.08
##  24    96.43       93.36       98.09 96.41 3.12
##  25    96.42       93.30       98.10 96.43 3.15
ukuran <- c("Accuracy", "Sensitivity", "Specificity", "PPV")
kurva.df <- rbind(
  data.frame(Data = "set.seed(12308)", k = rep(kurva$k, 4), Ukuran = rep(ukuran, each = 25), Nilai = unlist(kurva[, ukuran])),
  data.frame(Data = "Rata-rata 100 pembagian data", k = rep(rata$k, 4), Ukuran = rep(ukuran, each = 25), Nilai = unlist(rata[, ukuran])))
kurva.df$Data <- factor(kurva.df$Data, levels = c("set.seed(12308)", "Rata-rata 100 pembagian data"))

ggplot(kurva.df, aes(k, Nilai, colour = Ukuran)) +
  annotate("rect", xmin = 3, xmax = 11, ymin = -Inf, ymax = Inf, fill = "grey92") +
  geom_line(linewidth = 0.8) +
  geom_point(size = 1.6) +
  facet_wrap(~ Data) +
  scale_x_continuous(breaks = seq(1, 25, by = 2)) +
  scale_colour_manual(values = c(Accuracy = "#2b5c8f", Sensitivity = "#d95f02", Specificity = "#7B5EA7", PPV = "#008080")) +
  labs(x = "Jumlah tetangga terdekat (k)", y = "Persentase (%)", colour = "") +
  theme_minimal() +
  theme(legend.position = "bottom", panel.grid.minor = element_blank())
Gambar 4. Kurva performa K-NN untuk $k$ = 1 sampai 25 pada *set.seed*(12308) dan rata-rata 100 pembagian data

Gambar 4. Kurva performa K-NN untuk \(k\) = 1 sampai 25 pada set.seed(12308) dan rata-rata 100 pembagian data

Pada Gambar 4, daerah abu-abu menunjukkan rentang \(k\) = 3 sampai 11 yang menjadi batasan masalah. Panel kiri memperlihatkan kurva yang hampir datar pada pembagian data utama, sedangkan panel kanan memperlihatkan pola yang lebih jelas setelah hasil 100 pembagian data dirata-ratakan. Rata-rata sensitivity naik dari 93,23% pada \(k\) = 1 menjadi sekitar 96% pada \(k\) = 3 sampai 5, kemudian turun terus sampai 93,30% pada \(k\) = 25. Pola ini sama dengan rata-rata FN yang turun dari 3,18 pada \(k\) = 1 menjadi 1,86 pada \(k\) = 5, lalu naik kembali sampai 3,15 pada \(k\) = 25. Sebaliknya, rata-rata specificity dan PPV justru naik perlahan ketika \(k\) bertambah, yaitu dari 97,41% dan 95,21% pada \(k\) = 1 menjadi 98,10% dan 96,43% pada \(k\) = 25. Rata-rata accuracy tertinggi terdapat pada \(k\) = 5 (97,20%).

Pola tersebut sesuai dengan kompromi bias dan varians pada subbab 2.2. Pada \(k\) = 1 dan 2, keputusan hanya bergantung pada satu atau dua tetangga sehingga mudah terpengaruh noise dan kesalahannya lebih banyak. Pada \(k\) yang besar, tetangga yang lebih jauh ikut menentukan kelas, sehingga keputusan semakin terdorong ke kelas mayoritas, yaitu benign. Akibatnya, tumor jinak semakin jarang salah diklasifikasikan, tetapi semakin banyak tumor ganas yang lolos sebagai jinak. Untuk tujuan diagnosis, kondisi ini tidak diinginkan karena FN lebih berbahaya daripada FP. Ringkasan untuk kelima nilai \(k\) pada batasan masalah disajikan pada Tabel 7.

ulang5 <- ulang[ulang$k %in% k, ]
ringkas <- aggregate(cbind(Accuracy, Sensitivity, Specificity, PPV, FN) ~ k, data = ulang5, FUN = mean)
fn <- xtabs(FN ~ seed + k, data = ulang5)
ringkas$FN_min <- colSums(fn == apply(fn, 1, min))
knitr::kable(ringkas, digits = 2, align = "c", format.args = list(decimal.mark = ","),
             col.names = c("k", "Rata-rata accuracy (%)", "Rata-rata sensitivity (%)", "Rata-rata specificity (%)",
                           "Rata-rata PPV (%)", "Rata-rata FN", "Banyak pembagian dengan FN terkecil"),
             caption = "Tabel 7. Ringkasan hasil K-NN dari 100 pembagian data untuk $k$ = 3, 5, 7, 9, dan 11")
Tabel 7. Ringkasan hasil K-NN dari 100 pembagian data untuk \(k\) = 3, 5, 7, 9, dan 11
k Rata-rata accuracy (%) Rata-rata sensitivity (%) Rata-rata specificity (%) Rata-rata PPV (%) Rata-rata FN Banyak pembagian dengan FN terkecil
3 97,07 95,94 97,69 95,82 1,91 59
5 97,20 96,04 97,83 96,05 1,86 60
7 97,08 95,81 97,77 95,94 1,97 55
9 96,92 95,34 97,77 95,93 2,19 43
11 96,91 95,28 97,79 95,95 2,22 42
# perbandingan FN setiap k terhadap k = 7 pada pembagian data yang sama
sapply(c("3", "5", "9", "11"), function(j) c(Lebih_kecil = sum(fn[, j] < fn[, "7"]),
                                             Sama = sum(fn[, j] == fn[, "7"]),
                                             Lebih_besar = sum(fn[, j] > fn[, "7"])))
##              3  5  9 11
## Lebih_kecil 27 28  7 13
## Sama        47 52 67 53
## Lebih_besar 26 20 26 34

Berdasarkan Tabel 7, rata-rata FN pada \(k\) = 3, 5, dan 7 hampir sama, yaitu 1,91; 1,86; dan 1,97, sedangkan pada \(k\) = 9 dan 11 lebih besar, yaitu 2,19 dan 2,22. Banyaknya pembagian data dengan FN terkecil juga lebih banyak pada \(k\) = 3, 5, dan 7 (59, 60, dan 55 kali) dibandingkan \(k\) = 9 dan 11 (43 dan 42 kali). Rata-rata specificity dan PPV kelima nilai \(k\) hampir sama, yaitu 97,69% sampai 97,83% dan 95,82% sampai 96,05%.

Perbandingan pada pembagian data yang sama menunjukkan bahwa FN \(k\) = 3 dan \(k\) = 7 hampir seimbang, yaitu \(k\) = 3 lebih kecil pada 27 pembagian dan lebih besar pada 26 pembagian. FN \(k\) = 5 lebih kecil daripada \(k\) = 7 pada 28 pembagian dan lebih besar pada 20 pembagian. Selisih pada \(k\) = 3 dan 5 tersebut kecil, dan sekitar separuh pembagian menghasilkan FN yang sama dengan \(k\) = 7. Sebaliknya, FN \(k\) = 9 lebih besar daripada \(k\) = 7 pada 26 pembagian dan hanya lebih kecil pada 7 pembagian, sedangkan FN \(k\) = 11 lebih besar pada 34 pembagian dan hanya lebih kecil pada 13 pembagian. Artinya, di antara kelima nilai \(k\) pada batasan masalah, kenaikan FN mulai terlihat jelas setelah \(k\) = 7.

4.9 Penentuan Nilai \(k\) Optimal

Penentuan nilai \(k\) optimal didasarkan pada kriteria utama meminimalkan FN, kemudian kriteria specificity, PPV, dan accuracy digunakan apabila FN sama. Pada pembagian data dengan set.seed(12308), kelima nilai \(k\) memiliki FN yang sama (3), sehingga kriteria FN belum dapat membedakan model. Berdasarkan specificity, PPV, dan accuracy, model terbaik adalah \(k\) = 7, 9, dan 11. Hasil 100 pembagian data kemudian menunjukkan bahwa FN paling rendah berada pada \(k\) = 3 sampai 7, sedangkan pada \(k\) = 9 dan 11 FN cenderung bertambah.

Dengan demikian, nilai \(k\) paling optimal adalah \(k\) = 7, dengan accuracy 96,27%, sensitivity 93,62%, specificity 97,70%, PPV 95,65%, 3 FN, dan 2 FP pada data testing. Nilai \(k\) = 7 merupakan satu-satunya nilai yang termasuk kelompok terbaik pada pembagian data utama sekaligus kelompok dengan FN rendah pada 100 pembagian data. Selain itu, berdasarkan Tabel 5, hasil \(k\) = 7 pada data testing tidak berubah ketika seed diganti, sedangkan hasil \(k\) = 3 dan 5 masih bergantung pada pemilihan acak saat voting seri. Namun, perlu dicatat bahwa perbedaan \(k\) = 7 dengan \(k\) = 3 dan 5 sangat kecil. Pada data testing selisihnya hanya satu FP, dan pada 100 pembagian data selisih rata-rata FN-nya hanya sekitar 0,1 observasi per pembagian. Jadi, \(k\) = 3, 5, dan 7 sama-sama layak digunakan, sedangkan \(k\) = 9 dan 11 kurang disarankan karena cenderung meningkatkan FN.

BAB V KESIMPULAN DAN SARAN

5.1 Kesimpulan

Berdasarkan hasil praktikum, diperoleh kesimpulan sebagai berikut.

  1. K-Nearest Neighbor (K-NN) adalah metode klasifikasi nonparametrik supervised learning yang tidak membangun model secara eksplisit. Untuk observasi baru, K-NN mencari \(k\) observasi training terdekat, menduga peluang setiap kelas dengan proporsi kelas di antara tetangga tersebut, lalu memilih kelas dengan suara terbanyak. Menurut teorema Cover-Hart, untuk ukuran sampel yang sangat besar kesalahan aturan satu tetangga terdekat tidak lebih dari dua kali kesalahan pengklasifikasi Bayes. Nilai \(k\) mengendalikan kompromi bias dan varians, yaitu \(k\) kecil cenderung overfitting dan \(k\) besar cenderung underfitting.
  2. Penskalaan fitur penting karena metrik jarak menghitung selisih nilai secara langsung, sehingga variabel dengan rentang besar akan mendominasi jarak. Pada data BreastCancer, seluruh prediktor sudah berada pada skala 1 sampai 10, sehingga hasil tanpa penskalaan dan dengan normalisasi min-max sama persis. Standardisasi z-score mengubah FP pada \(k\) = 5 dan 11 karena memberi bobot lebih besar pada variabel dengan simpangan baku kecil, seperti Mitoses. Jadi, metode penskalaan menentukan bobot setiap variabel dalam perhitungan jarak.
  3. K-NN diimplementasikan di R melalui tahapan pra-pemrosesan, yaitu menghapus 8 data duplikat, 16 observasi dengan missing value, dan variabel Id, serta mengubah prediktor menjadi numerik dengan as.numeric(as.character()). Data dibagi secara terstratifikasi menjadi 541 data training dan 134 data testing dengan set.seed(12308), diskalakan menggunakan min-max, lalu diklasifikasikan menggunakan knn() dari paket class. Evaluasi dilakukan menggunakan confusionMatrix() dari paket caret dengan argumen positive = “malignant”, karena tanpa argumen tersebut sensitivity, specificity, dan PPV dihitung dengan benign sebagai kelas positif.
  4. Kelima nilai \(k\) memiliki FN yang sama, yaitu 3, dengan sensitivity 93,62%. Model \(k\) = 7, 9, dan 11 memiliki accuracy 96,27%, specificity 97,70%, dan PPV 95,65%, sedikit lebih baik daripada \(k\) = 3 dan 5 yang memiliki accuracy 95,52%, specificity 96,55%, dan PPV 93,62%. Ketiga FN berasal dari tumor ganas yang skor sitologinya mirip tumor jinak, sehingga tidak dapat diperbaiki hanya dengan mengubah nilai \(k\).
  5. Kurva performa \(k\) = 1 sampai 25 pada pembagian data utama hampir datar mulai \(k\) = 7. Rata-rata 100 pembagian data memperlihatkan bahwa FN paling rendah berada pada \(k\) = 3 sampai 7, sedangkan \(k\) yang lebih kecil atau lebih besar menghasilkan FN lebih banyak. Semakin besar \(k\), specificity dan PPV sedikit naik tetapi sensitivity turun karena keputusan terdorong ke kelas mayoritas. Berdasarkan kriteria meminimalkan FN, nilai \(k\) paling optimal adalah \(k\) = 7, meskipun perbedaannya dengan \(k\) = 3 dan 5 sangat kecil.

5.2 Saran

Pada praktikum Machine Learning berikutnya, disarankan agar praktikan lebih teliti dalam penggunaan sintaks dan interpretasi output di RStudio, terutama dalam menentukan kelas positif pada confusionMatrix() dan mengubah faktor menjadi numerik menggunakan as.numeric(as.character()). Parameter penskalaan sebaiknya dihitung dari data training saja, dan metode penskalaan dipilih dengan memperhatikan skala serta makna setiap variabel. Nilai \(k\) sebaiknya dipilih menggunakan validasi silang pada data training, bukan berdasarkan data testing, agar data testing hanya digunakan untuk evaluasi akhir. Karena FN lebih berbahaya daripada FP, batas keputusan juga dapat diturunkan, misalnya observasi diklasifikasikan ganas walaupun proporsi suara malignant kurang dari 0,5, dengan tetap memperhatikan kenaikan FP. Selain itu, dapat dicoba metrik jarak lain seperti Manhattan atau Mahalanobis untuk mengatasi korelasi antarprediktor, serta set.seed() perlu selalu diberikan sebelum knn() karena hasil voting seri ditentukan secara acak.

DAFTAR PUSTAKA

Altman, D. G., & Bland, J. M. (1994a). Diagnostic tests 1: Sensitivity and specificity. BMJ, 308(6943), 1552. https://doi.org/10.1136/bmj.308.6943.1552

Altman, D. G., & Bland, J. M. (1994b). Diagnostic tests 2: Predictive values. BMJ, 309(6947), 102. https://doi.org/10.1136/bmj.309.6947.102

Bray, F., Laversanne, M., Sung, H., Ferlay, J., Siegel, R. L., Soerjomataram, I., & Jemal, A. (2024). Global cancer statistics 2022: GLOBOCAN estimates of incidence and mortality worldwide for 36 cancers in 185 countries. CA: A Cancer Journal for Clinicians, 74(3), 229–263. https://doi.org/10.3322/caac.21834

Cover, T. M., & Hart, P. E. (1967). Nearest neighbor pattern classification. IEEE Transactions on Information Theory, 13(1), 21–27. https://doi.org/10.1109/TIT.1967.1053964

Cunningham, P., & Delany, S. J. (2021). k-Nearest neighbour classifiers: A tutorial. ACM Computing Surveys, 54(6), 1–25. https://doi.org/10.1145/3459665

Fawcett, T. (2006). An introduction to ROC analysis. Pattern Recognition Letters, 27(8), 861–874. https://doi.org/10.1016/j.patrec.2005.10.010

Fix, E., & Hodges, J. L. (1951). Discriminatory analysis. Nonparametric discrimination: Consistency properties (Report No. 4, Project No. 21-49-004). USAF School of Aviation Medicine.

Han, J., Kamber, M., & Pei, J. (2012). Data mining: Concepts and techniques (3rd ed.). Morgan Kaufmann.

Hastie, T., Tibshirani, R., & Friedman, J. (2009). The elements of statistical learning: Data mining, inference, and prediction (2nd ed.). Springer.

James, G., Witten, D., Hastie, T., & Tibshirani, R. (2021). An introduction to statistical learning: With applications in R (2nd ed.). Springer.

Kuhn, M. (2008). Building predictive models in R using the caret package. Journal of Statistical Software, 28(5), 1–26. https://doi.org/10.18637/jss.v028.i05

Kuhn, M., & Johnson, K. (2013). Applied predictive modeling. Springer.

Laboratorium Matematika FMIPA Universitas Bengkulu. (2026). Modul praktikum machine learning: K-NN (K-nearest neighbor). Universitas Bengkulu.

Leisch, F., & Dimitriadou, E. (2021). mlbench: Machine learning benchmark problems (R package version 2.1-3.1). https://CRAN.R-project.org/package=mlbench

Muraina, I. O. (2022). Ideal dataset splitting ratios in machine learning algorithms: General concerns for data scientists and data analysts. Dalam Proceedings of the 7th International Mardin Artuklu Scientific Research Conference (hlm. 496–504).

Venables, W. N., & Ripley, B. D. (2002). Modern applied statistics with S (4th ed.). Springer.

Wickham, H. (2016). ggplot2: Elegant graphics for data analysis (2nd ed.). Springer.

Wolberg, W. H., & Mangasarian, O. L. (1990). Multisurface method of pattern separation for medical diagnosis applied to breast cytology. Proceedings of the National Academy of Sciences, 87(23), 9193–9196. https://doi.org/10.1073/pnas.87.23.9193