K-近鄰算法(KNN)

 
keyword
  
  文本分類算法、簡單的機器學習算法、基本要素、距離度量、類別斷定、k取值、改進策略
 
摘要
  
  kNN算法是著名的模式識別統計學方法,是最好的文本分類算法之一,在機器學習分類算法中佔有至關大的地位,是最簡單的機器學習算法之一。
 
基本信息
  
  外文名:k-Nearest Neighbor(簡稱kNN)
  中文名:k最鄰近分類算法
  應用:文本分類、模式識別、圖像及空間分類
  典型:懶惰學習
  訓練時間開銷:0
  提出時間:1968年
  做者:Cover和Hart提出
  關鍵字:kNN算法、k近鄰算法、機器學習、文本分類
 
 
工做原理
  
思想:
  
  官方:給定測試樣本,基於某種距離度量找出訓練集中與其最靠近的k個訓練樣本,而後基於這k個"鄰居"的信息來進行預測。
  通俗點說:就是計算一個點與樣本空間全部點之間的距離,取出與該點最近的k個點,而後統計這k個點裏面所屬分類比例最大的(「迴歸」裏面使用平均法),則點A屬於該分類。
 k鄰近法實際上利用訓練數據集對特徵向量空間進行劃分,並做爲其分類的「模型」。
   三個基本要素:k值的選擇、距離度量、分類決策規則
 
 
圖例說明:
 
 
    上圖中,綠色圓要被決定賦予哪一個類,是紅色三角形仍是藍色四方形?若是K=3,因爲紅色三角形所佔比例爲2/3,綠色圓將被賦予紅色三角形那個類,若是K=5,因爲藍色四方形比例爲3/5,所以綠色圓被賦予藍色四方形類。
 
算法計算步驟

 

  


  
  一、算距離: 給定測試對象,計算它與訓練集中的每一個對象的距離;
  二、找鄰居:圈定距離最近的k個訓練對象,做爲測試對象的近鄰;
  三、作分類:根據這k個近鄰歸屬的主要類別,來對測試對象分類; 
 
距離的計算方式(類似性度量):

 

  
  歐式距離:

  曼哈頓距離:html

 
類別的斷定:
  
  投票法:少數服從多數,近鄰中哪一個類別的點最多就分爲該類。
  加權投票法:根據距離的遠近,對鄰近的投票進行加權,距離越近則權重越大(權重爲距離平方的倒數)。
 
 
優、缺點
 
優勢:
  一、簡單,易於理解,易於實現,無需估計參數,無需訓練;
  二、適合對稀有事件進行分類;
  三、特別適合於多分類問題(multi-modal,對象具備多個類別標籤), kNN比SVM的表現要好。 
缺點:
  一、 樣本容量較小的類域採用這種算法比較容易產生誤分。
    該算法在分類時有個主要的不足是,當樣本不平衡時,如一個類的樣本容量很大,而其餘類樣本容量很小時,有可能致使當輸入一個新樣本時,該樣本的K個鄰居中大容量類的樣本佔多數。 該算法只計算「最近的」鄰居樣本,某一類的樣本數量很大,那麼或者這類樣本並不接近目標樣本,或者這類樣本很靠近目標樣本。不管怎樣,數量並不能影響運行結果。
  二、該方法的另外一個不足之處是 計算量較大,由於對每個待分類的文本都要計算它到全體已知樣本的距離,才能求得它的K個最近鄰點。
  三、可理解性差,沒法給出像決策樹那樣的規則。
 
 
算法實例
 
流程:
  一、計算距離
  二、選擇距離最小的k個點
  三、經過投票方式,選擇點最多的標籤。
 
#-*- coding:utf-8 -*-
import numpy as np
import operator

def createDataset():
    #四組二維特徵
    group = np.array([[5,115],[7,106],[56,11],[66,9]])
    #四組對應標籤
    labels = ('動做片','動做片','愛情片','愛情片')
    return group,labels

