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,因此綠色圓被賦予藍色四方形類。
 
算法計算步驟

 

  


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

 

  
  歐式距離:

  曼哈頓距離:

 
類別的判定:
  
  投票法:少數服從多數,近鄰中哪個類別的點最多就分為該類。
  加權投票法:根據距離的遠近,對鄰近的投票進行加權,距離越近則權重越大(權重為距離平方的倒數)。
 
 
優、缺點
 
優點:
  1、簡單,易於理解,易於實現,無需估計參數,無需訓練;
  2、適合對稀有事件進行分類;
  3、特別適合於多分類問題(multi-modal,對象具有多個類別標簽), kNN比SVM的表現要好。 
缺點:
  1、 樣本容量較小的類域采用這種算法比較容易產生誤分。
    該算法在分類時有個主要的不足是,當樣本不平衡時,如一個類的樣本容量很大,而其他類樣本容量很小時,有可能導致當輸入一個新樣本時,該樣本的K個鄰居中大容量類的樣本占多數。 該算法只計算“最近的”鄰居樣本,某一類的樣本數量很大,那么或者這類樣本並不接近目標樣本,或者這類樣本很靠近目標樣本。無論怎樣,數量並不能影響運行結果。
  2、該方法的另一個不足之處是 計算量較大,因為對每一個待分類的文本都要計算它到全體已知樣本的距離,才能求得它的K個最近鄰點。
  3、可理解性差,無法給出像決策樹那樣的規則。
 
 
算法實例
 
流程:
  1、計算距離
  2、選擇距離最小的k個點
  3、通過投票方式,選擇點最多的標簽。
 
#-*- 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)

  

 
運行結果 :

 


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

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


免責聲明!

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



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