Algoritma K-Nearest Neighbors (KNN) dengan Python Scikit-Learn
Konsep KNN
K-Nearest Neighbors (KNN) adalah metode klasifikasi yang populer dalam bidang machine learning. Konsep dasar dari algoritma KNN adalah mencari k-nearest neighbors atau k tetangga terdekat dari suatu objek berdasarkan metrik jarak tertentu. KNN umumnya digunakan untuk pemodelan klasifikasi namun dapat juga digunakan untuk pemodelan regresi.
Dalam model klasifikasi, algoritma KNN menghitung jarak antara objek yang akan diklasifikasikan dengan dataset yang sudah ada, dan memilih k tetangga terdekat berdasarkan jarak tersebut. Setelah itu, algoritma ini melakukan voting atau pemungutan suara untuk menentukan kelas mayoritas dari tetangga terdekat, dan mengklasifikasikan objek yang akan diklasifikasikan berdasarkan mayoritas kelas tersebut.
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, 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 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.
KNN dengan Scikit-Learn
Data yang digunakan untuk pemodelan KNN ini adalah dataset wine quality
dengan versi yang sudah dikelompokkan menjadi 3 kelas.Dataset terdiri 1143 amatan dengan 11 variabel input/fitur dan 1 kolom sebagai label (3 kelas kualitas wine).
Python
import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns data = pd.read_csv("https://raw.githubusercontent.com/sainsdataid/dataset/main/wine-quality-multiclass.csv") data
Output
Eksplorasi Data
Python
grup = data.groupby('quality').agg({"quality": "count"}) grup_prop = grup / len(data) print(grup) print(grup_prop)
Output
quality quality HIGH 159 LOW 522 STANDARD 462 quality quality HIGH 0.139108 LOW 0.456693 STANDARD 0.404199
Dari tabulasi di atas, dapat dilihat jumlah data untuk masing-masing kelas yaitu HIGH
sebanyak 159 amatan, LOW
sebanyak 522 amatan dan STANDARD
sebanyak 462 amatan. Secara proporsi, kelas LOW
dan STANDARD
memiliki proporsi yang relatif mirip, sedangkan untuk kelas HIGH
jumlahnya lebih sedikit yaitu sekitar 13,9 persen saja. Adanya ketidakseimbangan ini, kemungkinan akan mempengaruhi kinerja model, khususnya saat memprediksi data yang seharusnya masuk kelas HIGH
.
Python
summary = data.groupby('quality').mean().transpose() print(summary)
Output
# OUTPUT quality HIGH LOW STANDARD fixed acidity 8.846541 8.142146 8.317749 volatile acidity 0.395314 0.596121 0.504957 citric acid 0.391195 0.235096 0.263680 residual sugar 2.748428 2.543582 2.444805 chlorides 0.074711 0.092117 0.085281 free sulfur dioxide 14.188679 16.404215 15.215368 total sulfur dioxide 36.672956 54.016284 39.941558 density 0.996019 0.997054 0.996610 pH 3.282453 3.308410 3.323788 sulphates 0.745849 0.614195 0.676537 alcohol 11.528407 9.922510 10.655339
Kita juga dapat melihat bagaimana karakteristik masing-masing kelas berdasarkan nilai fitur-fiturnya. Misalkan rata-rata kadar alcohol
pada kelas HIGH
terlihat lebih tinggi dibandingkan kelas STANDARD
dan LOW
. Sebaliknya rata-rata kadar total.sulfur.dioxide
pada kelas HIGH
jauh lebih rendah dibandingkan dua kelas lainnya. Contoh lainnya pada pH
terlihat ketiga kelas hampir tidak memiliki perbedaan. Artinya kemungkinan fitur ini tidak memiliki kontribusi besar untuk membedakan ketiga kelas.
Jika diperlukan, dapat pula dibuat plot sebarannya untuk masing-masing kelas untuk melihat perbandingan secara visual. Misalkan pada contoh di bawah ini kita menyajikan boxplot untuk sebaran nilai alcohol
dan pH
menurut kelasnya. Dari visualisasi tersebut terlihat bahwa cenderung terdapat perbedaan nilai alcohol
dimana nilai pada kelas HIGH
relatif lebih tinggi dibandingkaan kelas STANDARD
, begitu juga untuk kelas LOW
dimana nilainya relatif lebih rendah dibandingkan kelas lainnya. Sementara itu, pada boxplot nilai pH
sebaran nilainya terlihat tidak terlalu berbeda antar ketiga kelas, hal ini bisa menjadi indikasi kemungkinan fitur ini tidak memiliki pengaruh yang besar dalam menentukan kelas data.
Python
# Membuat plot boxplot untuk kolom alcohol plt.figure(figsize=(8, 4)) sns.boxplot(x='quality', y='alcohol', hue='quality', data=data) plt.title('Sebaran nilai alcohol Menurut quality') plt.show() # Membuat plot boxplot untuk kolom pH plt.figure(figsize=(8, 4)) sns.boxplot(x='quality', y='pH', hue='quality', data=data) plt.title('Sebaran nilai pH Menurut quality') plt.show()
Output
Data Training dan Testing
Langkah selanjutnya adalah membagi data untuk traning dan testing. Data traning digunakan sebagai dasar pelatihan model, sementara data testing untuk evaluasi performa model. Pembagian data kita lakukan dengan fungsi train_test_split
yang tersedia pada pustaka sklearn.model_selection
.
Python
from sklearn.model_selection import train_test_split # membuat data fitur/input X = data.drop('quality', axis=1) # membuat data output y = data['quality'] # membagi data traning 70% dan data testing 30% X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
Pembagian data kita atur dengan proporsi data training 70% dan data testing 30%. Parameter random_state
dapat di-set berapa saja. Dengan nilai random_state
yang sama, maka pembagian data yang sama dapat direproduksi ulang. Setiap kali menjalankan ulang fungsi rain_test_split
maka pembagian data akan selalu sama bahkan jika dilakukan pada perangkat manapun.
Features Scaling
KNN merupakan algoritma 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 standardize, Proses standardize akan membuat setiap fitur memiliki nilai rata-rata 0 dan standar deviasi 1.
Standardize dapat dilakukan secara manual, namun untuk memudahkan, kita dapat menggunakan fungsi StandarScaler
dari scikit-learn
.
Python
from sklearn.preprocessing import StandardScaler scaler = StandardScaler() # Standardisasi skala data fitur scaled_X_train = scaler.fit_transform(X_train) scaled_X_test = scaler.transform(X_test)
Membuat Model KNN
Model KNN dapat kita bangun menggunakan fungsi KNeighborsClassifier
pada pustaka sklearn.neighbors
. Fungsi ini memiliki beberapa parameter yang bisa kita atur. beberapa parameter yang terpenting yaitu jumlah tetangga (n_neighbors
, default=5
), metrik jarak (metric
, default='minkowski'
), bobot setiap titik (weight
, default='uniform'
: semua k tetangga memiliki bobot sama) dan parameter lainnya.
Pada bagian ini, kita akan membuat model KNN dengan mengatur nilai-nilai parameter menggunakan nilai defaultnya.
Setelah mendapatkan model KNN berdasarkan data training, perlu dilakukan evaluasi terhadap model untuk memprediksi output dari data testing. Metrik yang dapat digunakan untuk masalah klasifikasi adalah accuracy, balanced accuracy, F1 Score (khusus klasifikasi biner) dan sebagainya. Dalam model klasifikasi, juga dapat dilihat confussion matrix untuk membandingkan hasil prediksi terhadap klasifikasi yang sebenarnya.
Python
from sklearn.neighbors import KNeighborsClassifier from sklearn.metrics import confusion_matrix, classification_report # help(KNeighborsClassifier) knn_model = KNeighborsClassifier(n_neighbors=5) # Membuat model berdasarkan data training knn_model.fit(scaled_X_train, y_train) # Memprediksi output dari data testing y_pred = knn_model.predict(scaled_X_test) # menampilkan confusion matriks print(confusion_matrix(y_test, y_pred)) # menampilkan nilai akurasi dan metrik lainnya print(classification_report(y_test, y_pred))
Output
[[ 17 6 22] [ 8 106 38] [ 21 57 68]] precision recall f1-score support HIGH 0.37 0.38 0.37 45 LOW 0.63 0.70 0.66 152 STANDARD 0.53 0.47 0.50 146 accuracy 0.56 343 macro avg 0.51 0.51 0.51 343 weighted avg 0.55 0.56 0.55 343
Berdasarkan hasil di atas, dengan mengunakan 5 tetangga diperoleh model dengan akurasi yang cukup rendah yaitu 0,56. Seperti yang disampaikan sebelumnya kinerja model sangat buruk ketika memprediksi data pada kelas HIGH
. Dengan nilai presisi hanya 0,37
, model hanya benar memprediksi 17 dari 46 data kelas HIGH
(8 salah prediksi sebagai kelas LOW
dan 21 sebagai kelas STANDARD
). Ini artinya lebih dari setengahnya salah diprediksi yang menunjukkan hasil yang buruk.
Untuk kelas lainnya nilai presisi juga beragam, yaitu 0,63
untuk kelas LOW
dan 0,53
untuk kelas STANDARD
. Hasil ini tentunya juga tidak bisa disebut baik. Pada bagian selanjutnya, kita akan mencoba melakukan pengaturan nilai k serta hiperparameter lainnya, untuk mencari model dengan kinerja yang lebih baik.
Tuning Hiperparameter
Model sebelumnya dengan nilai k=5
menghasilkan kinerja yang kurang memuaskan. Hal ini tidak terlepas dari kondisi data yang tidak seimbang. Untuk mencari model yang lebih baik kita dapat menggunakan fungsi GridSearchCV
. Terdapat beberapa parameter yang dapat diatur pada fungsi KNeighborsClassifier
. Namun, pada contoh ini hanya dua yang akan diatur yaitu n_neighbors
yang menunjukkan nilai k atau banyaknya tetangga, serta weights
untuk mengatur bobot masing-masing kelas. Pengaturan bobot ini memungkinkan kita untuk memperbesar bobot kelas HIGH
dengan harapan meningkatkan kinerja model khususnya pada kelas tersebut.
Penentuan model terbaik dapat menggunakan berbagai metrik nilai seperti yang disampaikan sebelumnya. Kita akan melakukan iterasi untuk berbagai nilai k dan mencari model yang memberikan skor terbaik. Pada contoh ini akan mengunakan metrik akurasi dimana semakin tinggi nilai akurasi maka performa model semakin baik.
Python
import numpy as np from sklearn.neighbors import KNeighborsClassifier from sklearn.metrics import confusion_matrix, classification_report from sklearn.model_selection import GridSearchCV param_grid = { 'n_neighbors': np.arange(1, 20, 1), # 1, 2, 3, ....19 'weights' : ['uniform', 'distance'] } model_knn = KNeighborsClassifier() model_knn_cv = GridSearchCV(model_knn, param_grid=param_grid, scoring="accuracy" , cv=5, refit=True, n_jobs=4) # fitting model model_knn_cv.fit(scaled_X_train, y_train) # menampilkan pengaturan parameter da skor terbaik print("Best Param:", model_knn_cv.best_params_) print("best Score:", model_knn_cv.best_score_) # membuat prediksi data uji y_pred = model_knn_cv.predict(scaled_X_test) print(y_pred) print(confusion_matrix(y_test, y_pred)) print("Accuracy :", accuracy_score(y_test, y_pred)) print(classification_report(y_test, y_pred))
Output
# Output Best Param: {'n_neighbors': 17, 'weights': 'distance'} best Score: 0.6625 ['LOW' 'STANDARD' 'LOW', ..., 'STANDARD' 'LOW' 'LOW'] [[ 33 2 10] [ 3 116 33] [ 10 46 90]] Accuracy : 0.6967930029154519 precision recall f1-score support HIGH 0.72 0.73 0.73 45 LOW 0.71 0.76 0.73 152 STANDARD 0.68 0.62 0.65 146 accuracy 0.70 343 macro avg 0.70 0.70 0.70 343 weighted avg 0.70 0.70 0.70 343
Dari hasil di atas kita peroleh model dengan nilai k (n_neighbors
) sebanyak 17
serta weights
menggunakan distance
dengan nilai akurasi saat pelatihan sebesar 0,6625
. Saat model digunakan untuk memprediksi data uji, diperoleh hasil yang baik di mana akurasi model mencapai 0,7
. Nilai ini jauh lebih tinggi dibandingkan model sebelumnya dengan akurasi hanya sebesar 0,56
. Nilai presisi dan recall juga menunjukkan hasil yang baik. Pada kelas HIGH
misalnya, nilai presisi mencapai 0,72
, dari 46 data kelas HIGH
sebanyak 33 diprediksi dengan tepat dan sisanya (3 diprediksi sebagai kelas LOW
dan 10 sebagai kelas STANDARD
).
Hasil ini mungkin masih dapat ditingkatkan dengan pengaturan lebih lanjut hiperparameter model. Silahkan untuk mencoba kombinasi dan pengaturan lainnya.
Prediksi Data Baru
Setelah memperoleh model terbaik, maka kita dapat melakukan prediksi pada data baru. Sebagai contoh, terdapat data 2 wine baru dan kita ingin mengetahui perkiraan kualitasnya. Langkah untuk memprediksi data tersebut adalah sebagai berikut:
Python
# contoh data baru new_data = pd.DataFrame({'fixed acidity' : [8.25, 7.94], 'volatile acidity' : [0.46, 0.48], 'citric acid' : [0.32, 0.28], 'residual sugar' : [2.6, 2.6], 'chlorides': [0.065, 0.081], 'free sulfur dioxide': [14.7, 14.7], 'total sulfur dioxide': [38.24, 38.85], 'density': [0.96, 0.98], 'pH': [3.4, 3.4], 'sulphates': [0.72, 0.70], 'alcohol': [11.4, 11.0] }) print(new_data.transpose()) # data baru perlu di scaling dengan scaler yang digunakan saat pelatihan scaled_new_data = scaler.transform(new_data) # prediksi kelas data prediksi = knn_model.predict(scaled_new_data) print(f"\nKualitas: {prediksi}")
Output
# OUTPUT fixed acidity 8.250 7.940 volatile acidity 0.460 0.480 citric acid 0.320 0.280 residual sugar 2.600 2.600 chlorides 0.065 0.081 free sulfur dioxide 14.700 14.700 total sulfur dioxide 38.240 38.850 density 0.960 0.980 pH 3.400 3.400 sulphates 0.720 0.700 alcohol 11.400 11.000 Kualitas: ['HIGH' 'STANDARD']
Berdasarkan hasil di atas, kita memprediksi bahwa wine pertama memiliki kualitas HIGH
dan untuk wine kedua masuk kelas STANDARD
.
Selamat mencoba dengan data lainnya!
Referensi
- James, G., Witten, D., Hastie, T., Tibshirani, R. 2014, An Introduction to Statistical Learning with Applications in R, Springer.
- sklearn.neighbors.KNeighborsClassifier — scikit-learn 1.5 documentation
Tulisan Lainnya