1、模型原理
(一)原理
1、原理:是一種常用的監督學習方法,給定測試樣本,基于某種距離度量找出訓練集中與其最靠近的k個訓練樣本,然后基于這k個“鄰居”的信息來進行預測。也有無監督的最近鄰,暫不討論。
2、判定方法主要有兩種:
(1)在分類任務中的可使用“投票法”,即選擇這k個樣本中出現最多的類別標記作為預測結果;
(2)在回歸任務中可使用“平均法”,即將這k個樣本的標記平均值作為預測結果。
(3)還可以根據距離遠近,對樣本進行加權,實現加權平均或加權投票。
(二)注意點:
1、距離度量方法不同,找到的“近鄰”也可能有顯著區別,進而導致分類結果不同。通常是用歐式距離,即平方和開根號。
2、k在其中是一個相當重要的參數,k取值不同時,分類結果會有顯著不同。
3、
(三)相關概念
1、“維度災難”,如果樣本的屬性維度過多,在這種高維情況下,會出現數據樣本稀疏(不密集,太過分散),距離計算困難等問題,這是所有機器學習方法共同面對的問題,被稱為維度災難。
2、由于這種情況,就需要進行降維。在低維空間中保持樣本點間的距離不變,最簡單的是對原始的高維空間進行線性變換,主成分分析就是最常見的一種線性降維方法。
有時,需要非線性映射才能找到恰當的低維嵌入,就會采用比如“核技巧”等非線性降維方法。
這里引申出來了“主成分分析”方法,可以在下面做補充。
(四)Python實現步驟
(1)計算已知類別數據集中的每個點依次執行以下操作;
(2)按照距離遞增次序排序(越來越大);
(3)選取與當前點距離最小的k個點;
(4)確定前k個點所在類別的出現頻率;
(5)返回前k個點出現頻率最高的類別作為當前點的預測分類
最近鄰算法,是基于輸入樣本的,它和其他算法不一樣,最近鄰不會試圖去構造一個泛化的模型(即,它的思路不是去擬合出一個含有各種參數的函數,然后把新的數據帶入就可以得到新的結果),而只是去簡單的使用輸入訓練集的所有數據,通過測算距離,來實現分類或回歸。
分為KNN分類(KNeighborsClassifier)和KNN(KNeighborsRegressor)回歸兩種,一種是預測屬性(離散值),一種是預測數值(連續值)。
與它對應的還有,通過設置半徑R來進行分類和回歸的,RadiusNeighborsClassifier和RadiusNeighborsRegressor。當用戶確定了一個半徑之后,這些在半徑之內的點都會被考慮。
當我們需要訓練的數據不那么規范的時候RadiusNeighborsClassifier (RN)會是一個更好的選擇,對于一些高維空間,RN的效率會受到影響,這也是一種“維度之殤”了吧。
2、Python3中sklearn-KNN的代碼實現
第一,sklearn中的KNN包源代碼(未查到,以后補充)
第二,sklearn中的KNN包,有幾個可調參數,及每個參數代表的意義
KNeighborsClassifier( n_neighbors=5, weights=’uniform’, algorithm=’auto’, leaf_size=30, p=2, metric=’minkowski’, metric_params=None, n_jobs=1, **kwargs )
n_neighbors,即選擇k值,較大的k值可以容忍較多的噪聲,但是會使得分類的結果變的不那么精確;但樣本不平衡時,一個類樣本容量很大,其他樣本容量很小,導致輸入新樣本時,該樣本鄰近中大樣本占多數,因此可以采取權值的方法(和樣本距離小的鄰近權值大)來改進,減少k值選擇對結果的影響;可以通過循環來嘗試不同的k值的效果。
weights,即權重設置,‘uniform’和‘distance’,對每個點賦予同樣的權重,或者根據距離遠近,賦予不同的權重(距離越遠權重越小)。
algorithm,即搜索最近鄰算法的選擇,包括ball_tree、kd_tree、brute和auto。
brute代表Brute Force算法,就是一個最原始(蠻力)鄰居搜索做法,Brute Force在尋找鄰居時,會把輸入的點同所有樣本中的點做一個距離計算,然后再排序選擇最近的點。
kd_tree代表KD樹算法,為了解決BF算法效率低下的問題,人們提出了很多樹形結構的算法,樹形結構的主要貢獻在于,它們一般通過事先的合理組織,降低了我們搜索中的開銷,也就是使用樹形結構的算法,我們在搜索時可以不用每個樣本都去計算距離了,這無疑降低了很多的開銷。在不太高的維度(小于20)下,KD樹的效果是很不錯的,不過當維度走向更高時,KD樹的效率也會隨之下降,這也呼應了我們之前提到的“維度之殤”的問題。
ball_tree代表Ball Tree算法,KD-Tree是為了解決Brute Force的效率問題,那么Ball-Tree也就是為了解決KD-Tree在高維情況下的效率不佳的另一個做法了,Ball樹在構建的時候,比起KD樹要復雜許多,不過在最后的搜索過程中,其表現就會非常好。
三者的選取:樣本≤30,用BF;樣本較大,但維度≤20,用KD_tree;維度更多的,用ball tree。
參考:知乎回答:KDtree和Ball Tree的區別
默認值是auto,在auto下,將會從你給定的測試數據當中選擇最終性能最好的哪一個算法。leaf_size,設置一個數值,什么時候切換到BF暴力求解,默認是30。
metric ,用于樹的距離度量。默認'minkowski與P = 2(即歐氏度量)。
第三,KNN的基本操作
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors=6) #設置knn中的參數,并賦予某變量
knn.fit(x,y) #導入訓練集,進行模型訓練,x是數據,y是標簽
y_pred = knn.predict(X_new) #帶入新樣本進行分類預測
如何判斷準確率?那只能是把有標簽的數據劃分為訓練集、測試集,然后看它預測的準確率。
from sklearn.model_selection import train_test_split #調用了sklearn中進行測試集和訓練集分類的函數
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=42,stratify=y)
knn.score(X_test,y_test) # .score,就是測試準確度用的
具體的用法如下:
fit(x,y) #導入數據
get_params([deep]) #獲取此估算器的參數
kneighbors([X, n_neighbors, return_distance]) #找到一個點的n個鄰居,并返回距離值
kneighbors_graph([X, n_neighbors, mode]) # 計算X中的點的k-鄰居的(加權)圖
predict(X) #預測提供的數據的分類標簽
predict_proba(X) #返回測試數據X的概率估計。
score(X, y[, sample_weight]) #返回給定測試數據上的平均精確度
set_params(**params) #設置此估算器的參數
取不同k值時,計算準確度
#取不同k值的效率圖:
#創建一個數組儲存訓練和測試數據的精確度
neighbors = np.arange(1, 9)
train_accuracy = np.empty(len(neighbors))
test_accuracy = np.empty(len(neighbors))
# 循環對k進行賦值
for i, k in enumerate(neighbors):
# Setup a k-NN Classifier with k neighbors: knn
knn = KNeighborsClassifier(n_neighbors=k)
# Fit the classifier to the training data
knn.fit(X_train,y_train)
#計算訓練集的準確度
train_accuracy[i] = knn.score(X_train, y_train)
#計算測試集的準確度
test_accuracy[i] = knn.score(X_test, y_test)
用一個循環對
一個簡單的小例子
import numpy as np
from sklearn import neighbors
knn = neighbors.KNeighborsClassifier() #取得knn分類器
data = np.array([[3,104],[2,100],[1,81],[101,10],[99,5],[98,2]]) #data對應著打斗次數和接吻次數
labels = np.array([1,1,1,2,2,2]) #labels則是對應Romance和Action
knn.fit(data,labels) #導入數據進行訓練
print(knn.predict([18,90]))
一點注意
拿《機器學習實戰》中第二章KNN部分的約會網站數據進行了測試,發現雖然直接用的是結果類別標簽數據‘largeDoses’、‘smallDoses’、‘didntLike’,未進行類別變量的轉換,但在模型預測時,可以正確執行預測,結果直接為‘didntLike’等。
3、參考資料
劉建平博客中關于KNN的部分:
K近鄰法(KNN)原理小結
scikit-learn K近鄰法類庫使用小結
以及ML:Scikit-Learn 學習筆記--- Nearest Neighbors 最近鄰 1-3篇
參考的兩篇帖子,NumPy 和 sklearn入門,以及 ML神器:sklearn的快速使用。
里面提到的幾個點很好,比如為什么不用Python自帶的數組list,而使用Numpy的array。
比如,sklearn中各個算法有統一的API接口,各個算法的一般實現流程是:
step1. 數據加載和預處理
step2. 定義分類器, 比如: lr_model = LogisticRegression()
step3. 使用訓練集訓練模型 : lr_model.fit(X,Y)
step4. 使用訓練好的模型進行預測: y_pred = lr_model.predict(X_test)
step5. 對模型進行性能評估:lr_model.score(X_test, y_test)
引申問題
1、計算樣本間的差異有多大,也就是樣本間距離。涉及到如何衡量距離。
2、排序問題,最經典的算法問題了。
這應該都有專門的代碼。