1. 程式人生 > 其它 >機器學習筆記—KNN演算法

機器學習筆記—KNN演算法

目錄[-]

前言

分類(Classification)是資料探勘領域中的一種重要技術,它從一組已分類的訓練樣本中發現分類模型,將這個分類模型應用到待分類的樣本進行預測。

當前主流的分類演算法有:樸素貝葉斯分類(Naive Bayes)、支援向量機(SVM)、KNN(K-Nearest Neighbors)、神經網路(NNet)、決策樹(Decision Tree)等等。

KNN演算法是一個理論上比較成熟的方法,最初由Cover和Hart於1968年提出,思路非常簡單直觀,易於快速實現。

基本思想

如下圖所示,假設有已知型別的三類訓練樣本 $ omega_1、omega_2、omega_3$,現對樣本 $ X_u $進行分類。根據距離函式

依次計算待分類樣本 $ X_u$ 和每個訓練的距離,這個距離看做是相似度。選擇與待分類樣本距離最近的K個訓練樣本,如下圖黑色箭頭所指的5個樣本。最後K個類別中所屬類別最多的類別作為待分類樣本的類別,如下圖中 $ X_u $屬於 $ omega_1$ 類。

KNN可以說是一種最直接的用來分類未知資料的方法。簡單來說,KNN可以看成:有那麼一堆已經知道類別的資料,當有一個新資料進入時,依次計算這個資料和每個訓練資料的距離,然後跳出離這個資料最近的K個點,看看這個K個點屬於什麼型別,然後用少數服從多數的原則,給新資料歸類。

演算法實現

實現步驟

  • 1.構建訓練資料集(資料標準化);
  • 2.計算訓練資料集中的點與當前點的距離;
  • 3.按照距離遞增排序;
  • 4.選取距離與當前距離最小的K個點;
  • 5.確定前K個點中所在類別的出現概率;
  • 6.返回前K個點中出現概率最高的類別作為當前點的分類。

Python實現程式碼:

import numpy as np
import operator


def createDataSet():
    """
    構造假的訓練資料,產生四條訓練樣本,group為樣本屬性,labels為分類標籤,即[1.0,1.1]屬於A類
    :return:
    """
    group = np.array([[1.0, 1.1], [1.0, 1.0], [0, 0], [0, 0.1]])
    labels = ['A', 'A', 'B', 'B']
    return group, labels


def classify(inX, dataSet, labels, k):
    """
    簡單KNN分類
    :param inX: 待分類向量
    :param dataSet: 訓練樣本集
    :param labels: 訓練樣本標籤
    :param k: K值
    :return:
    """
    dataSetSize = dataSet.shape[0]  # 訓練樣本個數
    diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet  # 計算訓練樣本和待分類樣本的數值差值
    # 用於後面計算歐式距離,歐氏距離為各維度上數值差值的平方和再開方的結果
    sqDiffMat = diffMat ** 2             # 差值的平方
    sqDistances = sqDiffMat.sum(axis=1)  # 平方和
    distances = sqDistances ** 0.5       # 平方和開方
    sortedDistIndicies = distances.argsort()  # 返回升序排列後的索引
    classCount = {}
    # 統計前K個樣本中各標籤出現次數
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
    # 按標籤次數排序,返回次數最多的標籤
    return sortedClassCount[0][0]

if __name__ == '__main__':
    group, labels = createDataSet()
    print(classify([0, 0], group, labels, 2))
    # 最終輸出類別為B

上例程式碼中,樣本距離計算採用的是歐式距離,距離方法的選擇也會影響到分類結果,關於可選的距離度量以及計算公式,可以參考這篇文章 常用樣本相似性和距離度量方法

優缺點

  • 優點
    • 1.KNN演算法思想簡單,非常容易實現;
    • 2.有新樣本要加入訓練集時,無需重新訓練;
    • 3.時間和空間複雜度與訓練集大小成線性相關;
  • 缺點
    • 1.分類速度慢;

    KNN演算法的時間複雜度和儲存空間會隨著訓練集規模和特徵維數的增大而增加。因此每次分類新樣本時,都要和所有的訓練樣本進行計算比較。整個演算法的時間複雜度可以用 $O(m*n)$ 表示,其實 $m$ 和 $n$ 分別是特徵維度和訓練集樣本個數。

    • 2.各屬性權重相同,影響準確率;

    當樣分佈不均勻時,如果某一個類的樣本容量很大,而其他類樣本容量很小。有可能在對新樣本進行分類時,前K個最近的樣本中樣本容量大的類佔了多數,而不是真正接近的類佔了多數,這樣會導致分類錯誤。

    • 3.樣本依賴性很強;
    • 4.K值不好確定;

    K值設定過小時,得到的鄰近數也會太小,這樣會放大噪聲資料的干擾,影響分類精度。K值設定過大時,就會使2中描述的錯誤概率增加。

