knn基礎與優化1--kd-tree

KNN

KNN(K-Nearest Neighbours),k最近鄰算法,是一個基於距離的有監督算法,常被用於分類問題的算法,它也可以用於迴歸問題。所謂k最近鄰,就是k個最近的鄰居的意思,說的是每個數據點都可以用它最接近的k個鄰居數據點來代表。當用於分類時,用k個最近鄰居所屬類別的多數做預測結果;當用於迴歸時,用k個最近鄰居對應標籤的平均值來表示預測結果。knn算法雖然簡單,但在數據量較大時,效果還是相當不錯的。

注意事項:

  • k值的選取:k值是需要預先設定的;選小了(極端k=1),數據噪音將會對結果有很大的影響,容易欠擬合;選大了,則預測耗時會很大;實際應用是需要折中效果和耗時進行考慮。
  • 樣本數量:很明顯,在應用knn進行分類時,需要注意各類別樣本數量都不要太少、而導致小樣本類別的數據很容易被淹沒了,否則k個最近鄰居基本都不會屬於小樣本類別,對效果會有很大影響;在這種情況下,可以考慮對樣本進行加權,來緩解樣本不均衡的問題。

雖然knn可以暴力實現,就是每預測一個樣本,就計算其與每個訓練樣本的距離,找到k個最近鄰居,但複雜度O(nd)太高,爲了提高kNN搜索的效率、加快預測時的速度,可以考慮使用特殊的結構存儲訓練數據,以減少計算距離的次數,便出現了kd-tree與ball-tree。

kd-tree

kd-tree (K-dimension tree) 是一種對k維空間中的實例點進行存儲以便對其進行快速檢索的樹形數據結構。kd樹是是一種二叉搜索樹,表示對k維空間的一個劃分;構造kd樹時,每次選擇一個維度和分割點將數據分成一大一小兩部分,相當於不斷地用垂直於座標軸的超平面將K維空間切分,構成一系列的超矩形空間區域。kd樹的每個結點對應於一個超矩形空間區域,每個非葉子節點都在分割超平面上。利用kd樹可以省去對大部分數據點的搜索,從而減少搜索的計算量。
kd-tree構建過程中,涉及兩個問題:維度如何選取?分割點如何選取?這兩個問題都可以歸到同一個目標,即選取的值要讓構造出來的樹深儘可能的小,即樹儘可能平衡。

問題1:維度如何選取?選取方差最大的那個維度,能使數據空間劃分得更加均勻;但由於這樣計算量比較大,一般多使用輪流選擇每個維度進行劃分的方法。

問題2:分割點如何選取?很明顯,選擇中位數,均分數據,左邊一半,右邊一半。

kd-tree構建的示例圖(引用自:https://blog.csdn.net/zhaomengszu/article/details/78103646

在訓練階段構建好kd-tree後,如何使用kd-tree進行knn搜索較爲關鍵;簡單起見,先闡述k=1時的搜索過程:

  1. 找到待預測樣本在kd-tree中所屬的葉子節點;
    1. 計算樣本與當前節點的距離,如小於最近距離d0,則更新最小距離、更新最近點爲當前節點;
    2. 計算與(當前節點的父節點所在的)分割超平面的距離d_1 = |X_t^{k}-X_{p_i}^k|,其中X_{p_i}表示當前節點的父節點,k表示其分割維度;
    3. 若d0<d1,即以樣本點爲球心、d0爲半徑的球空間沒有與分割超平面相交,則當前節點的兄弟節點所對應的區域中的數據點距離一定比d0大,即最近點一定不會出現其兄弟節點對應的區域中;反之,則當前節點的兄弟節點所對應的區域中可能有數據點的距離比當前d0小,移動到兄弟節點,遞歸進行最近鄰搜索
  2. 移動到父節點,重複過程1.1~1.3;
  3. 重複步驟2,直至回退到根結點時,搜索結束,輸出結果。

以上圖中的kd-tree爲例,搜索點(3,4.5)的最近鄰,過程如下:找到對應的葉子節點(4,7),與其距離爲2.69,大於與父節點(5,4)所在分割超平面的距離0.5;移動到兄弟節點(2,3),計算距離爲1.8,更新最近鄰;移動到節點(5,4),計算距離2.06>1.8,不更新最近鄰,計算與父節點(7,2)所在分割超平面的距離4>1.8,不搜索兄弟節點;移動到節點(7,2),計算距離4.72>1.8,不更新最近鄰,結束;返回最近鄰(2,3)。

k>1的情況相似,具體如下:

  1. 找到待預測樣本在kd-tree中所屬的葉子節點;
    1. 計算樣本與當前節點的距離,如小於第k個最近距離d_{0,k},則更新k個最近鄰以及相應的距離(可使用大頂堆來維護k最近鄰);
    2. 計算與(當前節點的父節點所在的)分割超平面的距離d_1 = |X_t^{k}-X_{p_i}^k|,其中X_{p_i}表示當前節點的父節點,k表示其分割維度;
    3. d_{0,k} < d_1,即以樣本點爲球心、d0爲半徑的球空間沒有與分割超平面相交,則當前節點的兄弟節點所對應的區域中的數據點距離一定比d_{0,k}大,即其兄弟節點對應區域中的數據點一定不會成爲k個最近鄰中的一員;反之,則當前節點的兄弟節點所對應的區域中可能有數據點的距離比當前d_{0,k}小,即可能有數據點會成爲k個最近鄰中的一員,移動到兄弟節點,遞歸進行最近鄰搜索
  2. 移動到父節點,重複過程1.1~1.3;
  3. 重複步驟2,直至回退到根結點時,搜索結束,輸出結果。

 

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