k近邻算法与kd树的创建和搜索
hit2015spring晨鳧追風
歡迎關注我的博客:http://blog.csdn.NET/hit2015spring
k近鄰算法
是一種常用的監督學習的方法:給定測試樣本,基于某種距離度量找出訓練集中與其最靠近的k個訓練樣本,然后基于k個鄰居的信息來進行預測。通常:
分類任務中用投票,選擇k個樣本中出現最多的類別標記作為預測結果 回歸任務中:平均法 還可以基于距離的遠近進行加權平均或者加權投票,距離越近權重越大沒有顯示的訓練過程,訓練時間開銷為0,是一種懶惰學習
分類的結果與k的選擇和距離計算方式的選擇有關系
上圖可以看出二維空間中,距離的計算方式不同,包含的區域也是不相同的。故會影響結果
k值得選擇也會對結果產生影響,k值小的話,相當于用較小的鄰域中的訓練實例進行預測,學習的近似誤差會減小,只有與輸入實例較近的訓練實例才會對預測結果起作用,但是估計誤差會增大,意味著會產生過擬合。
kd樹的構建
實現k近鄰方法時,面臨一個計算速度的挑戰問題,當特征空間的維數非常大以及訓練數據非常大的時候,我們優化這個搜索的方法就顯得尤為重要了
一般方法:最簡單的是實現一個線性掃描,就是計算輸入的實例與每一個訓練實例之間的距離,訓練集很大的時候,計算會耗時很長,于是就出現了kd樹的這種方法。
構造kd樹的數學描述比較難懂:
輸入的是k維空間數據集T={x1,x2,?,xN},注意這里的k維指的是特征的維度是k維,即xi=(x(1)i,x(2)i,?,x(k)i),i=1,2,?,N
(1)開始:構造根結點,根結點對應于包含T的k維空間的超矩形區域.選擇x(1)為坐標軸,以T中所有的實例的x(1)坐標的中位數為切分點,將根結點對應的超矩形區域劃分為兩個子區域。切分由通過切分點并與坐標軸x(1)垂直的超平面實現。
由根結點生成深度為1的左右兩個子結點:左結點對應坐標x(1)小于切分點的子區域,右結點對應于坐標x(1)大于切分點的子區域,落在切分超平面的點保存在根結點
(2)重復:對深度為j的結點,選擇x(l)為切分的坐標軸,以該結點的區域內部所有的實例的x(l)坐標的中位數作為切分點,將該結點對應的矩形區域切分為兩個子區域。切分由通過切分點并與坐標軸x(l)垂直的超平面實現。
該結點生成左右兩個結點,左結點對應坐標x(l)小于切分點的子區域,右子結點對應坐標x(l)大于切分點的子區域。落在切分超平面上的實例點保存在該結點。
(3)直到兩個子區域沒有實例存在時停止。
直接通過一個例子來理解:
簡單的理解就是:每次選擇一個維度的特征,把該實例點劃分為兩個部分,一個大于中位數,一個小于中位數,中位數就保留在這個結點,其他的放到下一層中,繼續上面的過程。
當然了這里面的關鍵是怎么選取要切分那個維度呢?
最簡單的方法就是輪著來,即如果這次選擇了在第i維上進行數據劃分,那下一次就在第j(j≠i)維上進行劃分,例如:j = (i mod k) + 1。想象一下我們切豆腐時,先是豎著切一刀,切成兩半后,再橫著來一刀,就得到了很小的方塊豆腐。
可是“輪著來”的方法是否可以很好地解決問題呢?再次想象一下,我們現在要切 的是一根木條,按照“輪著來”的方法先是豎著切一刀,木條一分為二,干凈利落,接下來就是再橫著切一刀,這個時候就有點考驗刀法了,如果木條的直徑(橫截 面)較大,還可以下手,如果直徑較小,就沒法往下切了。因此,如果K維數據的分布像上面的豆腐一樣,“輪著來”的切分方法是可以奏效,但是如果K維度上數 據的分布像木條一樣,“輪著來”就不好用了。因此,還需要想想其他的切法。
如果一個K維數據集合的分布像木條一樣,那就是說明這K維數據在木條較長方向 代表的維度上,這些數據的分布散得比較開,數學上來說,就是這些數據在該維度上的方差(invariance)比較大,換句話說,正因為這些數據在該維度 上分散的比較開,我們就更容易在這個維度上將它們劃分開,因此,這就引出了我們選擇維度的另一種方法:最大方差法(max invarince),即每次我們選擇維度進行劃分時,都選擇具有最大方差維度。
最后再給一個例子看看:
運用kd樹查找
構建好了kd樹之后就是利用kd樹來進行最近鄰查找了:
(1)將查詢數據Q從根結點開始,按照Q與各個結點比較的結果向下訪問kd樹,直到查找到葉子結點。
就是把Q的k個特征,在每一個結點上面的維度k與對應的分割的值m(那個中位數)這樣向下走,就到了一個葉子結點,把Q與結點上面的數據進行計算距離,記做當前的最近鄰點P_point和最小距離P_dist。
(2)進行回溯操作,這個操作是為了找到離Q點更加近的最近鄰點。即判斷沒有被訪問的分支里面的點是否還具有更近的點。
如果Q與其父結點下的未被訪問過的分支之間的距離小于Dcur,則認為該分支中存在離P更近的數據,進入該結點,進行(1)步驟一樣的查找過程,如果找到更近的數據點,則更新為當前的“最近鄰點”Pcur,并更新Dcur
怎樣判斷未被訪問的樹的分支里面是否有離Q更近的點?
從幾何空間上來看,就是判斷以Q為中心center和以Dcur為半徑Radius的超球面(Hypersphere)與樹分支Branch代表的超矩形(Hyperrectangle)之間是否相交。
在實現中,在構造樹的過程中,記錄下每個子樹所在的分割維度k和分割值m,(k, m),Q與子樹的距離則為|Q(k) - m|。即這個距離和當前存的最小距離相比較,如果有比這個距離小,那就進去搜索,如果沒有那就往上面回溯。
就是理解為超球體和超平面是否相交
以上就是Kd-tree的構造過程和基于Kd-Tree的最近鄰查找過程。
下面用一個簡單的例子來演示基于Kd-Tree的最近鄰查找的過程。
數據點集合:(2,3), (4,7), (5,4), (9,6), (8,1), (7,2) 。
已建好的Kd-Tree:
假設我們的k-d tree就是上面通過樣本集{(2,3), (5,4), (9,6), (4,7), (8,1), (7,2)}創建的。
我們來查找點(2.1,3.1),在(7,2)點測試到達(5,4),在(5,4)點測試到達(2,3),然后search_path中的結點為<(7,2), (5,4), (2,3)>,從search_path中取出(2,3)作為當前最佳結點nearest, dist為0.141;
然后回溯至(5,4),以(2.1,3.1)為圓心,以dist=0.141為半徑畫一個圓,并不和超平面y=4相交,如下圖,所以不必跳到結點(5,4)的右子空間去搜索,因為右子空間中不可能有更近樣本點了。
于是在回溯至(7,2),同理,以(2.1,3.1)為圓心,以dist=0.141為半徑畫一個圓并不和超平面x=7相交,所以也不用跳到結點(7,2)的右子空間去搜索。
至此,search_path為空,結束整個搜索,返回nearest(2,3)作為(2.1,3.1)的最近鄰點,最近距離為0.141。
參考文章
參考文章
福利答謝大家!
感謝您閱讀本篇文章,對此特別發放一個無門檻的現金紅包,打開支付寶掃碼領取!
總結
以上是生活随笔為你收集整理的k近邻算法与kd树的创建和搜索的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: grub4dos linux live,
- 下一篇: C# 读写视频文件