最近鄰居分類(k-nearest neighbors, k-NN)的概念相當簡單:一個資料點在空間中跟那些類別的點最接近,就說它是屬於哪一個類別。這個方法不需要訓練過程,或者說訓練就是把所有資料記起來;而在預測的階段,則是將待測點與其他資料點計算距離,找出最接近的 k 的點,並依據這 k 的點所屬的類別或值進行投票,來做為待測點的預測結果。

我們使用 scikit-learn 的 neighbors.KNeighborsClassifier 來幫我們執行 k-NN 演算法,使用的資料集是 Wine Data Set,該資料集在 scikit-learn 有內建一版,你可以直接透過 import 相關函式來使用,不必自己下載:

import numpy as np
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
 
dataset = load_wine()
print('Data shapes:', dataset.data.shape, dataset.target.shape)
 
X_train, X_test, y_train, y_test = train_test_split(dataset.data, dataset.target)
print('Training data shapes:', X_train.shape, y_train.shape)
print('Test data shapes:', X_test.shape, y_test.shape)
 
model = KNeighborsClassifier(n_neighbors=1)
model.fit(X_train, y_train)
pred = model.predict(X_test)
print('Accuracy (sklearn): {:.2f}%'.format(100*np.mean(pred==y_test)))

pred = []
for p_te in X_test:
    dists = [np.sum((p_tr - p_te) ** 2) ** 0.5 for p_tr in X_train]
    pred.append(y_train[np.argmin(dists)])

pred = np.array(pred)
print('Accuracy (for loop): {:.2f}%'.format(100*np.mean(pred==y_test)))

在上述範例中,由於 train_test_split 是隨機進行,因此每次執行時,準確度可能會有所變化。此外,範例的下半部同時也示範了自行實作最近鄰居分類的參考方式,其中的 n_neighbors 與前半部同樣為 1,距離則是使用 2-norm。

下面對 KNeighborsClassifier 的部分參數進行一些說明,若需要更多細節,可以參考官方文件。