統計學習方法——K近鄰模型

0. 寫在前面

在這一講的討論班中,我們將要討論一下K近鄰模型。可能有人會說,K近鄰模型有什麼好寫的,那分明就是一個最簡單的機器學習模型,哦,不,連機器學習也算不上的算法吧。但是這裏,我想提醒的是,我們要討論的,不僅僅是簡單的K近鄰模型,而是和它相關的一些有困惑的話題。

1. K近鄰定義

k近鄰算法,也成爲KNN算法,是一種基本分類與迴歸算法。它在基本實現上,使用的是多數表決的惰性學習過程。也就是它實際上是基於記憶的學習方法。它並沒有學出一個什麼判別模型,其實也沒有像貝葉斯那樣算出一個新東西,而是簡單的統計距離目標點最近的K個節點裏數目最多的標籤賦予目標點。就是這麼一個簡單的算法。我們這裏給出一個最樸素的K近鄰算法:

K近鄰算法
輸入:訓練數據集T=(x1,y1),(x2,y2),...(xN,yN)T=(x1,y1),(x2,y2),...(xN,yN)T=(x1,y1),(x2,y2),...(xN,yN)T=(x1,y1),(x2,y2),...(xN,yN)T={(x_1,y_1),(x_2,y_2),...(x_N,y_N)}T=(x1​,y1​),(x2​,y2​),...(xN​,yN​)
輸出:實例x所屬的類y

算法步驟:
(1)根據給定的距離度量,在訓練集T中找出與x最近鄰的k個點,涵蓋這k個點的x的鄰域記作Nk(x)Nk(x)Nk(x)Nk(x)N_k(x)Nk​(x)
(2)在Nk(x)Nk(x)Nk(x)Nk(x)N_k(x)Nk​(x)中根據分類決策規則,如多數表決決定x的類別y。

1.1. k近鄰模型

k近鄰模型的核心就是使用一種距離度量,獲得距離目標點最近的k個點,根據分類決策規則,決定目標點的分類。

就是這麼三句話,決定了k近鄰模型的三個基本要素——距離度量、k值的選擇、分類決策規則。

1.2. 距離度量

一個點和一個點之間的距離,無論是什麼計算方式,基本上離不開LpLpLpLpL_pLp​距離。我們熟知的歐式距離,則是L2L2L2L2L_2L2​範式,也就是p=2的情況,而另一個很熟悉的距離曼哈頓距離,則是L1L1L1L1L_1L1​範式。LpLpLpLpL_pLp​距離的定義如下:
Lp(xi,xj)=(l=1nxi(l)xj(l)p)1pLp(xi,xj)=(l=1nxi(l)xj(l)p)1pLp(xi,xj)=(l=1nxi(l)xj(l)p)p1Lp(xi,xj)=(∑l=1n∣xi(l)−xj(l)∣p)1pL_p(x_i,x_j)=(\displaystyle\sum_{l=1}^{n}|x_i^{(l)}-x_j^{(l)}|^p)^{\frac{1}{p}}Lp​(xi​,xj​)=(l=1∑n​∣xi(l)​−xj(l)​∣p)p1​

當然,如果p→∞的時候,就叫做切比雪夫距離了。

除了這個閔可夫斯基距離集合外,還有另外的距離評估體系,例如馬氏距離、巴氏距離、漢明距離,這些都是和概率論中的統計學度量標準相關。而像夾角餘弦、傑卡德相似係數、皮爾遜係數等都是和相似度有關的。

因此,簡單說來,各種“距離”的應用場景簡單概括爲,空間:歐氏距離,路徑:曼哈頓距離,國際象棋國王:切比雪夫距離,以上三種的統一形式:閔可夫斯基距離,加權:標準化歐氏距離,排除量綱和依存:馬氏距離,向量差距:夾角餘弦,編碼差別:漢明距離,集合近似度:傑卡德類似係數與距離,相關:相關係數與相關距離。

這其實只是個度量標準而已,應當根據數據特徵選擇相應的度量標準。

1.3. k值的選擇

k值的選擇也很有必要,因爲k的選擇小了,則近似誤差會減小,但估計誤差會增大;相反k的選擇大了,則近似誤差會增大,估計誤差會減小。這一點,我們會在近似誤差與估計誤差那一部分進一步講解。

1.4. 分類決策規則

