K近鄰(k-Nearest Neighbor,KNN)算法,一種基於實例的學習方法

1. 基於實例的學習算法

0x1:數據挖掘的一些相關知識脈絡

本文是一篇介紹K近鄰數據挖掘算法的文章,而所謂數據挖掘,就是討論如何在數據中尋找模式的一門學科。算法

其實人類的科學技術發展的歷史,就一直伴隨着數據挖掘,人們一直在試圖中數據中尋找模式,數據庫

  • 獵人在動物遷徙的行爲中尋找模式
  • 農夫在莊稼的生長中尋找模式
  • 政客在選民的意見上尋找模式
  • 戀人在對方的反應中尋找模式
  • 企業家的工做是要辨別出機會,尋找出那些能夠轉變爲有利可圖的生意的行爲中的一些模式,也即所謂的成功的模式,而且利用這些機會
  • 科學家的工做是理解數據,從數據中尋找模式,並用它們來指導在真實世界中如何運做

所謂數據挖掘,本質上就是經過分析存在於數據庫裏的數據來解決問題,數據挖掘被定義爲找出數據中的模式的過程,這個過程必須是自動的或半自動的數據結構

接下來的問題就是,如何表示數據模式app

有價值的數據模式可以讓咱們對新數據作出非凡的預測,表示一個數據模式有兩種極端的方法:機器學習

  • 一種是內部結構很難被理解的黑匣子
  • 一種是展現模式結構的透明結構,它的結構揭示了模式的結構

兩種方法可能均可以作出好的預測,它們的區別在於被挖掘出的模式可否以結構的形式清晰地表現,這個結構是否經得起分析,理由是否充分,可否用來造成將來的決策ide

若是模式可以以顯而易見的方法得到決策結構,就稱爲結構模式(structural pattern),換句話說,結構模式可以幫助解釋有關數據的一些現象,具有可解釋性。函數

更進一步地,機器學習從數據中挖掘結構模式的過程,稱爲知識表達,機器學習所能發現的模式有許多不一樣的表達方式,每一種方式就是一種推斷數據輸出結構的技術,包括:工具

  • 表(table):所謂表,就是採用與輸入相同的形式,完整存儲全部的輸入數據。這是機器學習輸出結構的最簡單、最基本的方法,它本質上等於一種存儲與搜索技術
  • 迴歸表(regression table):線性迴歸模型就是一種迴歸表,迴歸表的核心目標是如何進行特徵選擇,造成一個比原始數據集更小的、扼要的決策表,關鍵問題是肯定去除哪些屬性而不會影響最終的決策
  • 決策表(decision table):決策樹模型就是一種決策表
  • 實例表(instance table):本文要介紹的K近鄰就是一種基於實例的學習算法,它在傳統表的基礎上進行了優化,有效縮減了須要存儲和開銷以及優化了搜索效率

0x2:什麼是基於實例的學習算法?

瞭解了前因後果的知識脈絡以外,咱們將視野縮小到」基於實例的機器學習「這個領域內。學習

在基於實例的學習中,訓練樣本被一字不差地保存,而且使用一個距離函數來斷定訓練集中的哪一個實例與一個未知的測試實例最靠近。一旦找到最靠近的訓練實例,那麼最靠近實例所屬的類就被預測爲測試實例的類。測試

基於實例的算法,有時也稱爲基於記憶的學習,它不是明確概括機率分佈或者分界面,而是將新的問題例子與訓練過程當中見過的例子進行對比,這些見過的例子就在存儲器中。

Relevant Link:

《數據挖掘 實用機器學習工具與技術》Ian H.Witten Eibe Frank,Mark A.Hall

 

2. 從有效尋找最近鄰問題提及

咱們先來看下面這張圖,

假設咱們如今的目標是尋找圖中離綠色點最近的實例。這個問題的答案彷佛是顯而易見的,很顯然是右下方向的紅色三角。

可是咱們只要對題目稍加改造,例如將空間維數從2維擴展到100維,圖上的點密度增長10倍,這個時候,答案還依然明顯嗎?顯然不是了!

最直觀的想法是,咱們須要建一張表(table),將圖中全部的數據點的座標都保存起來,例如:

x1 ...... xn
A 1 ...... 2
..      
N 5 ...... 3

這樣,每輸入一個新的點時,咱們就遍歷一遍整張表,根據必定的距離函數(例如歐氏距離)找出距離最近的1個或k個實例。

這個場景在現實中是很是常見的需求,例如:

  • 類似文本發現
  • 類似性聚類
  • 目標分類
  • ..... 

