决策树:特征分布空间划分方法
前言:懶惰的原因是因為時間太少,不能夠去仔細的探索學習,拿來主義喪失了很多快樂!
K近鄰算法的實現:KD樹
原文鏈接:http://blog.csdn.net/v_july_v/article/details/8203674/
2.0、背景
? ?? 之前blog內曾經介紹過SIFT特征匹配算法,特征點匹配和數據庫查、圖像檢索本質上是同一個問題,都可以歸結為一個通過距離函數在高維矢量之間進行相似性檢索的問題,如何快速而準確地找到查詢點的近鄰,不少人提出了很多高維空間索引結構和近似查詢的算法。
? ? 一般說來,索引結構中相似性查詢有兩種基本的方式:
? ? 同樣,針對特征點匹配也有兩種方法:
- 最容易的辦法就是線性掃描,也就是我們常說的窮舉搜索,依次計算樣本集E中每個樣本到輸入實例點的距離,然后抽取出計算出來的最小距離的點即為最近鄰點。此種辦法簡單直白,但當樣本集或訓練集很大時,它的缺點就立馬暴露出來了,舉個例子,在物體識別的問題中,可能有數千個甚至數萬個SIFT特征點,而去一一計算這成千上萬的特征點與輸入實例點的距離,明顯是不足取的。
- 另外一種,就是構建數據索引,因為實際數據一般都會呈現簇狀的聚類形態,因此我們想到建立數據索引,然后再進行快速匹配。索引樹是一種樹結構索引方法,其基本思想是對搜索空間進行層次劃分。根據劃分的空間是否有混疊可以分為Clipping和Overlapping兩種。前者劃分空間沒有重疊,其代表就是k-d樹;后者劃分空間相互有交疊,其代表為R樹。
? ? 而關于R樹本blog內之前已有介紹(同時,關于基于R樹的最近鄰查找,還可以看下這篇文章:http://blog.sina.com.cn/s/blog_72e1c7550101dsc3.html),本文著重介紹k-d樹。
? ? 1975年,來自斯坦福大學的Jon Louis Bentley在ACM雜志上發表的一篇論文:Multidimensional Binary Search Trees Used for Associative Searching 中正式提出和闡述的了如下圖形式的把空間劃分為多個部分的k-d樹。
2.1、什么是KD樹
? ? Kd-樹是K-dimension tree的縮寫,是對數據點在k維空間(如二維(x,y),三維(x,y,z),k維(x1,y,z..))中劃分的一種數據結構,主要應用于多維空間關鍵數據的搜索(如:范圍搜索和最近鄰搜索)。本質上說,Kd-樹就是一種平衡二叉樹。
? ? 首先必須搞清楚的是,k-d樹是一種空間劃分樹,說白了,就是把整個空間劃分為特定的幾個部分,然后在特定空間的部分內進行相關搜索操作。想像一個三維(多維有點為難你的想象力了)空間,kd樹按照一定的劃分規則把這個三維空間劃分了多個空間,如下圖所示:
2.2、KD樹的構建
? ? kd樹構建的偽代碼如下圖所示:
? ? 再舉一個簡單直觀的實例來介紹k-d樹構建算法。假設有6個二維數據點{(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)},數據點位于二維空間內,如下圖所示。為了能有效的找到最近鄰,k-d樹采用分而治之的思想,即將整個空間劃分為幾個小部分,首先,粗黑線將空間一分為二,然后在兩個子空間中,細黑直線又將整個空間劃分為四部分,最后虛黑直線將這四部分進一步劃分。
? ? 6個二維數據點{(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)}構建kd樹的具體步驟為:
? ? 與此同時,經過對上面所示的空間劃分之后,我們可以看出,點(7,2)可以為根結點,從根結點出發的兩條紅粗斜線指向的(5,4)和(9,6)則為根結點的左右子結點,而(2,3),(4,7)則為(5,4)的左右孩子(通過兩條細紅斜線相連),最后,(8,1)為(9,6)的左孩子(通過細紅斜線相連)。如此,便形成了下面這樣一棵k-d樹:
?
? ? k-d樹的數據結構
? ? 針對上表給出的kd樹的數據結構,轉化成具體代碼如下所示(注,本文以下代碼分析基于Rob Hess維護的sift庫):
/** a node in a k-d tree */ struct kd_node {int ki; /**< partition key index *///關鍵點直方圖方差最大向量系列位置double kv; /**< partition key value *///直方圖方差最大向量系列中最中間模值int leaf; /**< 1 if node is a leaf, 0 otherwise */struct feature* features; /**< features at this node */int n; /**< number of features */struct kd_node* kd_left; /**< left child */struct kd_node* kd_right; /**< right child */ };? ? 也就是說,如之前所述,kd樹中,kd代表k-dimension,每個節點即為一個k維的點。每個非葉節點可以想象為一個分割超平面,用垂直于坐標軸的超平面將空間分為兩個部分,這樣遞歸的從根節點不停的劃分,直到沒有實例為止。經典的構造k-d tree的規則如下:
? ? 對于n個實例的k維數據來說,建立kd-tree的時間復雜度為O(k*n*logn)。
? ? 以下是構建k-d樹的代碼:
struct kd_node* kdtree_build( struct feature* features, int n ) {struct kd_node* kd_root;if( ! features || n <= 0 ){fprintf( stderr, "Warning: kdtree_build(): no features, %s, line %d\n",__FILE__, __LINE__ );return NULL;}//初始化kd_root = kd_node_init( features, n ); //n--number of features,initinalize root of tree.expand_kd_node_subtree( kd_root ); //kd tree expandreturn kd_root; }? ? 上面的涉及初始化操作的兩個函數kd_node_init,及expand_kd_node_subtree代碼分別如下所示:
static struct kd_node* kd_node_init( struct feature* features, int n ) { //n--number of featuresstruct kd_node* kd_node;kd_node = (struct kd_node*)(malloc( sizeof( struct kd_node ) ));memset( kd_node, 0, sizeof( struct kd_node ) ); //0填充kd_node->ki = -1; //???????kd_node->features = features;kd_node->n = n;return kd_node; } static void expand_kd_node_subtree( struct kd_node* kd_node ) {/* base case: leaf node */if( kd_node->n == 1 || kd_node->n == 0 ){ //葉節點 //偽葉節點kd_node->leaf = 1;return;}assign_part_key( kd_node ); //get ki,kvpartition_features( kd_node ); //creat left and right children,特征點ki位置左樹比右樹模值小,kv作為分界模值//kd_node中關鍵點已經排序if( kd_node->kd_left )expand_kd_node_subtree( kd_node->kd_left );if( kd_node->kd_right )expand_kd_node_subtree( kd_node->kd_right ); }? ? 構建完kd樹之后,如今進行最近鄰搜索呢?從下面的動態gif圖中,你是否能看出些許端倪呢?
? ? k-d樹算法可以分為兩大部分,除了上部分有關k-d樹本身這種數據結構建立的算法,另一部分是在建立的k-d樹上各種諸如插入,刪除,查找(最鄰近查找)等操作涉及的算法。下面,咱們依次來看kd樹的插入、刪除、查找操作。
2.3、KD樹的插入
? ? 元素插入到一個K-D樹的方法和二叉檢索樹類似。本質上,在偶數層比較x坐標值,而在奇數層比較y坐標值。當我們到達了樹的底部,(也就是當一個空指針出現),我們也就找到了結點將要插入的位置。生成的K-D樹的形狀依賴于結點插入時的順序。給定N個點,其中一個結點插入和檢索的平均代價是O(log2N)。
? ? 下面4副圖(來源:中國地質大學電子課件)說明了插入順序為(a) Chicago, (b) Mobile, (c) Toronto, and (d) Buffalo,建立空間K-D樹的示例:
? ? 應該清楚,這里描述的插入過程中,每個結點將其所在的平面分割成兩部分。因比,Chicago 將平面上所有結點分成兩部分,一部分所有的結點x坐標值小于35,另一部分結點的x坐標值大于或等于35。同樣Mobile將所有x坐標值大于35的結點以分成兩部分,一部分結點的Y坐標值是小于10,另一部分結點的Y坐標值大于或等于10。后面的Toronto、Buffalo也按照一分為二的規則繼續劃分。
2.4、KD樹的刪除
KD樹的刪除可以用遞歸程序來實現。我們假設希望從K-D樹中刪除結點(a,b)。如果(a,b)的兩個子樹都為空,則用空樹來代替(a,b)。否則,在(a,b)的子樹中尋找一個合適的結點來代替它,譬如(c,d),則遞歸地從K-D樹中刪除(c,d)。一旦(c,d)已經被刪除,則用(c,d)代替(a,b)。假設(a,b)是一個X識別器,那么,它得替代節點要么是(a,b)左子樹中的X坐標最大值的結點,要么是(a,b)右子樹中x坐標最小值的結點。 也就是說,跟普通二叉樹(包括如下圖所示的紅黑樹)結點的刪除是同樣的思想:用被刪除節點A的左子樹的最右節點或者A的右子樹的最左節點作為替代A的節點(比如,下圖紅黑樹中,若要刪除根結點26,第一步便是用23或28取代根結點26)。 當(a,b)的右子樹為空時,找到(a,b)左子樹中具有x坐標最大的結點,譬如(c,d),將(a,b)的左子樹放到(c,d)的右子樹中,且在樹中從它的上一層遞歸地應用刪除過程(也就是(a,b)的左子樹) 。 下面來舉一個實際的例子(來源:中國地質大學電子課件,原課件錯誤已經在下文中訂正),如下圖所示,原始圖像及對應的kd樹,現在要刪除圖中的A結點,請看一系列刪除步驟: 要刪除上圖中結點A,選擇結點A的右子樹中X坐標值最小的結點,這里是C,C成為根,如下圖: 從C的右子樹中找出一個結點代替先前C的位置, 這里是D,并將D的左子樹轉為它的右子樹,D代替先前C的位置,如下圖: 在D的新右子樹中,找X坐標最小的結點,這里為H,H代替D的位置, 在D的右子樹中找到一個Y坐標最小的值,這里是I,將I代替原先H的位置,從而A結點從圖中順利刪除,如下圖所示: 從一個K-D樹中刪除結點(a,b)的問題變成了在(a,b)的子樹中尋找x坐標為最小的結點。不幸的是尋找最小x坐標值的結點比二叉檢索樹中解決類似的問題要復雜得多。特別是雖然最小x坐標值的結點一定在x識別器的左子樹中,但它同樣可在y識別器的兩個子樹中。因此關系到檢索,且必須注意檢索坐標,以使在每個奇數層僅檢索2個子樹中的一個。? ? 從K-D樹中刪除一個結點是代價很高的,很清楚刪除子樹的根受到子樹中結點個數的限制。用TPL(T)表示樹T總的路徑長度。可看出樹中子樹大小的總和為TPL(T)+N。 以隨機方式插入N個點形成樹的TPL是O(N*log2N),這就意味著從一個隨機形成的K-D樹中刪除一個隨機選取的結點平均代價的上界是O(log2N) 。
2.5、KD樹的最近鄰搜索算法
? ? 現實生活中有許多問題需要在多維數據的快速分析和快速搜索,對于這個問題最常用的方法是所謂的kd樹。在k-d樹中進行數據的查找也是特征匹配的重要環節,其目的是檢索在k-d樹中與查詢點距離最近的數據點。在一個N維的笛卡兒空間在兩個點之間的距離是由下述公式確定:
2.5.1、k-d樹查詢算法的偽代碼
? ? k-d樹查詢算法的偽代碼如下所示:
? ?讀者來信點評@yhxyhxyhx,在“將Kd_point壓入search_path堆棧;”這行代碼后,應該是調到步驟2再往下走二分搜索的邏輯一直到葉結點,我寫了一個遞歸版本的二維kd tree的搜索函數你對比的看看:
void innerGetClosest(NODE* pNode, PT point, PT& res, int& nMinDis) {if (NULL == pNode)return;int nCurDis = abs(point.x - pNode->pt.x) + abs(point.y - pNode->pt.y);if (nMinDis < 0 || nCurDis < nMinDis){nMinDis = nCurDis;res = pNode->pt;}if (pNode->splitX && point.x <= pNode->pt.x || !pNode->splitX && point.y <= pNode->pt.y)innerGetClosest(pNode->pLft, point, res, nMinDis);elseinnerGetClosest(pNode->pRgt, point, res, nMinDis);int rang = pNode->splitX ? abs(point.x - pNode->pt.x) : abs(point.y - pNode->pt.y);if (rang > nMinDis)return;NODE* pGoInto = pNode->pLft;if (pNode->splitX && point.x > pNode->pt.x || !pNode->splitX && point.y > pNode->pt.y)pGoInto = pNode->pRgt;innerGetClosest(pGoInto, point, res, nMinDis); }? ? 下面,以兩個簡單的實例(例子來自圖像局部不變特性特征與描述一書)來描述最鄰近查找的基本思路。
2.5.2、舉例:查詢點(2.1,3.1)
? ? 星號表示要查詢的點(2.1,3.1)。通過二叉搜索,順著搜索路徑很快就能找到最鄰近的近似點,也就是葉子節點(2,3)。而找到的葉子節點并不一定就是最鄰近的,最鄰近肯定距離查詢點更近,應該位于以查詢點為圓心且通過葉子節點的圓域內。為了找到真正的最近鄰,還需要進行相關的‘回溯'操作。也就是說,算法首先沿搜索路徑反向查找是否有距離查詢點更近的數據點。
? ? 以查詢(2.1,3.1)為例:
2.5.3、舉例:查詢點(2,4.5)
? ? 一個復雜點了例子如查找點為(2,4.5),具體步驟依次如下:
? ? 上述兩次實例表明,當查詢點的鄰域與分割超平面兩側空間交割時,需要查找另一側子空間,導致檢索過程復雜,效率下降。
一般來講,最臨近搜索只需要檢測幾個葉子結點即可,如下圖所示:
但是,如果當實例點的分布比較糟糕時,幾乎要遍歷所有的結點,如下所示:
? ? 研究表明N個節點的K維k-d樹搜索過程時間復雜度為:tworst=O(kN1-1/k)。
? ? 同時,以上為了介紹方便,討論的是二維或三維情形。但在實際的應用中,如SIFT特征矢量128維,SURF特征矢量64維,維度都比較大,直接利用k-d樹快速檢索(維數不超過20)的性能急劇下降,幾乎接近貪婪線性掃描。假設數據集的維數為D,一般來說要求數據的規模N滿足N?2D,才能達到高效的搜索。所以這就引出了一系列對k-d樹算法的改進:BBF算法,和一系列M樹、VP樹、MVP樹等高維空間索引樹(下文2.6節kd樹近鄰搜索算法的改進:BBF算法,與2.7節球樹、M樹、VP樹、MVP樹)。
2.6、kd樹近鄰搜索算法的改進:BBF算法
? ? 咱們順著上一節的思路,參考統計學習方法一書上的內容,再來總結下kd樹的最近鄰搜索算法:
輸入:以構造的kd樹,目標點x;輸出:x 的最近鄰
算法步驟如下:
(a)如果該結點保存的實例點比當前最近點距離目標點更近,則更新“當前最近點”,也就是說以該實例點為“當前最近點”。
(b)當前最近點一定存在于該結點一個子結點對應的區域,檢查子結點的父結點的另一子結點對應的區域是否有更近的點。具體做法是,檢查另一子結點對應的區域是否以目標點位球心,以目標點與“當前最近點”間的距離為半徑的圓或超球體相交:
如果相交,可能在另一個子結點對應的區域內存在距目標點更近的點,移動到另一個子結點,接著,繼續遞歸地進行最近鄰搜索;
如果不相交,向上回溯。
? ? 如果實例點是隨機分布的,那么kd樹搜索的平均計算復雜度是O(NlogN),這里的N是訓練實例樹。所以說,kd樹更適用于訓練實例數遠大于空間維數時的k近鄰搜索,當空間維數接近訓練實例數時,它的效率會迅速下降,一降降到“解放前”:線性掃描的速度。
? ? 也正因為上述k最近鄰搜索算法的第4個步驟中的所述:“回退到根結點時,搜索結束”,每個最近鄰點的查詢比較完成過程最終都要回退到根結點而結束,而導致了許多不必要回溯訪問和比較到的結點,這些多余的損耗在高維度數據查找的時候,搜索效率將變得相當之地下,那有什么辦法可以改進這個原始的kd樹最近鄰搜索算法呢?
? ? 從上述標準的kd樹查詢過程可以看出其搜索過程中的“回溯”是由“查詢路徑”決定的,并沒有考慮查詢路徑上一些數據點本身的一些性質。一個簡單的改進思路就是將“查詢路徑”上的結點進行排序,如按各自分割超平面(也稱bin)與查詢點的距離排序,也就是說,回溯檢查總是從優先級最高(Best Bin)的樹結點開始。
? ? 針對此BBF機制,讀者Feng&書童點評道:
? ? 如此,就引出了本節要討論的kd樹最近鄰搜索算法的改進:BBF(Best-Bin-First)查詢算法,它是由發明sift算法的David Lowe在1997的一篇文章中針對高維數據提出的一種近似算法,此算法能確保優先檢索包含最近鄰點可能性較高的空間,此外,BBF機制還設置了一個運行超時限定。采用了BBF查詢機制后,kd樹便可以有效的擴展到高維數據集上。
? ? 偽代碼如下圖所示(圖取自圖像局部不變特性特征與描述一書):
? ? 還是以上面的查詢(2,4.5)為例,搜索的算法流程為:
2.7、球樹、M樹、VP樹、MVP樹
2.7.1、球樹
? ? 咱們來針對上文內容總結回顧下,針對下面這樣一棵kd樹:
? ? 現要找它的最近鄰。
? ? 通過上文2.5節,總結來說,我們已經知道:
1、為了找到一個給定目標點的最近鄰,需要從樹的根結點開始向下沿樹找出目標點所在的區域,如下圖所示,給定目標點,用星號標示,我們似乎一眼看出,有一個點離目標點最近,因為它落在以目標點為圓心以較小長度為半徑的虛線圓內,但為了確定是否可能還村莊一個最近的近鄰,我們會先檢查葉節點的同胞結點,然葉節點的同胞結點在圖中所示的陰影部分,虛線圓并不與之相交,所以確定同胞葉結點不可能包含更近的近鄰。
2、于是我們回溯到父節點,并檢查父節點的同胞結點,父節點的同胞結點覆蓋了圖中所有橫線X軸上的區域。因為虛線圓與右上方的矩形(KD樹把二維平面劃分成一個一個矩形)相交...
? ? 如上,我們看到,KD樹是可用于有效尋找最近鄰的一個樹結構,但這個樹結構其實并不完美,當處理不均勻分布的數據集時便會呈現出一個基本沖突:既邀請樹有完美的平衡結構,又要求待查找的區域近似方形,但不管是近似方形,還是矩形,甚至正方形,都不是最好的使用形狀,因為他們都有角。
? ? ? ??
? ? 什么意思呢?就是說,在上圖中,如果黑色的實例點離目標點星點再遠一點,那么勢必那個虛線圓會如紅線所示那樣擴大,以致與左上方矩形的右下角相交,既然相交了,那么勢必又必須檢查這個左上方矩形,而實際上,最近的點離星點的距離很近,檢查左上方矩形區域已是多余。于此我們看見,KD樹把二維平面劃分成一個一個矩形,但矩形區域的角卻是個難以處理的問題。
? ? 解決的方案就是使用如下圖所示的球樹:
先從球中選擇一個離球的中心最遠的點,然后選擇第二個點離第一個點最遠,將球中所有的點分配到離這兩個聚類中心最近的一個上,然后計算每個聚類的中心,以及聚類能夠包含它所有數據點所需的最小半徑。這種方法的優點是分裂一個包含n個殊絕點的球的成本只是隨n呈線性增加。
? ? 使用球樹找出給定目標點的最近鄰方法是,首先自上而下貫穿整棵樹找出包含目標點所在的葉子,并在這個球里找出與目標點最靠近的點,這將確定出目標點距離它的最近鄰點的一個上限值,然后跟KD樹查找一樣,檢查同胞結點,如果目標點到同胞結點中心的距離超過同胞結點的半徑與當前的上限值之和,那么同胞結點里不可能存在一個更近的點;否則的話,必須進一步檢查位于同胞結點以下的子樹。
? ? 如下圖,目標點還是用一個星表示,黑色點是當前已知的的目標點的最近鄰,灰色球里的所有內容將被排除,因為灰色球的中心點離的太遠,所以它不可能包含一個更近的點,像這樣,遞歸的向樹的根結點進行回溯處理,檢查所有可能包含一個更近于當前上限值的點的球。
? ? 球樹是自上而下的建立,和KD樹一樣,根本問題就是要找到一個好的方法將包含數據點集的球分裂成兩個,在實踐中,不必等到葉子結點只有兩個胡數據點時才停止,可以采用和KD樹一樣的方法,一旦結點上的數據點打到預先設置的最小數量時,便可提前停止建樹過程。
? ? 也就是上面所述,先從球中選擇一個離球的中心最遠的點,然后選擇第二個點離第一個點最遠,將球中所有的點分配到離這兩個聚類中心最近的一個上,然后計算每個聚類的中心,以及聚類能夠包含它所有數據點所需的最小半徑。這種方法的優點是分裂一個包含n個殊絕點的球的成本只是隨n呈線性增加(注:本小節內容主要來自參考條目19:數據挖掘實用機器學習技術,[新西蘭]Ian H.Witten 著,第4章4.7節)。
2.7.2、VP樹與MVP樹簡介
? ??高維特征向量的距離索引問題是基于內容的圖像檢索的一項關鍵技術,目前經常采用的解決辦法是首先對高維特征空間做降維處理,然后采用包括四叉樹、kd樹、R樹族等在內的主流多維索引結構,這種方法的出發點是:目前的主流多維索引結構在處理維數較低的情況時具有比較好的效率,但對于維數很高的情況則顯得力不從心(即所謂的維數危機) 。
? ? 實驗結果表明當特征空間的維數超過20 的時候,效率明顯降低,而可視化特征往往采用高維向量描述,一般情況下可以達到10^2的量級,甚至更高。在表示圖像可視化特征的高維向量中各維信息的重要程度是不同的,通過降維技術去除屬于次要信息的特征向量以及相關性較強的特征向量,從而降低特征空間的維數,這種方法已經得到了一些實際應用。
? ??然而這種方法存在不足之處采用降維技術可能會導致有效信息的損失,尤其不適合于處理特征空間中的特征向量相關性很小的情況。另外主流的多維索引結構大都針對歐氏空間,設計需要利用到歐氏空間的幾何性質,而圖像的相似性計算很可能不限于基于歐氏距離。這種情況下人們越來越關注基于距離的度量空間高維索引結構可以直接應用于高維向量相似性查詢問題。
? ? 度量空間中對象之間的距離度量只能利用三角不等式性質,而不能利用其他幾何性質。向量空間可以看作由實數坐標串組成的特殊度量空間,目前針對度量空間的高維索引問題提出的索引結構有很多種大致可以作如下分類,如下圖所示:
? ? ?讀者點評:
? ? 更多內容請參見論文1:DIST ANCE-BASED INDEXING FOR HIGH-DIMENSIONAL METRIC SP ACES,作者:Tolga Bozkaya & Meral Ozsoyoglu,及論文2:基于度量空間高維索引結構VP-tree及MVP-tree的圖像檢索,王志強,甘國輝,程起敏。
? ? 當然,如果你覺得上述論文還不夠滿足你胃口的話,這里有一大堆nearest neighbor algorithms相關的論文可供你看:http://scholar.google.com.hk/scholar?q=nearest+neighbor+algorithms&btnG=&hl=zh-CN&as_sdt=0&as_vis=1(其中,這篇可以看下:Spill-Trees,An investigation of practical approximate nearest neighbor algorithms)。
總結
以上是生活随笔為你收集整理的决策树:特征分布空间划分方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ***K近邻Survey-Distanc
- 下一篇: 中行企业网银安装步骤?