k近鄰的分類決策規則是最爲常見的簡單多數規則,也就是在最近的K個點中,哪個標籤數目最多,就把目標點的標籤歸於哪一類。

實際上,也是可行的,也是唯一可行的分類決策規則。無論是全體一致規則(一票否決制)還是絕對多數規則,都不能在任何時候對目標點做出確切的預測,更不用提少數原則這種不靠譜的決策規則了。

當然,這也是有理論依據的:
如果分類的損失函數爲0-1損失函數,則誤分類的概率是:
KaTeX parse error: Unknown accent ' ̸' at position 45: …)=1-P(Y=f(X))P(Y̸̲̲​=f(X))=1−P(Y=f…

也就是說誤分類率爲:

KaTeX parse error: Unknown accent ' ̸' at position 83: …_i=c_j)k1​∑I(yi​̸̲̲​=cj​)=1−k1​I(y…

要使得誤分類率最小,也就是經驗風險最小,就要使得1kI(yi=cj)1kI(yi=cj)k1I(yi=cj)1kI(yi=cj)\frac{1}{k}I(y_i=c_j)k1​I(yi​=cj​)最大,所以多數表決規則等價於經驗最小化。

其實,還可以使用權重加權的多數表決,對於K個最近點,根據其距離的遠近來進行加權統計,從而獲得一個折中的效果。本方法爲個人所想,不知有沒有實踐來論證。

2. 估計誤差與近似誤差

2.1. 估計誤差

估計誤差我們應該在初中或者高中物理的時候就已經學過了,也許只是忘記了而已。估計誤差主要包含四個部分:系統誤差、隨機誤差、過失誤差、精密度和精確度。

就我們K近鄰來講,如果K值比較小,那麼例如像噪點,錯誤的數據,不恰當的度量標準以及數據本身的缺陷等,都會很大程度上影響最終的結果,而如果K值比較大,那麼以上缺陷就會盡可能的平均,從而減小對最終結果的影響。

2.2. 近似誤差

近似誤差與估計誤差的描述對象不同,估計誤差度量的是預測結果與最優結果的相近程度,而近似誤差是度量與最優誤差之間的相似程度。就K近鄰算法來講,K值越小,那麼與目標點相近的點的標籤對於其目標點的影響也就越大,其標籤的一致性就越高,這樣近似誤差就會變小。

2.3. 兩者區別與聯繫

總而言之,近似誤差指的是目標點對於其原樣本點的可信度,誤差越小,對於原樣本點的信任度越高,也就是說,目標點可能只需要對最近的點確認一次就可以標註自己的標籤,而無需去詢問其他目標點。而估計誤差則是原模型本身的真實性,也就是說,該模型所表現出的分類特性,是不是就是真實的分類特性,比如有噪點影響,有錯誤數據記錄,或者本身數據分佈就不是很好,都會是影響估計誤差的因素,而詢問的點越多,那麼這些壞點對於目標點的標籤影響就越小。

這就像是你向別人徵求意見,你對於別人意見的採納率越高,則別人意見的近似誤差越小。而別人意見越符合實際情況,則估計誤差越小。這麼說應該有個大致的理解了吧。

3. K近鄰的實現kd樹

我們通過上述描述,應該清楚了一個K近鄰算法的基本運作思想,由於沒有訓練過程,沒有預測模型,使得K近鄰算法的計算量十分巨大,因爲它需要把所有的樣本點都和目標點進行一次距離度量,很難適應大規模的數據樣本。那麼kd樹就應運而生了。

3.1. kd樹定義

kd樹,指的是k-dimensional tree,是一種分割K維數據空間的數據結構,主要用於多維空間關鍵數據的搜索。kd樹是二進制空間分割樹的特殊情況。

索引結構中相似性查詢有兩種基本的方式:一種是範圍查詢,另一種是K近鄰查詢。範圍查詢就是給定查詢點和查詢距離的閾值,從數據集中找出所有與查詢點距離小於閾值的數據;K近鄰查詢是給定查詢點及正整數K,從數據集中找到距離查詢點最近的K個數據,當K=1時,就是最近鄰查詢。

而對於這類問題,解決辦法有兩類:一類是線性掃描法,即將數據集中的點與查詢點逐一進行距離比較,也就是窮舉,缺點很明顯,就是沒有利用數據集本身蘊含的任何結構信息,搜索效率較低,第二類是建立數據索引,然後再進行快速匹配。因爲實際數據一般都會呈現出簇狀的聚類形態,通過設計有效的索引結構可以大大加快檢索的速度。索引樹屬於第二類,其基本思想就是對搜索空間進行層次劃分。根據劃分的空間是否有混疊可以分爲Clipping和Overlapping兩種。前者劃分空間沒有重疊,其代表就是k-d樹;後者劃分空間相互有交疊,其代表爲R樹。

但是要說明的是kd樹的樸素用法,只能解決最近鄰算法,對於K近鄰算法還需要改進後才能夠使用,這裏我們放到最後再講。

3.2. kd樹的構造算法

構造kd樹的方法根據不同的決策規則分爲很多種,但最終都是平衡二叉樹。具體方法如下:

  1. 構造根節點,使根節點對應用於K維空間中包含所有實例點的超矩形區域。
  2. 通過下面的遞歸方法,不斷切分K維空間,生成子節點:
    1. 在超矩形區域上選擇一個座標軸和該座標上的一個切分點,確定一個超平面。

    2. 以經過該點且垂直於該座標軸做一個超平面,該超平面將當前的超矩形區域切分成左右兩個子區域,實例被分到兩個子區域。

  3. 該過程直到子區域內無實例時終止(終止時的節點爲子節點)。
    在此過程中將實例集合保存在相應的節點上。

在這個方法中,有兩個部分時可以進行調節的,第一個部分就是選取的維度的順序,另一個部分就是選取分割點的度量標準。

在第一部分,我們可以使用順序採樣,即從第1維,第2維,第n維一直到分割完畢爲止。也可以使用最大方差所在的維度,也可以使用維度主次優先級爲順序,以此等等。

在第二部分,我們可以使用的是所在維度的中位數作爲切分點,也可以使用中值作爲切分點,以此等等。

這裏,我們使用的是最樸素的方法,維度採用順序採樣,切分點選取中位數作爲切分點,來描述一下kd樹構造算法。

kd樹構造算法
輸入:k維空間數據集T = x1,x2,,xNx1,x2,,xNx1,x2,,xNx1,x2,…,xN{x_1,x_2, …, x_N}x1​,x2​,…,xN​,其中,xi=(xi(1),xi(2),,xi(k))i=1,2,,Nxi=(xi(1),xi(2),,xi(k))i=1,2,,Nxi=(xi(1),xi(2),,xi(k))i=1,2,,Nxi=(xi(1),xi(2),…,xi(k)),i=1,2,…,Nx_i = (x_i^{(1)}, x_i^{(2)},…, x_i^{(k)}),i = 1, 2, …, Nxi​=(xi(1)​,xi(2)​,…,xi(k)​),i=1,2,…,N
輸出:kd樹
開始:

  1. 構造根節點(根節點對應於包含T的K維空間的超矩形區域)
    選擇x(1)x(1)x(1)x(1)x^{(1)}x(1)爲座標軸,以T中所有實例的x(1)x(1)x(1)x(1)x^{(1)}x(1)座標的中位數爲切分點,這樣,經過該切分點且垂直與x(1)x(1)x(1)x(1)x^{(1)}x(1)的超平面就將超矩形區域切分成2個子區域。保存這個切分點爲根節點。

  2. 重複如下步驟:
    對深度爲j的節點選擇x(l)x(l)x(l)x(l)x^{(l)}x(l)爲切分的座標軸,KaTeX parse error: Expected 'EOF', got '&' at position 8: l=j(mod&̲ThickSpace;k)+1… ,以該節點區域中所有實例的x(l)x(l)x(l)x(l)x^{(l)}x(l)座標的中位數爲切分點,將該節點對應的超平面切分成兩個子區域。切分由通過切分點並與座標軸x(l)x(l)x(l)x(l)x^{(l)}x(l)垂直的超平面實現。保存這個切分點爲一般節點。

  3. 直到兩個子區域沒有實例存在時停止。

具體的例子大家可以看一下書,我們的重點不在於此。對於書上的例子,一句話概括爲:偶數層以第一維爲二分檢索樹,奇數層以第二維爲二分檢索樹。對於n個實例的k維數據來說,建立kd-tree的時間複雜度爲O(k×n×logn)。

而對於kd樹的插入刪除等不在我們這堂課的討論範圍內,大家可以課後自己查閱資料,因爲這方面比較複雜。

對於kd樹的插入來說,就相當於一個隨時改變比較維度的二叉檢索樹:在偶數層比較x座標值,而在奇數層比較y座標值。當我們到達了樹的底部,(也就是當一個空指針出現),我們也就找到了結點將要插入的位置。

這一部分感興趣的同學可以更深入的研究一下。

3.3. kd樹的檢索算法

既然已經建成了kd樹了,那麼kd樹的檢索算法就被提上議程,這次,我們使用的就是針對上面的kd樹構建算法而寫出的kd樹檢索算法:

kd樹最近鄰搜索算法
輸入:已構造的kd樹:目標點x;
輸出:x的最近鄰。

  1. 在kd樹中找出包含目標點x的葉結點:從根結點出發,遞歸的向下訪問kd樹。若目標點x當前維的座標小於切分點的座標,則移動到左子結點,否則移動到右子節點,直到子節點爲葉結點爲止。
  2. 以此葉節點爲“當前最近點”。
  3. 遞歸的向上回退,在每個結點進行以下操作:
    1. 如果該結點保存的實例點比當前最近點距離目標點更近,則以該實例點爲“當前最近點”。
    2. 當前最近點一定存在於該結點一個子結點對應的區域。檢查該子結點的另一子結點對應的區域是否有更近的點。
      具體的,檢查另一子結點對應的區域是否與以目標點爲球心,以目標點與“當前最近點”間的距離爲半徑的超球體相交。
      如果相交,可能在另一個子結點對應的區域內存在距離目標點更近的點,移動到另一個子結點,接着,遞歸地進行最近鄰搜索。
      如果不相交,向上回退。
  4. 當回退到根結點時,搜索結束,最後的“當前最近點”即爲x的最近鄰點。

這樣,其實只要把握住了這麼個幾個部分,首先,是當前最近點的初始值的確定,第二,如何回溯比較,第三,如何搜索可能存在的解。

總而言之,若實例點隨機分佈,則KD樹搜索的時間複雜度爲O(logN),N爲訓練實例數。就具體而言,KD樹更適用於訓練實例數遠大於空間維度的K近鄰搜索。一般是20維以下的,效果比較好。

4. 關於K近鄰算法的若干其他問題

關於K近鄰算法還有很多更加深入的問題,我們在下面進行簡要的討論,在以後有時間時,我們會針對某些具體的問題,做出專題講解。

4.1. K近鄰算法與K-means聚類算法的區別

K近鄰算法和K均值聚類算法看起來十分相似,不過還是有一些區別的,我們這裏給出一張表:

KNN K-Means
KNN是分類算法 K-Means是聚類算法
KNN是監督學習 K-Means非監督學習
沒有明顯的前期訓練過程 有明顯的前期訓練過程
K的含義指的是判斷依據來源個數 K的含義是集合的分類數目

而這兩者都用到了NN算法,一般使用kd樹來實現。

4.2. 如何使用kd樹來進行K近鄰查找

這道題是課後習題第三題,網上說通過維護一個包含 k 個最近鄰結點的隊列來實現,就我個人想法而言,實際上,主要是看這些隊列裏的值從何而來。我認爲,這些較近的點是來源於那些最近鄰點可能存在的點的集合中,也就是最近鄰點的父節點以及跨越了超球面的那些區域內的點及他們的父節點。

也就是說,只需要改動這麼幾個步驟,就是在與最近鄰點相比較的所有節點都可以存入到k近鄰隊列中,然後隊列未滿時,其最短距離爲∞,隊列已滿時,其最短距離爲隊列中最長的結點的距離。一旦新來的結點小於這個最長距離,則刪除最長結點,插入新來的結點,並且更新隊列的最短距離。

一般來講,如果k比較小,那麼常規kd樹檢索已經足夠查到K個近鄰點。但是如果發生了沒有找全k個最小的,可以在另一半的樹中查找剩下的近鄰點。

4.3. 課後習題3.1

課後題目3.1描述如下:

參照圖3.1,在二維空間中給出實例點,畫出k爲1和2時的k近鄰法構成的空間劃分,並對其進行比較,體會k值選擇與模型複雜度及預測準確率的關係。

我們不去考慮k爲1的情況,因爲k爲1的情況我們可以很容易從原圖中獲取,我們來考慮k=2時候的空間劃分。

我們都知道,在2維空間中,我們通常使用的是一條線來進行2分類,這也是最優的分類方式(每次減小樣本空間一半),那麼在這個題目中,如果k=2的時候,我們考慮最近的3個點開始,其實無論是多少都沒關係的,只不過時間複雜度比較大,但是我們通常不會選取過多的候選點。

現在,這條線就是2個點的連線的垂直平分線,如下圖所示:
2個點的圖片
爲了更清楚,我把圖片放大,以至於A,B點變成了圓,l爲AB兩點連線的垂直平分線。如圖上所標,這時候只能考慮k=1d的時候的劃分。一條垂直平分線可以把平面分成兩個部分,左邊紅色的部分都會被歸結爲離A點近,右邊的藍色部分都會被歸結於B點近。

那麼如果我們考慮三個點的k近鄰,如下圖所示:
三個點

如果K=1,那麼最終的分類就會是如此,藍色的點都是被歸於點A,紅色的點都歸於點B,紫色的點都歸於點C,但是如果是K=2的時候呢?K=2的時候,只需要把垂直平分線延長就可以了,如下圖:

三種顏色

爲了區分歸屬,我把三個點都標上了顏色,而被劃分的6個區域,其最近的2個點的顏色都在圖上標出,其實就是一個二維層面的三次切分,取其中最近的2個點。這樣就得到了空間劃分。

實際上4個點,5個點,n個點都是同樣的道理,這個算法不一定是最優的,但是是可以推廣到n個點的普適算法,而且又由於k的取值不會過大,因此不會造成大數災難。

你可能覺得很巧,爲什麼所有的垂直平分線都會交於一點,實際上,所有的凸多邊體都會有一個外接圓,那麼圓心到所有點的距離都相等,這就是所有邊的垂直平分線的焦點。但是對於凹多邊體,就沒有外接圓了,但是也不用擔心,空間中所有的部分都會被若干個垂直平分線所分割,只需要比較圍成這個區域的n個垂直平分線,然後再根據k的取值取前K個點即可。

這樣就解決了題目3.1。

4.4. kd樹的若干改進算法

但是事實上,即使我們上面的Kd樹可以完成k近鄰的查找,但是對於大數據來講,仍然是效率不夠的。

4.4.1. BBF算法

那麼一個最基本的改進就可以被提出了,那就是BBF(Best-Bin-First)查詢算法。這個算法是由發明sift算法的David Lowe在1997的一篇文章中針對高維數據提出的一種近似算法,此算法能確保優先檢索包含最近鄰點可能性較高的空間,此外,BBF機制還設置了一個運行超時限定。採用了BBF查詢機制後,kd樹便可以有效的擴展到高維數據集上。

BBF算法的改進思路爲:將“查詢路徑”上的結點進行排序,如按各自分割超平面(也稱bin)與查詢點的距離排序,也就是說,回溯檢查總是從優先級最高(Best Bin)的樹結點開始。

4.4.2. 球樹

僅僅在kd樹上進行BBF算法的改進,仍然還是不能夠避免一些結構本身存在的弊端,當處理不均勻分佈的數據集時便會呈現出一個基本衝突:既要求樹有完美的平衡結構,又要求待查找的區域近似方形,但不管是近似方形,還是矩形,甚至正方形,都不是最好的使用形狀,因爲他們都有角。

其實這個問題的實質是因爲,我們對於距離的度量使用的是圓形,也就是歐氏距離,如果是我們之前提到的像切比雪夫距離這種方形的,就可以在一定程度上減少這個衝突。因爲無論是你的模板和樣本,其度量標準是一致的,也就是要麼是方形的,都是方形的,要是圓形的,都是圓形的。
例如下面這個就是球樹:
在這裏插入圖片描述
從球中選擇一個離球的中心最遠的點,然後選擇第二個點離第一個點最遠,將球中所有的點分配到離這兩個聚類中心最近的一個上,然後計算每個聚類的中心,以及聚類能夠包含它所有數據點所需的最小半徑。這種方法的優點是分裂一個包含n個殊絕點的球的成本只是隨n呈線性增加。

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

5. 小結

在本次討論課上,我們對於K近鄰算法有了一個直觀的認識,並且針對一些特定的問題,我們也做了一些深入的瞭解和探究,但是這還遠遠不夠,一些問題我們仍然沒有展開來說,例如度量標準中的那些距離的具體表現形式,還有沒有給出k近鄰算法的一些實例,以及kd樹的數據結構和實際運行代碼。這些還需要大家在課後加以補充。好了,我們下期見。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章