儘管上面描述的查表法很是簡單且有效,可是缺點是速度很是慢。這個過程與訓練實例的數量成線性關係,換句話說,就是一個單獨的預測所花費的時間與訓練實例的數量成比例關係。處理整個數據集所花費的時間與訓練集實例數量O(train)和測試集實例數量O(test)的乘積成正比。

如何解決這個關鍵矛盾呢?學者們從數據結構優化上入手,提出了一系列的高效數據結構與搜索算法,它們合稱爲K近鄰算法,K近鄰算法要解決的最核心問題就是如何有效尋找到最近鄰的實例集,支撐這種搜索的結構就是一種知識表達。咱們接下來來討論它。

 

3. K近鄰法(k-nearest neighbor KNN)算法介紹

K近鄰法(k-nearest neighbor KNN)是一種數據驅動(基於實例的算法(Instance-based Algorithms))的分類迴歸方法。它屬於一種判別模型。

0x1:適用場景

1. 多分類問題場景

在多分類問題中的k近鄰法,k近鄰法的輸入爲實例的特徵向量,對應於特徵空間的點,輸出爲實例的類別。

k近鄰法假設給定一個訓練數據集,其中的實例類別已定,分類時,對新的實例,根據其k個最近鄰的訓練實例的類別,經過多數表決等方式進行預測。所以,k近鄰法不具備顯示的學習過程(或者說是一種延遲學習),k近鄰法實際上利用訓練數據集對特徵向量空間進行劃分,並做爲其分類的「模型」。

2. 迴歸問題的場景

KNN算法不只能夠用於分類,還能夠用於迴歸。經過找出一個樣本的k個最近鄰居,將這些鄰居的屬性的平均值賦給該樣本,就能夠獲得該樣本的屬性。

更有用的方法是將不一樣距離的鄰居對該樣本產生的影響給予不一樣的權值(weight),如權值與距離成正比。

0x2:算法模型

輸入訓練數據集,其中爲實例的特徵向量,爲實例的類別。

根據給定的距離度量,在訓練集中找出與 x 最鄰近的 K(須要人工設定調參) 個點,在由這 K 個點組成的鄰域中根據分類決策規則決定 x 的類別 y

K近鄰法的特殊狀況是k=1的情形,稱爲最近鄰算法,即對於輸入的實例點(特徵向量)x,最近鄰法將訓練數據集中與x最鄰近的類做爲x的類。

Y = P(y | x):這裏機率函數P指某種最小化距離斷定公式

能夠看到,K近鄰法沒有顯示的學習過程,做爲判別模型的一種,k近鄰法的判別函數的具體形式也不是很明顯。

K近鄰法使用的模型實際上對應於特徵空間的劃分,某種意義上來講,k近鄰的模型就是樣本特徵空間自己。

在k近鄰法中,當下列基本要素:

  • 訓練集
  • 距離度量
  • k值
  • 分類決策規則

肯定後,對於任何一個新的輸入實例,它所屬的類惟一地肯定。這至關於根據上述基本要素將特徵空間劃分爲一些子空間,肯定子空間裏的每一個點所屬的類。

特徵空間中,對每一個訓練實例點x1,距離該點比其餘點更近的全部點組成一個區域,叫做單元(cell)。每一個訓練實例點擁有一個單元,全部訓練實例點的單元構成對特徵空間的一個劃分:

K近鄰很好地體現了判別式模型的思想,k近鄰不生成機率分佈函數,它只是經過三個基本要素儘量地「捕捉」訓練樣本中的機率密度特徵。之因此輸入樣本會被分到不一樣的類別,其本質就在於在訓練樣本中存在不均勻的機率密度分佈,即某一個區域某一個類別密度佔比比其餘的類多。

下面咱們來具體談談K近鄰模型的幾個基本要素。

1. K值選擇

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

  • 若是選擇較小的K值,就至關於用較小的鄰域中的訓練實例進行預測
    • 「學習」的近似偏差(approximation error)會減小,只有與輸入實例較近的(類似的、Lp距離較小的)訓練實例纔會對預測結果起做用
    • 但缺點是「學習」的估計偏差(estimation error)會增大,預測結果會對近鄰的實例點很是敏感,若是近鄰的實例點恰巧是噪聲,預測就會出錯,能夠理解爲模型的容錯性較差
    • 換句話說,k值的減少就意味着總體模型變得複雜(由於搜索範圍小了,因此總的須要的搜索結果的存儲單元就變多了),容易發生過擬合。
  • 若是選擇較大的K值,就至關於用較大鄰域中的訓練實例進行預測
    • 優勢是能夠減小學習的估計偏差,即不容易受到近鄰點的波動影響
    • 但缺點是學習的近似偏差會增大,這時與輸入實例較遠的(不類似的)訓練實例也會對預測其做用,使預測發生錯誤
    • 整體來講,K值的增大就意味着總體模型變得簡單

