1. 程式人生 > >k近鄰算法(KNN)

k近鄰算法(KNN)

葉子 share 容易 並且 曼哈頓 耗時 機器 發生 分類

1. 前言

K近鄰法(k-nearest neighbors,KNN)是一種很基本的機器學習方法了,在我們平常的生活中也會不自主的應用,就是“物以類聚,人以群分”。比如,我們判斷一個人的人品,只需要觀察他來往最密切的幾個人的人品好壞就可以得出了。這裏就運用了KNN的思想。KNN方法既可以做分類,也可以做回歸,這點和決策樹算法相同。

KNN做回歸和分類的主要區別在於最後做預測時候的決策方式不同。KNN做分類預測時,一般是選擇多數表決法,即訓練集裏和預測的樣本特征最近的K個樣本,預測為裏面有最多類別數的類別。而KNN做回歸時,一般是選擇平均法,即最近的K個樣本的樣本輸出的平均值作為回歸預測值。由於兩者區別不大,雖然本文主要是講解KNN的分類方法,但思想對KNN的回歸方法也適用。本文後面主要介紹的是KNN的分類問題。

2. KNN算法原理

給定一個訓練集,對新輸入的實例,在訓練集中找到與該實例最鄰近的k個實例,這k個實例的多數屬於某個類,我們就把該輸入實例分為這個類。
技術分享圖片

2.1 算法描述

輸入:訓練數據集\(T=\{(x_1,y_1),(x_2,y_2),...,(x_N,y_N)\}\),其中\(x_i\in{\chi}\)為實例的特征向量,\(y_i\in{\{c_1,c_2,...,c_m\}}\)為實例的類別;實例特征向量x

輸出:實例x所屬的類別y

  1. 根據給定的距離度量方式,在訓練集T中找到與x最鄰近的k個點,涵蓋著k個點的x的領域記住\(N_k(x)\)
  2. \(N_k(x)\)中根據分類決策規則決定x的類別y
    \[ y=argmax_{c_j}\sum_{x_i\in{N_k(x)}}I(y_i=c_j) \]

    其中\(I(y_i=c_j)\)為指示函數,當\(y_i=c_j\)的時候\(I=1\),後者\(I=0\)

3. KNN的基本要素

對於一個確定的訓練集,只要確定了距離度量、k值和分類決策規則,就能對任何一個新的實例,確定它的分類。

3.1 距離度量

距離度量是描述特征空間中兩個實例的距離,也是這兩個實例的相似程度。在n維實數向量空間中,我們主要使用的距離度量方式是歐式距離,但也可以使用更加一般化\(L_p\)距離(閔可夫斯基距離)。

在特征空間中,取出兩個特征\(x_i\)\(x_j\),它們分別是n維的特征向量。

3.1.1 歐氏距離

\[ L_2(x_i,x_j)=(\sum_{l=1}^n|x_i^l-x_j^l|)^{\frac{1}{2}} \]

3.1.2 曼哈頓距離

\[ L_1(x_i,x_j)=\sum_{l=1}^n|x_i^l-x_j^l| \]

3.1.3 閔可夫斯基距離

\[ L_p(x_i,x_j)=(\sum_{l=1}^n|x_i^l-x_j^l|)^{\frac{1}{p}} \]
從上式可以看出,歐氏距離和曼哈頓距離分別是閔可夫斯基距離的\((p=2,p=1)\)特殊情況

3.2 k值的選擇

對於k值的選擇,沒有一個固定的經驗,一般根據樣本的分布,選擇一個較小的值,然後通過交叉驗證選擇一個合適的k值

  • 選擇較小的k值,就相當於用較小的領域中的訓練實例進行預測,訓練誤差會減小,只有與輸入實例較近或相似的訓練實例才會對預測結果起作用,與此同時帶來的問題是泛化誤差會增大。換句話說,k值的減小就意味著整體模型變得復雜,容易發生過擬合。
  • 選擇較大的k值,就相當於用較大領域中的訓練實例進行預測,其優點是可以減少泛化誤差,但缺點是訓練誤差會增大。這時候,與輸入實例較遠(不相似的)訓練實例也會對預測器作用,使預測發生錯誤。換句話說,k值的增大就意味著整體的模型變得簡單,容易發生欠擬合。

