1. 程式人生 > >k近鄰算法(k-nearest neighbor,k-NN)

k近鄰算法(k-nearest neighbor,k-NN)

導致 邏輯回歸 希望 clas 基本上 nts 就是 保存 顯式

kNN是一種基本分類與回歸方法。k-NN的輸入為實例的特征向量,對應於特征空間中的點;輸出為實例的類別,可以取多類。k近鄰實際上利用訓練數據集對特征向量空間進行劃分,並作為其分類的“模型”。k值的選擇、距離度量及分類決策規則是k近鄰的三個基本要素。

算法

輸入:訓練數據集T={(x1,y1),(x2,y2),……..,(xN,yN)}

輸出:實例x所屬的類y

(1)根據給定的距離度量,在訓練集T中找到與x最鄰近的k個點,涵蓋這k個點的x的鄰域記作Nk(x)

(2)在Nk(x)中根據分類決策規則(如多數表決)決定x的類別y:

y=arg maxΣI(yi=cj) i=1,2,3,……,N; j=1,2,3,….K 其中I為指示函數,即當yi

=cj時I為1,否則I為0

k近鄰法的特殊情況是k=1的情形,稱為最近鄰算法。對於輸入的實例點(特征向量)x,最近鄰法將訓練數據集中與x最近鄰點的類作為x的類。k近鄰法沒有顯式的學習過程。

k近鄰模型

k近鄰法中,當訓練數據集、距離度量(如歐氏空間)、k值及分類決策規則(如多數表決)確定後,對於任何一個新的輸入實例,它屬於的類唯一地確定。這相當於根據上述要素將特征空間劃分為一些子空間,確定子空間裏的每個點所屬的類。

特征空間中,對每個訓練實例點xi,距離該點比其他點更近的所有點組成一個域,叫做單元cell。每個訓練實例點擁有一個單元,所有訓練實例點的單元構成對特征空間的一個劃分。

距離度量

常用的距離是歐式距離,Minkowski距離,更一般的是Lp

距離。

設k近鄰法中實例特征向量為一個n維實數向量,記為技術分享圖片,其中上標(m) 表示向量第m維的數值。

則一般距離Lp定義為:

技術分享圖片

當p=2時就是我們常用的歐式距離。

k值的選擇

k值的選擇會對k近鄰法的結果產生重大影響。

如果選擇較小的k值,就相當於用較小的鄰域中的訓練實例進行預測,“學習”的近似誤差會減小,只有與輸入實例較近的(相似的)訓練實例才會對預測結果起作用。但缺點是“學習”的估計誤差會增大,預測結果會對近鄰的實例點非常敏感。如果近鄰的實例點恰巧是噪聲,預測就會出錯。換句話說,k值的減小就意味著整體模型變得復雜,容易發生過擬合

如果選擇較大的k值,就相當於用較大鄰域中的訓練實例進行預測,其優點是可以減少學習的估計誤差。但缺點是學習的近似誤差會增大。這時與輸入實例較遠(不相似的)訓練實例也會對預測起作用,使預測發生錯誤。k值的增大就意味著整體模型變得簡單。

在應用中,k值一般取一個比較小的數值,通常采用交叉驗證法來選取最優的k值。

分類決策規則——多數表決規則

多數表決規則:

即輸入實例的k個近鄰的訓練實例中的多數類決定輸入實例的類別。多數表決規則的解釋:如果分類的損失函數為0-1損失函數,

分類函數為:

f:x ——>{c1,c2,...,ch}

其中x為實例的特征向量,c1,c2,...,ch為h個類別。

對給定的實例x,其最近鄰的k個訓練實例構成的集合Nk(x),如果覆蓋Nk(x)的區域的類別是cj,則誤分類率是:

技術分享圖片

要使誤分類率最小即經驗風險最小,就要使技術分享圖片所以多數表決規則等價於經驗風險最小化。

KNN算法之KD樹實現原理

    KD樹算法沒有一開始就嘗試對測試樣本分類,而是先對訓練集建模,建立的模型就是KD樹,建好了模型再對測試集做預測。所謂的KD樹就是K個特征維度的樹,註意這裏的K和KNN中的K的意思不同。KNN中的K代表特征輸出類別,KD樹中的K代表樣本特征的維數。為了防止混淆,後面我們稱特征維數為n。

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