近似偏差估計偏差的核心區別在因而假設臨近點的噪音擾動比較多仍是遠點的噪音擾動比較多。

在實際應用中,K值通常選取一個比較小的數值,即咱們基本上認爲近鄰點的相關性是比較大的,而原點的相關性比較小

在實際項目中,K值的選擇和樣本中的機率密度分佈有關,並無一個定式的理論告訴我麼該選什麼樣的K值,好在的是這個K值的搜索空間並非很大,一般咱們能夠採起一個for循環交叉驗證來搜索全部可能的K值,經過重複進行屢次實驗,每次隨機選取不一樣的train set和validate set,查看KNN模型對train set和validate set的擬合和泛化能力來選擇一個最好的K值。

理論上分析

理論上說,當 k 和實例的數量 n 都變成無窮大,使得 k/n -> 0 時,那麼在數據集上產生的偏差機率將達到理論上的最小值

2. 距離度量

特徵空間中兩個實例點的距離是兩個實例點類似程度的一種數字化度量。

K近鄰模型的特徵空間通常是n維實數向量空間,計算兩個向量之間的距離有不少種方法,注意這不是KNN獨有的算法,向量間距離模型是數學中的基礎概念:

設特徵空間是n維實數向量空間

的Lp距離定義爲:

1)P = 1:曼哈頓距離(Manhattan distance)

2)P = 2:歐式距離(Euclidean distance)

3)P = 正無窮:各個座標距離的最大值

下圖給出了二維空間中p取不一樣值時,與原點的Lp距離爲1(Lp = 1)的點的集合圖形

這張圖很好地說明了取不一樣的距離策略對於KNN對於緊鄰點的搜索範圍是不一樣的,進而影響隨後的判別分類結果

舉一個例子說明由不一樣的距離度量所肯定的最近鄰點是不一樣的。已知二維空間的3個點,咱們來對比一下在p取不一樣的值時,Lp距離下X1的最近鄰點

P值 和X2距離 和X3距離
1 4 6
2 4 4.24
3 4 3.78
4 4 3.57

能夠看到,p = 1/2時,X2是X1的最近鄰點;P >= 3,X3是X1的最近鄰點。

3. 分類決策規則

近鄰法中的分類決策規則每每是多數表決,即由輸入實例的k個臨近的訓練實例中的多數的label決定輸入實例的類。當K=1時算法退化爲最近鄰搜索。

多數表決規則(majority voting rule)本質也是最優化技術,它符合極大似然估計原則。

咱們假設分類的損失函數爲0-1損失函數爲:

那麼誤分類的機率是:

對給定的實例,其最近鄰的 k 個訓練實例點構成集合,若是涵蓋的區域的類別是Cj,那麼誤分類率是:

要使誤分類率最小,即經驗風險最小,就要使下式最大:

即模型對訓練樣本的預測準確度(擬合程度)最大。因此多數表決規則等價於經驗風險最小化。

0x3:學習策略

KNN的學習策略很簡單,就是在訓練集中尋找最近鄰的K個實例點,並進行voting,選擇最多類別的那個,即經驗風險最小化。這一樣體現了極大似然估計的核心思想。

0x4:學習算法

KNN的策略很是直觀易理解,算法要解決是具體的工程化問題,即如何在高維空間中選出 k 個近鄰點,當維度很高且樣本量很大的時候,若是不採起一些高效的算法而直接暴力搜索的話是很是耗時的。

解決該問題的思路就是利用特殊構造的存儲數據結構以及特殊的搜索方法來完成,這也是本文的重點討論部分。

最早被提出的一種數據結構是樹結構,經過應用分治思想,樹結構將原始的O(N)複雜度下降爲O(logN)複雜度,咱們接下來來討論它。

1. KD樹(kd tree)結構

KD樹是一種對K維空間中的實例點進行存儲以便對其進行快速檢索的樹形數據結構。kd樹是一個二叉樹,一棵KD樹就是一個超平面,表示對K維空間的一個劃分(partition)。構造KD樹至關於不斷地用垂直於座標軸的超平面將K維空間切分,構成一系列的K維超矩形區域。KD樹的每一個結點對應於一K維超矩形區域。