"""
KNN算法
"""
def classify(intX, dataSet, labels, k):
    '''
    numpy中shape[0]返回數組的行數,shape[1]返回列數
    '''
    dataSetSize = dataSet.shape[0]

    """
    將intX在橫向重複dataSetSize次,縱向重複1次
    例如intX=([1,2])--->([[1,2],[1,2],[1,2],[1,2]])便於後面計算
    """
    diffMat = np.tile(intX, (dataSetSize, 1)) - dataSet

    """
    計算距離:歐式距離, 特徵相減後乘方,而後再開方
    """
    sqdifMax = diffMat**2
    seqDistances = sqdifMax.sum(axis=1)
    distances = seqDistances**0.5

    #返回distance中元素從小到大排序後的索引
    print ("distances:",distances)
    sortDistance = distances.argsort()
    print ("sortDistance:", sortDistance)

    """
    取出前k個元素的類別
    """
    classCount = {}
    for i in range(k):
        voteLabel = labels[sortDistance[i]]
        s = "第{}個voteLabel={}".format(i, voteLabel)
        print(s)
        classCount[voteLabel] = classCount.get(voteLabel,0)+1

    #dict.get(key,default=None),字典的get()方法,返回指定鍵的值,若是值不在字典中返回默認值。
    #計算類別次數

    #key=operator.itemgetter(1)根據字典的值進行排序
    #key=operator.itemgetter(0)根據字典的鍵進行排序
    #reverse降序排序字典
    sortedClassCount = sorted(classCount.items(), key = operator.itemgetter(1), reverse = True)
    #結果sortedClassCount = [('動做片', 2), ('愛情片', 1)]
    print ("sortedClassCount:")
    print(sortedClassCount)
    return sortedClassCount[0][0]

if __name__ == '__main__':
    group,labels = createDataset()
    test = [20,101]
    test_class = classify(test,group,labels,3)
    print (test_class)

  

 
運行結果 :

 


 
改進策略
 
  一、對樣本屬性進行約簡。——刪除對分類結果影響較小的屬性。
  二、採用權值的方法(和該樣本距離小的鄰居權值大)來改進。——依照訓練集合中各類分類的樣本數量,選取不一樣數目的最近鄰居,來參與分類。
 

 
常見問題
 
一、k值設定
   k值選擇太小,獲得的近鄰數過少,會下降分類精度,同時也會放大噪聲數據的干擾;而若是k值選擇過大,而且待分類樣本屬於訓練集中包含數據數較少的類,那麼在選擇k個近鄰的時候,實際上並不類似的數據亦被包含進來,形成噪聲增長而致使分類效果的下降。
  如何選取恰當的K值也成爲KNN的研究熱點。k值一般是採用交叉檢驗來肯定(以k=1爲基準)。
   經驗規則:k通常低於訓練樣本數的平方根。
 
 二、類別的斷定方式
  投票法沒有考慮近鄰的距離的遠近,距離更近的近鄰也許更應該決定最終的分類,因此加權投票法更恰當一些。
 
三、距離度量方式的選擇
  高維度對距離衡量的影響:衆所周知當變量數越多,歐式距離的區分能力就越差。
  變量值域對距離的影響:值域越大的變量經常會在距離計算中佔據主導做用,所以應先對變量進行標準化。
 
四、訓練樣本的參考原則
   學者們對於訓練樣本的選擇進行研究,以達到減小計算的目的,這些算法大體可分爲兩類。第一類,減小訓練集的大小。KNN算法存儲的樣本數據,這些樣本數據包含了大量冗餘數據,這些冗餘的數據增了存儲的開銷和計算代價。縮小訓練樣本的方法有:在原有的樣本中刪掉一部分與分類相關不大的樣本樣本,將剩下的樣本做爲新的訓練樣本;或在原來的訓練樣本集中選取一些表明樣本做爲新的訓練樣本;或經過聚類,將聚類所產生的中心點做爲新的訓練樣本
  
  在訓練集中,有些樣本多是更值得依賴的。能夠給不一樣的樣本施加不一樣的權重,增強依賴樣本的權重,下降不可信賴樣本的影響。
 
五、性能問題
  kNN是一種懶惰算法,而懶惰的後果:構造模型很簡單,但在對測試樣本分類地的系統開銷大,由於要掃描所有訓練樣本並計算距離。
  已經有一些方法提升計算的效率,例如壓縮訓練樣本量等。
 
 
參考文獻
 
 
 
推薦
相關文章
相關標籤/搜索