KD樹的建立

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

    具體流程如下圖:

技術分享圖片

    比如我們有二維樣本6個,{(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)},構建kd樹的具體步驟為:

    1)找到劃分的特征。6個數據點在x,y維度上的數據方差分別為6.97,5.37,所以在x軸上方差更大,用第1維特征建樹。

    2)確定劃分點(7,2)。根據x維上的值將數據排序,6個數據的中值(所謂中值,即中間大小的值)為7,所以劃分點的數據是(7,2)。這樣,該節點的分割超平面就是通過(7,2)並垂直於:劃分點維度的直線x=7;

    3)確定左子空間和右子空間。 分割超平面x=7將整個空間分為兩部分:x<=7的部分為左子空間,包含3個節點={(2,3),(5,4),(4,7)};另一部分為右子空間,包含2個節點={(9,6),(8,1)}。

    4)用同樣的辦法劃分左子樹的節點{(2,3),(5,4),(4,7)}和右子樹的節點{(9,6),(8,1)}。最終得到KD樹。

    最後得到的KD樹如下:

技術分享圖片

KD樹搜索最近鄰  

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

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

    我們用前一節建立的KD樹,來看對點(2,4.5)找最近鄰的過程。

    先進行二叉查找,先從(7,2)查找到(5,4)節點,在進行查找時是由y = 4為分割超平面的,由於查找點為y值為4.5,因此進入右子空間查找到(4,7),形成搜索路徑<(7,2),(5,4),(4,7)>,但 (4,7)與目標查找點的距離為3.202,而(5,4)與查找點之間的距離為3.041,所以(5,4)為查詢點的最近點; 以(2,4.5)為圓心,以3.041為半徑作圓,如下圖所示。可見該圓和y = 4超平面交割,所以需要進入(5,4)左子空間進行查找,也就是將(2,3)節點加入搜索路徑中得<(7,2),(2,3)>;於是接著搜索至(2,3)葉子節點,(2,3)距離(2,4.5)比(5,4)要近,所以最近鄰點更新為(2,3),最近距離更新為1.5;回溯查找至(5,4),直到最後回溯到根結點(7,2)的時候,以(2,4.5)為圓心1.5為半徑作圓,並不和x = 7分割超平面交割,如下圖所示。至此,搜索路徑回溯完,返回最近鄰點(2,3),最近距離1.5。

    對應的圖如下:

技術分享圖片

KD樹預測 

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

KNN算法之球樹實現原理

    KD樹算法雖然提高了KNN搜索的效率,但是在某些時候效率並不高,比如當處理不均勻分布的數據集時,不管是近似方形,還是矩形,甚至正方形,都不是最好的使用形狀,因為他們都有角。一個例子如下圖:

技術分享圖片

    如果黑色的實例點離目標點星點再遠一點,那麽虛線圓會如紅線所示那樣擴大,導致與左上方矩形的右下角相交,既然相 交了,那麽就要檢查這個左上方矩形,而實際上,最近的點離星點的距離很近,檢查左上方矩形區域已是多余。於此我們看見,KD樹把二維平面劃分成一個一個矩形,但矩形區域的角卻是個難以處理的問題。

    為了優化超矩形體導致的搜索效率的問題,牛人們引入了球樹,這種結構可以優化上面的這種問題。

    我們現在來看看球樹建樹和搜索最近鄰的算法。

球樹的建立

    球樹,顧名思義,就是每個分割塊都是超球體,而不是KD樹裏面的超矩形體。

技術分享圖片

    我們看看具體的建樹流程:

    1) 先構建一個超球體,這個超球體是可以包含所有樣本的最小球體。

    2) 從球中選擇一個離球的中心最遠的點,然後選擇第二個點離第一個點最遠,將球中所有的點分配到離這兩個聚類中心最近的一個上,然後計算每個聚類的中心,以及聚類能夠包含它所有數據點所需的最小半徑。這樣我們得到了兩個子超球體,和KD樹裏面的左右子樹對應。

    3)對於這兩個子超球體,遞歸執行步驟2). 最終得到了一個球樹。

    可以看出KD樹和球樹類似,主要區別在於球樹得到的是節點樣本組成的最小超球體,而KD得到的是節點樣本組成的超矩形體,這個超球體要與對應的KD樹的超矩形體小,這樣在做最近鄰搜索的時候,可以避免一些無謂的搜索。