這裏K是數據集屬性的數量。

下圖展現了一個k=2的小例子:

 

樹不必定會發展到相同的深度,訓練集中的每個實例與樹中的一個結點相對應,最多一半的結點是葉子節點。

2. 構建KD樹

輸入:k維空間數據集(樣本數量是N),每一個樣本的維度是k,

  • 構造根節點,根節點對應於K維空間中包含全部實例點的超矩形區域
  • 選擇爲座標軸,以數據集T中全部實例的座標的中位數作 i 爲切分點,將根節點對應的超矩形區域切分爲兩個子區域,切分由經過切分點並與座標軸垂直的超平面實現。由根節點生成深度爲 1 的左,右子節點
    • 左子結點對應座標小於切分點的子區域
    • 右子節點對應於座標大於切分點的子區域
  • 重複上述分裂過程,對深度爲 j 的結點,選擇爲切分的座標軸,(取模循環不斷根據每一個維度進行二叉切分),以該節點的區域中全部實例的座標的中位數做爲切分點,將該結點對應的超矩形區域切分爲兩個子區域。切分由經過切分點並與座標軸垂直的超平面實現。由該結點生成深度爲 j + 1 的左、右子節點:
    • 左子節點對應座標小於切分點的子區域;
    • 右子節點對應座標大於切分點的子區域;
    • 將恰好落在切分超平面上的實例點保存在該結點
  • 直到兩個子區域沒有實例存在時中止(即全部實例點都被分到某個子空間中),從而造成KD樹的區域劃分,最後一次切分獲得的左、右子矩形空間就是葉節點

用一個例子來講明kd樹構造過程 ,給定一個二維空間的數據集:

  • 根節點對應包含數據集 T 的超矩形區域
  • 選擇軸,6個數據點的座標的中位數是7,以平面將空間分爲左、右量子子矩形(子結點)
  • 接着,左矩形的第二個維度的中位數是4,因此以再分爲兩個子矩形;右矩形以分爲兩個子矩形
  • 繼續切分,直到全部的實例點都被分到一個超平面上,所切出的空間是一個不包含任何實例點的純超矩形空間爲止,最後一次切分獲得的左、右子矩形空間就是葉節點

3. KD樹更新

與其餘大部分機器學習方法相比,基於實例學習的一個優點是新的實例能夠在任什麼時候候加入到訓練集裏。

新的數據來臨時,須要用新的數據點判斷其屬於哪一個葉子節點,而且找出葉子節點的超矩形。若是超矩形爲空,就將新數據點放置在那裏,不然分裂超矩形,分裂在最長的邊上進行,以保持方形。

這種簡單的探索式方法並不能保證在加入一系列點後,樹依然會維持平衡,也不能保證爲搜索最近鄰塑造良好的超矩形。有時候從頭開始重建數不失爲一個良策。例如,當樹的深度達到最合適的深度值的兩倍時。

4. 搜索KD樹

完成了KD樹建樹後,接下來討論如何利用KD樹進行高效K近鄰搜索:

輸入:根據train set構造的kd樹;目標點x
輸出:x的最近鄰

  • 在KD樹中找出包含目標點x的葉節點:從根節點出發,遞歸地向下訪問KD樹,若目標點x當前維的座標小於切分點的座標,則移動到左子結點,不然移動到右子節點,直到子節點爲葉子節點(某個不含訓練實例的超矩形區域)爲止
  • 包含目標點的葉節點對應包含目標點的最小超矩形區域,以此葉節點的實例暫時做爲「當前最近點「,注意這裏說暫時是由於不必定該葉節點的實例點就真的是最近鄰點了,理論上目標點的最近鄰必定在以目標點爲中心而且圓周經過當前最近點的超球體內部(局部最優原理),接下來的逆向回溯的目的就是嘗試尋找在這個超球體區域內是否還存在其餘葉節點內的實例點比「當前最近點」更近
  • 以此葉節點爲"當前最近點"遞歸的向上回退,在每一個結點(父節點)進行如下操做:重複此過程,依次回退到根節點,搜索結束,最後查看存儲的"當前最近點"即爲x的最近鄰點
    • 若是該結點保存的實例點比當前最近點距離目標點更近,則已該實例點爲"當前最近點"
    • 若是該結點的另外一子結點的超矩形區域與超球體相交(可能存在另外一個局部最優),那麼在相交的區域內尋找與目標點更近的實例點。若是存在這樣的點,將此點做爲新的當前最近鄰點,算法轉到更上一級的父節點
    • 若是父節點的另外一個子結點的超矩形區域與超球體不相交,說明另外一個分支不存在另外一個局部最優,則繼續該分支的逆向回溯
  • 在回退的過程當中,不斷查找與目標點最鄰近的結點,當肯定不存在更近的結點時終止。這樣搜索就被限制在空間的局部區域上,效率大爲提升了(這也是二叉樹的核心思想 - 分而治之)

