寫在前面:
kNN算法,或者說K最近鄰(kNN,k-NearestNeighbor)分類算法,它是分類技術(shù)中最簡單的方法之一。所謂K最近鄰,就是k個最近的鄰居的意思,說的是每個樣本都可以用它最接近的k個鄰居來代表。
我們來看一個簡單的例子:
????如圖1,有兩類數(shù)據(jù),分別是藍色方塊和紅色三角形,現(xiàn)在,我們在圖正中間有了一個綠色圓圈,并且需要判斷它屬于這兩類中的哪一類。要怎么做呢?
????這個時候我們就用到kNN算法了,假設(shè)取k=3,那么離綠色圓圈最近的3個中有2個是紅色三角形,1個是藍色方塊。紅色三角形所占比例高,為2/3,所以可以把綠色圓圈歸為紅色三角形類。
????但如果取k=5,由于藍色方塊所占比例高,為3/5,所以可以把綠色圓圈歸為藍色方塊類。
????從這個例子不僅可以看出kNN算法的工作原理,而且也能夠看出k取值的重要性。
給出kNN的偽代碼(文字流程)如下:
0)假設(shè)現(xiàn)有已知類別的訓(xùn)練集一份和未知類別的測試數(shù)據(jù)一條;
1)計算訓(xùn)練集中的點與測試數(shù)據(jù)點之間的距離;
2)按照距離遞增次序排序;
3)選取與當(dāng)前點距離最小的k個點;
4)確定前k個點所在類別的出現(xiàn)頻率;
5)返回前k個點出現(xiàn)頻率最高的類別作為當(dāng)前點的預(yù)測分類。
那么,我們結(jié)合實際例子分析下kNN的實現(xiàn):
情景為: 海倫一直使用在線約會網(wǎng)站尋找適合自己的約會對象。盡管約會網(wǎng)站會推薦不同的人選,但她沒有從中找到喜歡的人。經(jīng)過一番總結(jié),她發(fā)現(xiàn)曾交往過三種類型的人:
????①不喜歡的人;
????②魅力一般的人;
????③極具魅力的人。
她現(xiàn)在總結(jié)好的數(shù)據(jù)中(即訓(xùn)練集)包含三種特征:
????①每年獲得的飛行常客里程數(shù)
????②玩視頻游戲所耗時間百分比
????③每周消費的冰淇淋公升數(shù)
她希望根據(jù)現(xiàn)有的數(shù)據(jù)及類型標(biāo)簽來判斷一個陌生男人會被她歸到哪一類。于是,她使用了kNN……
這里先給出數(shù)據(jù)集地址https://github.com/ocAreTheBestLanguage/fileRepository
上圖為數(shù)據(jù)的格式樣本,前三列是特征,最后一列是標(biāo)簽,總共有1000行樣本。
此處考慮到篇幅問題,略去對數(shù)據(jù)進行的預(yù)處理及歸一化處理代碼,假設(shè)我們已經(jīng)獲得了歸一化后的shape為(1000,3)的矩陣dataSet及shape為(1000,)標(biāo)簽數(shù)組labels,且k為要求得的最近鄰居的個數(shù)。并且使用歐式距離公式來計算點與點之間的距離,如distance = √( (x1-x2)2+(y1-y2)2+(z1-z2)2 )。
那么代碼如下:
#dataSet為訓(xùn)練集
#labels為標(biāo)簽集
#inX為要預(yù)測的那條數(shù)據(jù)
#獲取數(shù)據(jù)集的行數(shù)
dataSetRows = dataSet.shape[0]
#用tile()函數(shù)把要預(yù)測那條數(shù)據(jù)重復(fù)擴充到(1000,1) 然后與數(shù)據(jù)集相減并平方
temp = (tile(inX, (dataSetRows, 1)) - dataSet)**2
#求得每一行數(shù)據(jù)的總和并開平方,完成求得歐式距離
distances = temp.sum(axis=1) ** 0.5
#返回從小到大排列的元素下標(biāo)
sortedIndicies = distances.argsort()
#用與計算某類出現(xiàn)的次數(shù)
classCount = {}
#計算類別出現(xiàn)的對應(yīng)次數(shù)
for i in range(k):
label = labels[sortedIndicies[i]]
classCount[label] = classCount.get(label, 0) + 1
#利用類別出現(xiàn)的次數(shù),從大到小排序,其中的參數(shù)itemgetter(1)代表按照第二個域進行排序,即按照第二列進行排序。
sortedClassCount = sorted(classCount.iteritems(),key=operator.itemgetter(1),reverse=True)
#求得最終的預(yù)測類別
finalClass = sortedClassCount[0][0]
寫在最后:
最后簡單評價一下kNN吧,kNN是機器學(xué)習(xí)中可以說是最簡單的算法啦。
kNN的優(yōu)點在于簡單,容易理解,而且無須估計參數(shù),這也意味著它不需要訓(xùn)練這種操作。另外它適合對稀有事件進行分類。
kNN的缺點在于當(dāng)樣本不平衡時,如一個類的樣本容量很大,而其他類樣本容量很小時,有可能導(dǎo)致當(dāng)輸入一個新樣本時,該樣本的K個鄰居中大容量類的樣本占多數(shù)。這就使得運行結(jié)果受到數(shù)量的影響,而偏離了因為相似所以歸為同一類的原則。
謝謝閱讀本文!