1. 程式人生 > >一文搞懂K近鄰演算法(KNN),附帶多個實現案例

一文搞懂K近鄰演算法(KNN),附帶多個實現案例

640?wx_fmt=jpeg


簡介:本文作者為 CSDN 部落格作者董安勇,江蘇泰州人,現就讀於昆明理工大學電子與通訊工程專業碩士,目前主要學習機器學習,深度學習以及大資料,主要使用python、Java程式語言。平時喜歡看書,打籃球,程式設計。學習為了進步,進步為了更好的學習!


一、KNN回顧


k 近鄰學習是一種常用的監督學習方法,比如:判斷一個人的人品,只需要觀察與他來往最密切的幾個人的人品好壞就可以得出,即“近朱者赤,近墨者黑”。


理論/原理:“物以類聚,人以群分”


  • 相同/近似樣本在樣本空間中是比較接近的,所以可以使用和當前樣本比較近的其他樣本的目標屬性值作為當前樣本的預測值。


k 近鄰法的工作機制很簡單:


  • 給定測試樣本,基於某種距離度量(一般使用歐幾里德距離)找出訓練集中與其最靠近的k個訓練樣本,然後基於這k個“鄰居”的資訊來進行預測。


二、KNN三要素


1、K值的選擇


  • 對於K值的選擇,一般根據樣本分佈選擇一個較小的值,然後通過交叉驗證來選擇一個比較合適的最終值;

  • 當選擇比較小的K值的時候,表示使用較小領域中的樣本進行預測,訓練誤差會減小,但是會導致模型變得複雜,容易導致過擬合;

  • 當選擇較大的K值的時候,表示使用較大領域中的樣本進行預測,訓練誤差會增大,同時會使模型變得簡單,容易導致欠擬合;


2、距離度量


  • 一般使用歐幾里德距離

  • 關於距離度量,還有其他方式


3、決策規則


KNN在做迴歸和分類的主要區別在於最後做預測時的決策方式不同:


(1)分類預測規則:一般採用多數表決法或者加權多數表決法


640?wx_fmt=png


假設圖中 “?”表示待預測樣本,紅色圓表示一類,藍色方塊表示一類,2和3表示到待預測樣本的距離


1. 多數表決法:


  • 每個鄰近樣本的權重是一樣的,也就是說最終預測的結果為出現類別最多的那個類;

  • 如圖,待預測樣本被預測為紅色圓


2. 加權多數表決法:


  • 每個鄰近樣本的權重是不一樣的,一般情況下采用權重和距離成反比的方式來計算,也就是說最終預測結果是出現權重最大的那個類別;

  • 如圖,紅色圓到待預測樣本的距離為3,藍色方塊到待預測樣本的距離為2,權重與距離成反比,所以藍色的權重比較大,待預測樣本被預測為藍色方塊。


(2)迴歸預測規則:一般採用平均值法或者加權平均值法


640?wx_fmt=png


假設上圖中的2和3表示鄰近樣本的目標屬性值(標籤值),此時沒有類別,只有屬性值


1、平均值法


  • 每個鄰近樣本的權重是一樣的,也就是說最終預測的結果為所有鄰近樣本的目標屬性值的均值;

  • 如圖,均值為(3+3+3+2+2)/5=2.6


2、加權平均值法


640?wx_fmt=png


圖中,雙箭頭線上的數表示到待預測樣本的距離


  • 每個鄰近樣本的權重是不一樣的,一般情況下采用權重和距離成反比的方式來計算,也就是說在計算均值的時候進行加權操作;

  • 如圖,權重分別為(各自距離反比佔距離反比總和的比例):

  • 屬性值為3的權重:

640?wx_fmt=jpeg

  • 屬性值為2的權重:

    640?wx_fmt=png

  • 待預測樣本的加權平均值為:

640?wx_fmt=png


三、手寫 k 近鄰演算法


實現kNN分類演算法的虛擬碼:


對未知類別屬性的資料集中的每個點依次執行一下操作:


(1)計算已知類別資料集中的點與當前點之間的距離

(2)按照距離遞增次序排序

(3)選取與當前點距離最小的k個點

(4)確定前k個點所在類別的出現頻數

(5)返回當前k個點出現頻數最高的類別作為當前點的預測分類


歐氏距離公式:

 

640?wx_fmt=png

例如求點(1,0,0,1) (1,0,0,1)(1,0,0,1)和(7,6,9,4) (7,6,9,4)(7,6,9,4)之間的距離:

640?wx_fmt=png

檢測分類器效果:

  • 可以使用已知類別的資料(當然不告訴分類器),檢驗分類器給出的結果是否與已知類別相同,通過大量的測試資料,我們可以計算出分類器的錯誤率。


以上演算法的實現是用於分類的,決策規則使用了多數表決法;此演算法通過改變決策規則,同樣可以用於迴歸。


原始碼可見:https://github.com/Daycym/Machine_Learning/tree/master/03_KNN;01_k近鄰演算法.py


四、使用手寫k kk 近鄰演算法的案例


1、案例1:約會網站的配對效果


樣本包括3種特徵:


  • 每年獲得的飛行常客里程數

  • 玩視訊遊戲所耗時間百分比

  • 每週消費的冰淇淋公升數


樣本包括3種標籤:


  • 不喜歡的人

  • 魅力一般的人

  • 極具魅力的人


部分資料格式為:


640?wx_fmt=png


程式碼可見:02_約會網站的配對效果.py


2、案例2:手寫數字識別系統


  • 資料集包括訓練集和測試集

  • 資料是32*32的二進位制文字檔案

  • 需要將文字資料轉換為Numpy陣列


如下是0的一種表示:



  