用下圖來講明kd樹的搜索過程,根節點爲A,子節點是B,C,D,E,F,G;目標實例點S,求S的最近鄰

  • 首先在KD樹中正向搜索,定位到最右下角那個矩形區域,隨後開始逆向回溯過程
  • 該矩形區域的實例點是D,因此暫時以D做爲近似最近鄰。可是理論上最近鄰必定在以點S爲中心經過點D的圓的內部(局部最優),所以須要繼續逆向回溯 
  • 而後返回節點D的父節點B,在節點B的另外一子結點F的區域內嘗試搜索,可是由於節點F的區域與超圓不相交,不可能有最近鄰點
  • 繼續返回上一級父節點A,在節點A的另外一子節點C的區域內嘗試搜索,結點C的區域與圓相交,在超矩形區域在園內的實例點有點E,點E比點D更近,所以成爲新的最近似點
  • 最後獲得點E是點S的最近鄰

5. KD樹面臨的挑戰和困境

咱們已經看到,KD樹是可用於有效尋找最近鄰的良好數據結構,可是,並不完美。當面對不均勻數據的數據集時,便面臨一些基本衝突和挑戰:

  • 既要求樹有完美的平衡結構,又要求區域近似方形
  • 更重要的是,矩形、正方形都不是最好的使用形狀,緣由是它們都有角。處於邊界附近的實例點的近鄰搜索不太」柔和「,矩形的角是一個很難處理的問題

這裏所謂的平衡結構,就是指樹的兩邊分叉要儘可能分佈平均,這樣能夠最大程度地發揮O(logN)的優化效果,可是若是數據點的分佈很是不均衡,採用中值的方法也許會在同一個方向上產多屢次後續分裂,從而產生瘦長型的超矩形。一個更好的解決方法是採用平均值做爲分裂點而不是中位值。這樣產生的KD樹會更趨向於方形。

可是均值分裂點技術依然沒法徹底規避KD原生的問題,爲此,學界提出了超球分界面代替超矩形分界面的改進方法。

6. Ball Tree搜索

KD tree的思想很是精妙,可是也存在一些問題, 形並非用到這裏最好的方式。偏斜的數據集會形成咱們想要保持樹的平衡與保持區域的正方形特性的衝突。另外,矩形甚至是正方形並非用在這裏最完美的形狀,因爲它的角。爲了解決這些問題,引入了ball tree,即便用超球面而不是超矩形劃分區域

Ball Tree就是一個K維超球面來覆蓋訓練樣本點。

上圖(a)顯示了一個2維平面包含16個觀測實例的圖,圖(b)是其對應的ball tree,其中結點中的數字表示包含的觀測點數。

樹中的每一個結點對應一個圓,結點的數字表示該區域保含的觀測點數,但不必定就是圖中該區域囊括的點數,由於有重疊的狀況,而且一個觀測點只能屬於一個區域。實際的ball tree的結點保存圓心和半徑。葉子結點保存它包含的觀測點。

1)構造ball tree

Ball tree的建樹過程和KD tree大致上一致,區別在於ball tree每次的切分點都是當前超球體的圓心。

  • 選擇一個距離當前圓心最遠的觀測點 i1,和距離i1最遠的觀測點 i2
  • 將圓中全部離這兩個點最近的觀測點都賦給這兩個簇的中心
  • 而後計算每個簇的中心點和包含全部其所屬觀測點的最小半徑,這樣,左、右子節點又分裂成了新的超球體。

2)搜索ball tree

使用Ball tree時:

  • 先自上而下找到包含target的葉子結點,今後結點中找到離它最近的觀測點。這個距離就是最近鄰的距離的上界。
  • 檢查它的兄弟結點中是否包含比這個上界更小的觀測點,和KD tree同樣,檢查的標準就是兄弟的超球體和當前結點的超球體是否有交集
    • 若是沒有交集,則這個兄弟結點不可能包含「更近鄰點」
    • 若是有交集,則繼續搜索兄弟節點

Relevant Link:

http://blog.csdn.net/pipisorry/article/details/53156836
相關文章
相關標籤/搜索