球樹搜索最近鄰

使用球樹找出給定目標點的最近鄰方法是首先自上而下貫穿整棵樹找出包含目標點所在的葉子,並在這個球裏找出與目標點最鄰近的點,這將確定出目標點距離它的最近鄰點的一個上限值,然後跟KD樹查找一樣,檢查兄弟結點,如果目標點到兄弟結點中心的距離超過兄弟結點的半徑與當前的上限值之和,那麽兄弟結點裏不可能存在一個更近的點;否則的話,必須進一步檢查位於兄弟結點以下的子樹。

    檢查完兄弟節點後,我們向父節點回溯,繼續搜索最小鄰近值。當回溯到根節點時,此時的最小鄰近值就是最終的搜索結果。

    從上面的描述可以看出,KD樹在搜索路徑優化時使用的是兩點之間的距離來判斷,而球樹使用的是兩邊之和大於第三邊來判斷,相對來說球樹的判斷更加復雜,但是卻避免了更多的搜索,這是一個權衡。

KNN算法的擴展

    這裏我們再討論下KNN算法的擴展,限定半徑最近鄰算法。

    有時候我們會遇到這樣的問題,即樣本中某系類別的樣本非常的少,甚至少於K,這導致稀有類別樣本在找K個最近鄰的時候,會把距離其實較遠的其他樣本考慮進來,而導致預測不準確。為了解決這個問題,我們限定最近鄰的一個最大距離,也就是說,我們只在一個距離範圍內搜索所有的最近鄰,這避免了上述問題。這個距離我們一般稱為限定半徑。

    接著我們再討論下另一種擴展,最近質心算法。這個算法比KNN還簡單。它首先把樣本按輸出類別歸類。對於第 L類的Cl個樣本。它會對這Cl個樣本的n維特征中每一維特征求平均值,最終該類別所有維度的n個平均值形成所謂的質心點。對於樣本中的所有出現的類別,每個類別會最終得到一個質心點。當我們做預測時,僅僅需要比較預測樣本和這些質心的距離,最小的距離對於的質心類別即為預測的類別。這個算法通常用在文本分類處理上。

KNN算法小結

    KNN算法是很基本的機器學習算法了,它非常容易學習,在維度很高的時候也有很好的分類效率,因此運用也很廣泛,這裏總結下KNN的優缺點。

    KNN的主要優點有:

    1) 理論成熟,思想簡單,既可以用來做分類也可以用來做回歸

    2) 可用於非線性分類

    3) 訓練時間復雜度比支持向量機之類的算法低,僅為O(n)

    4) 和樸素貝葉斯之類的算法比,對數據沒有假設,準確度高,對異常點不敏感

    5) 由於KNN方法主要靠周圍有限的鄰近的樣本,而不是靠判別類域的方法來確定所屬類別的,因此對於類域的交叉或重疊較多的待分樣本集來說,KNN方法較其他方法更為適合

    6)該算法比較適用於樣本容量比較大的類域的自動分類,而那些樣本容量較小的類域采用這種算法比較容易產生誤分

    KNN的主要缺點有:

    1)計算量大,尤其是特征數非常多的時候

    2)樣本不平衡的時候,對稀有類別的預測準確率低

    3)KD樹,球樹之類的模型建立需要大量的內存

    4)使用懶散學習方法,基本上不學習,導致預測時速度比起邏輯回歸之類的算法慢

    5)相比決策樹模型,KNN模型可解釋性不強

    以上就是KNN算法原理的一個總結,希望可以幫到朋友們,尤其是在用scikit-learn學習KNN的朋友們。


參考文獻:統計學習方法(李航)

http://www.cnblogs.com/pinard/p/6061661.html

k近鄰算法(k-nearest neighbor,k-NN)