[機器學習] ——KNN K-最鄰近算法


KNN分類算法,是理論上比較成熟的方法,也是最簡單的機器學習算法之一。

該方法的思路是:如果一個樣本在特征空間中的k個最相似(即特征空間中最鄰近)的樣本中的大多數屬於某一個類別,則該樣本也屬於這個類別。

KNN算法中,所選擇的鄰居都是已經正確分類的對象。該方法在定類決策上只依據最鄰近的一個或者幾個樣本的類別來決定待分樣本所屬的類別。

 

一個對於KNN算法解釋最清楚的圖如下所示:

 

 

 

 

 

 

 

藍方塊和紅三角均是已有分類數據,當前的任務是將綠色圓塊進行分類判斷,判斷是屬於藍方塊或者紅三角。

當然這里的分類還跟K值是有關的:

如果K=3(實線圈),紅三角占比2/3,則判斷為紅三角;

如果K=5(虛線圈),藍方塊占比3/5,則判斷為藍方塊。

 

由此可以看出knn算法實際上根本就不用進行訓練,而是直接進行計算的,訓練時間為0,計算時間為訓練集規模n。

knn算法的基本要素大致有3個:

  1、K 值的選擇

  2、距離的度量

  3、分類決策規則


使用方式:(轉載)

  1. K 值會對算法的結果產生重大影響。K值較小意味着只有與輸入實例較近的訓練實例才會對預測結果起作用,容易發生過擬合;如果 K 值較大,優點是可以減少學習的估計誤差,缺點是學習的近似誤差增大,這時與輸入實例較遠的訓練實例也會對預測起作用,是預測發生錯誤。在實際應用中,K 值一般選擇一個較小的數值,通常采用交叉驗證的方法來選擇最有的 K 值。隨着訓練實例數目趨向於無窮和 K=1 時,誤差率不會超過貝葉斯誤差率的2倍,如果K也趨向於無窮,則誤差率趨向於貝葉斯誤差率。
  2. 算法中的分類決策規則往往是多數表決,即由輸入實例的 K 個最臨近的訓練實例中的多數類決定輸入實例的類別
  3. 距離度量一般采用 Lp 距離,當p=2時,即為歐氏距離,在度量之前,應該將每個屬性的值規范化,這樣有助於防止具有較大初始值域的屬性比具有較小初始值域的屬性的權重過大。

 

knn算法在分類時主要的不足是,當樣本不平衡時,如果一個類的樣本容量很大,而其他類樣本容量很小時,有可能導致當輸入一個新樣本時,該樣本的 K 個鄰居中大容量類的樣本占多數。

 

算法偽代碼:

 1 搜索k近鄰的算法:kNN(A[n],k)
 2 
 3 #輸入:A[n]為N個訓練樣本在空間中的坐標,k為近鄰數
 4 #輸出:x所屬的類別
 5 
 6 取A[1]~A[k]作為x的初始近鄰,計算與測試樣本x間的歐式距離d(x,A[i]),i=1,2,.....,k;
 7 按d(x,A[i])升序排序;
 8 取最遠樣本距離D = max{d(x,a[j]) | j=1,2,...,k};
 9 
10 for(i=k+1;i<=n;i++)#繼續計算剩下的n-k個數據的歐氏距離
11       計算a[i]與x間的距離d(x,A[i]);
12       if(d(x,A[i]))<D
13                then 用A[i]代替最遠樣本#將后面計算的數據直接進行插入即可
14  
15  最后的K個數據是有大小順序的,再進行K個樣本的統計即可
16  計算前k個樣本A[i]),i=1,2,..,k所屬類別的概率;
17  具有最大概率的類別即為樣本x的類

 

python 函數:

 1 #knn-k-最臨近算法
 2 #inX為待分類向量,dataSet為訓練數據集
 3 #labels為訓練集對應分類,k最鄰近算法
 4 def classify0(inX, dataSet, labels, k):
 5     dataSetSize = dataSet.shape[0]#獲得dataSet的行數
 6     
 7     diffMat = np.tile(inX, (dataSetSize,1)) - dataSet#對應的差值
 8     sqDiffMat = diffMat**2                           #差的平方
 9     sqDistances = sqDiffMat.sum(axis=1)              #差的平方的和
10     distances = sqDistances**0.5                     #差的平方的和的平方根
11     #計算待分類向量與每一個訓練數據集的歐氏距離   
12     
13     sortedDistIndicies = distances.argsort() #排序后,統計前面K個數據的分類情況
14     
15     classCount={}#字典
16     for i in range(k):
17         voteIlabel = labels[sortedDistIndicies[i]]#labels得是字典才可以如此
18         classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
19         
20     sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)#再次排序
21     
22     return sortedClassCount[0][0]#第一個就是最多的類別

 

最后針對於K值的選取,做最后的總結:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM