機器學習演算法-K最近鄰從原理到實現(Python)
本來這篇文章是5月份寫的,今天修改了一下內容,就成今天發表的了,CSDN這是出BUG了還是什麼改規則了。。。
引文:決策樹和基於規則的分類器都是積極學習方法(eager learner)的例子,因為一旦訓練資料可用,他們就開始學習從輸入屬性到類標號的對映模型。一個相反的策略是推遲對訓練資料的建模,直到需要分類測試樣例時再進行。採用這種策略的技術被稱為消極學習法(lazy learner)。最近鄰分類器就是這樣的一種方法。
注:KNN既可以用於分類,也可以用於迴歸。
1.K最近鄰分類器原理
首先給出一張圖,根據這張圖來理解最近鄰分類器,如下:
根據上圖所示,有兩類不同的樣本資料,分別用藍色的小正方形
我們常說,物以類聚,人以群分,判別一個人是一個什麼樣品質特徵的人,常常可以從他or她身邊的朋友入手,所謂觀其友,而識其人。我們不是要判別上圖中那個綠色的圓是屬於哪一類資料麼,好說,從它的鄰居下手。但一次性看多少個鄰居呢?從上圖中,你還能看到:
- 如果K=3,綠色圓點的最近的3個鄰居是2個紅色小三角形和1個藍色小正方形,少數從屬於多數,基於統計的方法,判定綠色的這個待分類點屬於紅色的三角形一類。
- 如果K=5,綠色圓點的最近的5個鄰居是2個紅色三角形和3個藍色的正方形,還是少數從屬於多數,基於統計的方法,判定綠色的這個待分類點屬於藍色的正方形一類。
於此我們看到,當無法判定當前待分類點是從屬於已知分類中的哪一類時,我們可以依據統計學的理論看它所處的位置特徵,衡量它周圍鄰居的權重,而把它歸為(或分配)到權重更大的那一類。這就是K近鄰演算法的核心思想。其關鍵還在於K值的選取,所以應當謹慎。
KNN演算法中,所選擇的鄰居都是已經正確分類的物件。該方法在定類決策上只依據最鄰近的一個或者幾個樣本的類別來決定待分樣本所屬的類別。
KNN 演算法本身簡單有效,它是一種 lazy-learning 演算法,分類器不需要使用訓練集進行訓練,訓練時間複雜度為0。KNN 分類的計算複雜度和訓練集中的文件數目成正比,也就是說,如果訓練集中文件總數為 n,那麼 KNN 的分類時間複雜度為O(n)。
前面的例子中強調了選擇合適的K值的重要性。如果太小,則最近鄰分類器容易受到訓練資料的噪聲而產生的過分擬合的影響;相反,如果K太大,最近分類器可能會誤會分類測試樣例,因為最近鄰列表中可能包含遠離其近鄰的資料點。(如下圖所示)
K較大時的最近鄰分類
可見,K值的選取還是非常關鍵。
2.演算法
演算法描述
k近鄰演算法簡單、直觀:給定一個訓練資料集(包括類別標籤),對新的輸入例項,在訓練資料集中找到與該例項最鄰近的k個例項,這k個例項的多數屬於某個類,就把該輸入例項分為這個類。下面是knn的演算法步驟。
演算法步驟如下所示:
對每個測試樣例
特徵空間中兩個例項點的距離是兩個例項相似程度的反映。
一旦得到最近鄰列表,測試樣例就可以根據最近鄰的多數類進行分類,使用多數表決方法。
K值選擇
k值對模型的預測有著直接的影響,如果k值過小,預測結果對鄰近的例項點非常敏感。如果鄰近的例項恰巧是噪聲資料,預測就會出錯。也就是說,k值越小就意味著整個模型就變得越複雜,越容易發生過擬合。
相反,如果k值越大,有點是可以減少模型的預測誤差,缺點是學習的近似誤差會增大。會使得距離例項點較遠的點也起作用,致使預測發生錯誤。同時,k值的增大意味著模型變得越來越簡單。如果k=N,那麼無論輸入例項是什麼,都將簡單的把它預測為樣本中最多的一類。這顯然實不可取的。
在實際建模應用中,k值一般取一個較小的數值,通常採用cross-validation的方法來選擇最優的k值。
3.K最鄰近演算法實現(Python)
KNN.py(程式碼來源《機器學習實戰》一書)
from numpy import *
import operator
class KNN:
def createDataset(self):
group = array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
labels = ['A','A','B','B']
return group,labels
def KnnClassify(self,testX,trainX,labels,K):
[N,M]=trainX.shape
#calculate the distance between testX and other training samples
difference = tile(testX,(N,1)) - trainX # tile for array and repeat for matrix in Python, == repmat in Matlab
difference = difference ** 2 # take pow(difference,2)
distance = difference.sum(1) # take the sum of difference from all dimensions
distance = distance ** 0.5
sortdiffidx = distance.argsort()
# find the k nearest neighbours
vote = {} #create the dictionary
for i in range(K):
ith_label = labels[sortdiffidx[i]];
vote[ith_label] = vote.get(ith_label,0)+1 #get(ith_label,0) : if dictionary 'vote' exist key 'ith_label', return vote[ith_label]; else return 0
sortedvote = sorted(vote.iteritems(),key = lambda x:x[1], reverse = True)
# 'key = lambda x: x[1]' can be substituted by operator.itemgetter(1)
return sortedvote[0][0]
k = KNN() #create KNN object
group,labels = k.createDataset()
cls = k.KnnClassify([0,0],group,labels,3)
print cls
執行:
1. 在Python Shell 中可以執行KNN.py
>>>import os
>>>os.chdir("/home/liudiwei/code/data_miningKNN/")
>>>execfile("KNN.py")
輸出:B
(B表示類別)
2.或者terminal中直接執行
$ python KNN.py
3.也可以不在KNN.py中寫輸出,而選擇在Shell中獲得結果,i.e.,
>>>import KNN
>>> KNN.k.KnnClassify([0,0],KNN.group,KNN.labels,3)
References
附件(兩張自己的計算過程圖):
圖1 KNN演算法核心部分
圖2 KNN計算過程
說明:上述圖片僅供參考,看不懂就自己測試一組資料如[0,1]慢慢推導一下吧