K近鄰演算法

無風聽海發表於2022-03-03

一、K近鄰演算法簡介

K近鄰演算法(K-Nearest Neighbor)簡稱KNN演算法,是最簡單的預測模型之一,它沒有多少數學上的假設,也不要求任何複雜的處理,它所要求的只有以下兩點

1.某種距離計算概念

2.彼此接近的點具有相似的性質

即對於一個新樣本,演算法在已有資料中尋找與它最相似的K個資料,或者說“離它最近”的K個資料,如果這K個資料大多數屬於某個類別,則該樣本也屬於這個類別。

KNN演算法只依賴待預測節點附近的少量節點,有意的忽略了資料集中的大量樣本,同時該演算法也不能幫助我們理解事物現象背後的機制和原理;

預測策略通常採用多數表決的投票法;也就是將k個樣本中出現最多的分類作為預測結果;計算公式如下,裡邊的v是樣本的分類標籤,yi是第i個樣本的分類標籤,I是指示函式,如果預測結果屬於某個分類就返回1,否則返回0,則最終取出現次數最多的分類作為預測結果;

\[y = argmax_{v} \sum_{(x_{i},y_{i})\in D_{z}} I(v=y_{i}) \]

相對來說,K近鄰學習演算法沒有顯示的訓練過程,只有收到待測試樣本才進行處理,這是一種典型的基於例項的惰性學習;

只選擇最近的k個鄰居的演算法,很容易受到資料集分佈偏斜的影響,通過不同的k值,最終會覆蓋到不同的樣本,最終也會得到不同的預測結果;

採用資料節點相等的少數服從多數很容易出現群體暴政,從而產生對新樣本分類結果的誤判;我們可以根據距離遠近賦予節點不同的區中,從而提高預測結果的準確性;

距離也有不同的演算法歐氏距離、馬氏距離、海明距離等,不同的演算法會影響對最近的k個節點的選擇,從而最終影響分類結果;

二、影響演算法效能的因素

影響k-近鄰演算法效能的因素有很多,其中比較重要的有四個:k值的選取、特徵資料的歸一化、鄰居距離的度量及分類原則;

k值的選擇

如果k值的選取比較小,則覆蓋的鄰域的訓練樣本比較小,從而導致預測結果對訓練樣本比較敏感,很容易發生過擬合現象;

如果k值的選取比較大,則覆蓋的鄰域的訓練樣本會比較多,分類準確率會提高,但是隨著k值的增大,則樣本攜帶的噪聲就會導致分類錯誤綠上升,所以對於k值的選取過猶不及;

通常可以採用交叉驗證的方式來選擇最優的k值,即對於每一個k值都做若干次交叉驗證,然後計算出他們各自的平均誤差,最後選擇誤差最小的k值使用;

特徵資料歸一化

計算樣本之間的距離,需要考慮不同特徵的取值範圍,不同特徵對距離的計算影響可謂大相徑庭;歸一化是特徵值預處理的常見處理方法,它會把所有的特徵值對映為[0,1]之間;

常用的一種歸一化方法,首先找到它的最大值和最小值,然後按照如下公式計算

\[x^{'} = \frac{x-Min} {Max-Min} \]

鄰居距離的度量

在特徵向量空間中,兩個點之間的距離也是他們之間相似度的度量,計算方式的不同,也會顯著的影響最終得到的最近距離,從而影響分類的結果;

一般情況下,經過歸一化處理之後,可以使用歐式距離或者馬氏距離來計算兩個未知樣本集的相似度方法;在文字分類等非連續變數的分類中,更多的採用馬氏距離來衡量字串之間的編輯距離;

分類原則

k近鄰演算法通常有兩類分類原則,一類是平等投票表決原則,一類是加權投票原則;

三、紅酒資料集情況

接下來我們使用knn演算法對紅酒進行分類;通過一下程式碼,我們可以看到紅酒樣本資料的特徵欄位名稱、分類標籤、樣本資料量等維度的資料;

from sklearn.datasets import  load_wine

wine = load_wine()
print('wine features:')
print(wine.feature_names)
print('wine target names:')
print(wine.target_names)
print('wine data shape:')
print(wine.data.shape)
print('one wine data:')
print(wine.data[0])
print('wine target:')
print(wine.target)

wine features:
['alcohol', 'malic_acid', 'ash', 'alcalinity_of_ash', 'magnesium', 'total_phenols', 'flavanoids', 'nonflavanoid_phenols', 'proanthocyanins', 'color_intensity', 'hue', 'od280/od315_of_diluted_wines', 'proline']
wine target names:
['class_0' 'class_1' 'class_2']
wine data shape:
(178, 13)
one wine data:
[1.423e+01 1.710e+00 2.430e+00 1.560e+01 1.270e+02 2.800e+00 3.060e+00
 2.800e-01 2.290e+00 5.640e+00 1.040e+00 3.920e+00 1.065e+03]
wine target:
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2]

四、使用knn進行紅酒分類

from sklearn.datasets import  load_wine
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score
from sklearn.preprocessing import MinMaxScaler

wine = load_wine()
X = wine.data
y = wine.target

# 歸一化
scaler = MinMaxScaler()
scaler.fit(X)
X = scaler.transform(X)

X_train,X_test,y_train,y_test = train_test_split(X,y, test_size=0.3, random_state=123)

knn = KNeighborsClassifier(n_neighbors=3)
knn.fit(X, y)
y_predict_train = knn.predict(X_train)
y_predict_test = knn.predict(X_test)

acc_train = accuracy_score(y_train, y_predict_train)
acc_test = accuracy_score(y_test, y_predict_test)
print("train set accuracy {:.2f}".format(100*acc_train))
print("test set accuracy {:.2f}".format(100*acc_test))


train set accuracy 96.77
test set accuracy 98.15

相關文章