機器學習-KNN(最近鄰)詳解

  1. K-近鄰算法原理
    K最近鄰(kNN,k-NearestNeighbor)分類算法,見名思意:找到最近的k個鄰居(樣本),在前k個樣本中選擇頻率最高的類別作爲預測類別。
    下面舉個例子,圖解一下大家就會顯而易見了,如下圖:
    在這裏插入圖片描述
    e.g:下圖中,綠色圓要被決定賦予哪個類,是紅色三角形還是藍色四方形?如果k=3,由於紅色三角形所佔比例爲2/3,綠色圓將被賦予紅色三角形那個類,如果k=5,由於藍色四方形比例爲3/5,因此綠色圓被賦予藍色四方形類。
    在這裏插入圖片描述
    我們的目的是要預測某個學生在數學課上的成績。。。
    先來說明幾個基本概念:圖中每個點代表一個樣本(在這裏是指一個學生),橫縱座標代表了特徵(到課率,作業質量),不同的形狀代表了類別(即:紅色代表A(優秀),綠色代表D(不及格))。我們現在看(10,20)這個點,它就代表着:在數學課上,某個學生到課率是10%,交作業質量是20分,最終導致了他期末考試得了D等級(不佳)。同理,這6個點也就代表了6個往屆學生的平時狀態和最終成績,稱之爲訓練樣本。。。。

現在要來實現我們的預測目的了,想象一下現在一學期快過完了,張三同學馬上要考試了,他想知道自己能考的怎麼樣,他在數學老師那裏查到了自己的到課率85%,作業質量是90,那麼怎麼實現預測呢?張三可以看做是(85,90)這個點–也被稱之爲測試樣本,首先,我們計算張三到其他6位同學(訓練樣本)的距離,點到點的距離相信我們初中就學了吧(一般用的歐氏距離)。再選取前K個最近的距離,例如我們選擇k=3,那麼我們就找出距離最近的三個樣本分別屬於哪個類別,此例中,自然三個都是A等,所以可預測出張三的數學期末成績可能是A等(優秀)。倘若李四現在也想進行預測,據他較近的3箇中兩個D,一個A,那麼李四的數學期末成績被預測爲D。這也就是最開始所說的:在前k個樣本中選擇頻率最高的類別作爲預測類別。。。

總結其計算步驟如下:

算距離:給定測試對象,計算它與訓練集中的每個對象的距離
找鄰居:圈定距離最近的k個訓練對象,作爲測試對象的近鄰
做分類:根據這k個近鄰歸屬的主要類別,來對測試對象分類

好了,經過上述過程,你是否對KNN算法基本思想有了一定了解。也許你會問我,我大學不去上課,不交作業,照樣考A,這預測根本不準確嘛,O(∩_∩)O哈哈~,首先說明一下這個例子舉的確實不太恰當,因爲我們的特徵(到課率和作業質量)選取的不當,在很多分類預測算法中,決定其分類預測上限的往往是好的特徵的選取,好的特徵也就是對其最終結果的影響比較大的。。。原理就說到這吧。。。

算法複雜度
kNN是一種lazy-learning算法,分類器不需要使用訓練集進行訓練,因此訓練時間複雜度爲0;kNN分類的計算複雜度和訓練集中的文檔數目成正比,也就是說,如果訓練集中文檔總數爲n,那麼kNN的分類時間複雜度爲O(n);因此,最終的時間複雜度是O(n)。

  1. K-近鄰的優缺點
    KNN算法的優點:

1)簡單、有效。
2)重新訓練的代價較低(類別體系的變化和訓練集的變化,在Web環境和電子商務應用中是很常見的)。
3)計算時間和空間線性於訓練集的規模(在一些場合不算太大)。
4)由於KNN方法主要靠周圍有限的鄰近的樣本,而不是靠判別類域的方法來確定所屬類別的,因此對於類域的交叉或重疊較多的待分樣本集來說,KNN方法較其他方法更爲適合。
5)該算法比較適用於樣本容量比較大的類域的自動分類,而那些樣本容量較小的類域採用這種算法比較容易產生誤分。

KNN算法缺點:

1)KNN算法是懶散學習方法(lazy learning,基本上不學習),一些積極學習的算法要快很多。
2)類別評分不是規格化的(不像概率評分)。
3)輸出的可解釋性不強,例如決策樹的可解釋性較強。
4)該算法在分類時有個主要的不足是,當樣本不平衡時,如一個類的樣本容量很大,而其他類樣本容量很小時,有可能導致當輸入一個新樣本時,該樣本的K個鄰居中大容量類的樣本佔多數。該算法只計算“最近的”鄰居樣本,某一類的樣本數量很大,那麼或者這類樣本並不接近目標樣本,或者這類樣本很靠近目標樣本。無論怎樣,數量並不能影響運行結果。可以採用權值的方法(和該樣本距離小的鄰居權值大)來改進。
5)計算量較大。目前常用的解決方法是事先對已知樣本點進行剪輯,事先去除對分類作用不大的樣本。

  1. K-近鄰算法的Python實現
    友情提示:本代碼是基於Python2.7的,而且需要提前安裝numpy函數庫(這是我們常用的強大的科學計算包)。。。。

3.1 首先我們介紹一下代碼實現步驟:

計算已知類別數據集中的點與當前點之間的距離
按距離遞增次序排序
選取與當前點距離最小的k個點
統計前k個點所在的類別出現的頻率
返回前k個點出現頻率最高的類別作爲當前點的預測分類

3.2 實現:我們先創建一個名爲knn.py的文件,整體實現代碼如下:

from numpy import * #導入numpy科學計算包
import operator     #導入運算符模塊

#加載數據的方法,返回樣本數據(每一行是一個樣本)和樣本標籤
def createDataSet():
    group = array([[90,100],[88,90],[85,95],[10,20],[30,40],[50,30]])    #樣本點數據
    labels = ['A','A','A''D''D','D']
    return group,labels

#分類方法  傳入的dataset需是array數組
def classify0(inX, dataSet, labels, k):    #inX爲輸入樣本,例如[85,90]
    dataSetSize = dataSet.shape[0]              #求出輸入數據矩陣的行數(樣本個數)
    diffMat = tile(inX, (dataSetSize,1)) - dataSet    #求矩陣差
    sqDiffMat = diffMat ** 2                  
    sqDistance = sqDiffMat.sum(axis = 1)          #平方和
    distance = sqDistance ** 0.5               #測試樣本點距離每個樣本點的距離  
    sortedDistance = distance.argsort()          #將距離按升序排列

    classCount = {}
    for i in range(k):
        voteLabel = labels[sortedDistance[i]]      #遍歷前k個樣本的標籤
        classCount[voteLabel] = classCount.get(voteLabel,0) + 1  #對標籤進行計數,即每一類出現的次數
    sortedClassCount = sorted(classCount.items(),key = operator.itemgetter(1),reverse = True)  #將計數後的標籤按降序進行排列,得到元組列表
    return sortedClassCount[0][0]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章