一個極端是k等於樣本數m,則完全沒有分類,此時無論輸入實例是什麽,都只是簡單的預測它屬於在訓練實例中最多的類,模型過於簡單。

3.3 分類決策規則

對於分類決策規則,一般都是使用前面提到的多數表決法。

4. kd樹

KNN算法最簡單的實現方式,就是好計算輸入實例和所有訓練實例的距離,然後進行排序,取前k個,進行分類。但是訓練集特別大的時候,這種方式非常耗時,不可行。下面介紹kd樹的方式,kd樹是通過減少輸入實例和訓練實例的計算次數來達到優化的目的。

kd樹算法包括三步,第一步是建樹,第二部是搜索最近鄰,最後一步是預測。

4.1 構造kd樹

kd樹是一種對n維空間的實例點進行存儲,以便對其進行快速檢索的樹形結構。kd樹是二叉樹,構造kd樹相當於不斷的用垂直於坐標軸的超平面將n維空間進行劃分,構成一系列的n維超矩陣區域。

我們首先來看建樹的方法。kd樹建樹采用的是從m個樣本的n維特征中,分別計算n個特征的取值的方差,用方差最大的第k維特征\(n_k\)來作為根節點。對於這個特征,我們選擇特征nk的取值的中位數\(n_{kv}\)對應的樣本作為劃分點,對於所有第k維特征的取值小於\(n_{kv}\)的樣本,我們劃入左子樹,對於第k維特征的取值大於等於\(n_{kv}\)的樣本,我們劃入右子樹,對於左子樹和右子樹,我們采用和剛才同樣的辦法來找方差最大的特征來做更節點,遞歸的生成kd樹。

下面的流程圖更加清晰的描述了kd樹的構建過程:

技術分享圖片

構建好的kd樹,大概如下:

技術分享圖片

4.2 kd樹搜索最近鄰

當我們生成kd樹以後,就可以去預測測試集裏面的樣本目標點了。預測的過程如下:

  1. 對於一個目標點,我們首先在kd樹裏面找到包含目標點的葉子節點。以目標點為圓心,以目標點到葉子節點樣本實例的距離為半徑,得到一個超球體,最近鄰的點一定在這個超球體內部。
  2. 然後返回葉子節點的父節點,檢查另一個子節點包含的超矩形體是否和超球體相交,如果相交就到這個子節點尋找是否有更加近的近鄰,有的話就更新最近鄰,並且更新超球體。如果不相交那就簡單了,我們直接返回父節點的父節點,在另一個子樹繼續搜索最近鄰。
  3. 當回溯到根節點時,算法結束,此時保存的最近鄰節點就是最終的最近鄰。

從上面的描述可以看出,kd樹劃分後可以大大減少無效的最近鄰搜索,很多樣本點由於所在的超矩形體和超球體不相交,根本不需要計算距離。大大節省了計算時間。

搜索過程,大致如下:

技術分享圖片

4.3 kd樹預測

有了kd樹搜索最近鄰的辦法,kd樹的預測就很簡單了,在kd樹搜索最近鄰的基礎上,我們選擇到了第一個最近鄰樣本,就把它置為已選。在第二輪中,我們忽略置為已選的樣本,重新選擇最近鄰,這樣跑k次,就得到了目標的k個最近鄰。然後根據多數表決法,如果是KNN分類,預測為k個最近鄰裏面有最多類別數的類別。如果是KNN回歸,用k個最近鄰樣本輸出的平均值作為回歸預測值。

k近鄰算法(KNN)