100000000000001100000000000000000
200000000000011111100000000000000
300000000000111111111000000000000
400000000011111111111000000000000
500000001111111111111100000000000
600000000111111100011110000000000
700000001111110000001110000000000
800000001111110000001110000000000
900000011111100000001110000000000
1000000011111100000001111000000000
1100000011111100000000011100000000
1200000011111100000000011100000000
1300000011111000000000001110000000
1400000011111000000000001110000000
1500000001111100000000000111000000
1600000001111100000000000111000000
1700000001111100000000000111000000
1800000011111000000000000111000000
1900000011111000000000000111000000
2000000000111100000000000011100000
2100000000111100000000000111100000
2200000000111100000000000111100000
2300000000111100000000001111100000
2400000000011110000000000111110000
2500000000011111000000001111100000
2600000000011111000000011111100000
2700000000011111000000111111000000
2800000000011111100011111111000000
2900000000000111111111111110000000
3000000000000111111111111100000000
3100000000000011111111110000000000
3200000000000000111110000000000000


預測錯誤的總數為:10

手寫數字識別系統的錯誤率為:0.010571


程式碼可見:03_手寫數字識別系統.py


五、KD樹


KNN演算法的重點在於找出K個最鄰近的點,主要方法如下:


1、蠻力實現(brute)


  • 計算出待預測樣本到所有訓練樣本的訓練資料,然後選擇最小的K個距離即可得到K個最鄰近點;

  • 當特徵數比較多,樣本數比較多的時候,演算法的執行效率比較低。


2、KD樹(KD_Tree)


  • KD_Tree演算法中,首先是對訓練資料進行建模,構建KD樹,然後再根據構建好的模型來獲取鄰近樣本資料

  • KD_Tree是KNN演算法中用於計算最近鄰的快速、便捷構建方式


除此之外,還有一些從KD_Tree修改後的求解最鄰近點的演算法,比如:Ball Tree、BBF Tree、MVP Tree等


  • 當樣本資料量少的時候,我們可以使用brute這種暴力的方式進行求解最近鄰,即計算到所有樣本的距離。

  • 當樣本量比較大的時候,直接計算所有樣本的距離,工作量有點大,所以在這種情況下,我們可以使用kd tree來快速的計算。


(1)KD數的構建


KD樹採用從m個樣本的n維特徵中,分別計算n個特徵取值的方差,用方差最大的第 k 維特徵640?wx_fmt=jpeg作為根節點。對於這個特徵,選擇取值的中位數640?wx_fmt=jpeg作為樣本的劃分點,對於小於該值的樣本劃分到左子樹,對於大於等於該值的樣本劃分到右子樹,對左右子樹採用同樣的方式找方差最大的特徵作為根節點,遞迴即可產生KD樹。


假設二維樣本為:{(2, 3), (5, 4), (9, 6), (4, 7), (8, 1), (7, 2)},下面我們來構建KD樹:


1、計算每個特徵的方差,取方差最大的作為根節點


640?wx_fmt=png

方差表示資料的離散程度,離散程度越大,值越大。因此,選擇第1維特徵x1作為根節點。


2、選取中位數作為劃分點


x1取值為2,4,5,7,8,9 2,4,5,7,8,92,4,5,7,8,9中位數取7來劃分,小於該值的放在左子樹,大於該值的放在右子樹


640?wx_fmt=png


3、特徵空間劃分:


640?wx_fmt=png


(2)KD tree查詢最近鄰


當我們生成KD樹以後,就可以取預測測試集裡面的樣本目標點了。

  • 對於一個目標點,我們首先在KD樹裡面尋找包含目標點的葉子節點;

  • 以目標點為圓心,以目標點到葉子節點樣本例項的距離為半徑,得到一個超球體,最近鄰的點一定在這個超球體內部;

  • 然後返回葉子節點的父節點,檢查另一個子節點包含的超矩形體是否和超球體相交,如果相交就到這個子節點尋找是否有更加近的近鄰,有點話就更新最近鄰;如果不相交那就直接返回父節點的父節點,在另一個子樹繼續搜尋最近鄰;

  • 當回溯到根節點時,演算法就結束了,儲存最近鄰節點就是最終的最近鄰。


假設要尋找點(2,2.5) (2,2.5)(2,2.5)的最近鄰點:


640?wx_fmt=png


六、KNN案例


1、鳶尾花資料分類


640?wx_fmt=png

640?wx_fmt=png

640?wx_fmt=png

  • 使用Logistic演算法和KNN演算法對鳶尾花資料進行分類,比較結果;

  • 具體內容在程式碼的註釋中有介紹;

  • 畫出下面兩張圖,需要將程式碼整合起來,才能畫出來。


程式碼可見:https://github.com/Daycym/Machine_Learning;02_Logistic迴歸05_鳶尾花資料分類.py,以及03_KNN目錄下04_鳶尾花資料分類.py


2、信貸審批

640?wx_fmt=png

640?wx_fmt=png

具體內容將在程式碼中介紹


程式碼可見:https://github.com/Daycym/Machine_Learning;02_Logistic迴歸03_信貸審批.py,以及03_KNN目錄下05_信貸審批.py


七、總結


  • 本篇主要通過簡單的暴力求解的方式實現KNN演算法,有助於理解KNN演算法

  • 後面又介紹了KD樹找K個最近鄰,此演算法是最快捷的

  • 最後通過sklearn庫下的KNeighborsClassifier實現了兩個案例,來屬性KNN模型的構建

原文連結:

https://blog.csdn.net/Daycym/article/details/84452786


(*本文為AI科技大本營轉載文章,轉載請聯絡原作者)


推薦


640?wx_fmt=jpeg


推薦閱讀

640?wx_fmt=png