KNN改進

降低計算複雜度

KNN的一個嚴重問題就是需要儲存全部訓練樣本,以及繁重的距離計算量。下面是一些已知的改進方法:

  • 特徵維度壓縮 在KNN演算法之前對樣本屬性進行約簡,刪除對分類結果影響較小(不重要)的屬性。例如粗糙集理論在用於決策表的屬性約簡時,可在保持決策表中決策能力不變的前提下,刪除其中不相關的冗餘屬性。
  • 縮小訓練樣本 就是在原樣本中挑選出對分類計算有效的樣本,使樣本總數合理地減少,但又不會影響分類精度。常用的有剪輯近鄰法壓縮近鄰法
    • 剪輯近鄰法

    其基本思想是:利用現有樣本集對自身進行剪輯,將不同類別交界處的樣本以適當方式篩選,可以實現即減少樣本數,又提高正確識別率的目的。過程如下:將樣本集 $K^N$ 分成兩個相互獨立的子集: test集 $K^T$ 和reference集 $K^R$ 。首先對 $K^T$ 中每個樣本 $X_i$ 在 $K^R$ 中找到其最近鄰的樣本 $Y_i(X_i)$ 。如果 $Y_i$ 和 $X_i$ 不屬於同一類別, 則將 $X_i$ 從 $K^t$ 中刪除,最後得到一個剪輯的樣本集 $K^TE$ ,以取代原樣本。

    • 壓縮近鄰法

    其基本思想是:利用現有樣本集,逐漸生成一個新的樣本集,使該樣本在保留最少樣本的條件下,仍能對原有樣本的全部用最近鄰法正確分類。過程如下:定義兩個儲存器,一個用來存放即將生成的樣本集,稱為Store;另一個儲存器則存放原樣本,稱為Grabbag。演算法過程: 過程1.初始化,Store是空集,原樣本存入Grabbag;從Grabbag中任意選擇一樣本放入Store中,作為新樣本集的第一個樣本。過程2.樣本集生成,依次從Grabbag中取出第 $i$ 個樣本,用Store中的樣本集用最近鄰發分類。若分類錯誤,則將該樣本從Grabbag中轉入Store,若分類正確,則將該樣本放回Grabbag。過程3.結束判斷,如果Grabbag中所有樣本在執行過程2時沒有發生轉入Store現象,或者Grabbag已為空,則演算法結束,否則轉入過程2。

  • 預建立結構 常用的是基於樹的快速查詢,其基本思想是:將樣本按鄰近關係分解成組,給出每組的質心,已經組內樣本至質心的最大距離。這些組又可以形成層次結構,即組又分子組,因而待識別樣本可將搜尋近鄰的範圍從某一大組,逐漸深入到其中的子組,直至樹的葉節點所代表的組,確定其近鄰關係。

提高分類準確度

  • 優化相似度量

前面已經計算樣本間的相似度量有很多,常用樣本相似性和距離度量方法。基本上KNN演算法都是基於歐氏距離來計算樣本相似度,但這種方法認為各維度對分類貢獻率是相同的,這回影響分類的準確度。因此也有人提出過基於權重調整係數的改進方法。改方法的思想是,在距離度量函式中對不同屬性賦予不同權重,改進後的歐式距離公式為: $$d(x_i,y_j)=sqrt{sum_{k=1}^lomega_l(x_{ki}-y_{kj})^2}$$ 然後通過靈敏度法確定權重向量 $omega_l$。

- 首先統計出分類錯誤的樣本數 $n$;
- 依次去掉特徵集中的屬性,應用KNN分類,統計出分類錯誤的樣本數量 $n_q$;
- $n_q$與 $n$ 的比值 $n_q over n$ 就是對於特徵維度的權重係數。
  • 選取恰當K值

由於KNN演算法中幾乎所有的計算都發生在分類階段,而且分類效果很大程度上依賴於L值的選擇,而目前為止,比較好的選擇K值的方法只能是通過反覆試驗調整。