日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

决策树:特征分布空间划分方法

發(fā)布時間:2023/12/31 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 决策树:特征分布空间划分方法 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

前言:懶惰的原因是因?yàn)闀r間太少,不能夠去仔細(xì)的探索學(xué)習(xí),拿來主義喪失了很多快樂!

K近鄰算法的實(shí)現(xiàn):KD樹

原文鏈接:http://blog.csdn.net/v_july_v/article/details/8203674/

2.0、背景

? ?? 之前blog內(nèi)曾經(jīng)介紹過SIFT特征匹配算法,特征點(diǎn)匹配和數(shù)據(jù)庫查、圖像檢索本質(zhì)上是同一個問題,都可以歸結(jié)為一個通過距離函數(shù)在高維矢量之間進(jìn)行相似性檢索的問題,如何快速而準(zhǔn)確地找到查詢點(diǎn)的近鄰,不少人提出了很多高維空間索引結(jié)構(gòu)和近似查詢的算法。

? ? 一般說來,索引結(jié)構(gòu)中相似性查詢有兩種基本的方式:

  • 一種是范圍查詢,范圍查詢時給定查詢點(diǎn)和查詢距離閾值,從數(shù)據(jù)集中查找所有與查詢點(diǎn)距離小于閾值的數(shù)據(jù)
  • 另一種是K近鄰查詢,就是給定查詢點(diǎn)及正整數(shù)K,從數(shù)據(jù)集中找到距離查詢點(diǎn)最近的K個數(shù)據(jù),當(dāng)K=1時,它就是最近鄰查詢。
  • ? ? 同樣,針對特征點(diǎn)匹配也有兩種方法:

    • 最容易的辦法就是線性掃描,也就是我們常說的窮舉搜索,依次計(jì)算樣本集E中每個樣本到輸入實(shí)例點(diǎn)的距離,然后抽取出計(jì)算出來的最小距離的點(diǎn)即為最近鄰點(diǎn)。此種辦法簡單直白,但當(dāng)樣本集或訓(xùn)練集很大時,它的缺點(diǎn)就立馬暴露出來了,舉個例子,在物體識別的問題中,可能有數(shù)千個甚至數(shù)萬個SIFT特征點(diǎn),而去一一計(jì)算這成千上萬的特征點(diǎn)與輸入實(shí)例點(diǎn)的距離,明顯是不足取的。
    • 另外一種,就是構(gòu)建數(shù)據(jù)索引,因?yàn)閷?shí)際數(shù)據(jù)一般都會呈現(xiàn)簇狀的聚類形態(tài),因此我們想到建立數(shù)據(jù)索引,然后再進(jìn)行快速匹配。索引樹是一種樹結(jié)構(gòu)索引方法,其基本思想是對搜索空間進(jìn)行層次劃分。根據(jù)劃分的空間是否有混疊可以分為Clipping和Overlapping兩種。前者劃分空間沒有重疊,其代表就是k-d樹;后者劃分空間相互有交疊,其代表為R樹。

    ? ? 而關(guān)于R樹本blog內(nèi)之前已有介紹(同時,關(guān)于基于R樹的最近鄰查找,還可以看下這篇文章:http://blog.sina.com.cn/s/blog_72e1c7550101dsc3.html),本文著重介紹k-d樹。

    ? ? 1975年,來自斯坦福大學(xué)的Jon Louis Bentley在ACM雜志上發(fā)表的一篇論文:Multidimensional Binary Search Trees Used for Associative Searching 中正式提出和闡述的了如下圖形式的把空間劃分為多個部分的k-d樹。

    2.1、什么是KD樹

    ? ? Kd-樹是K-dimension tree的縮寫,是對數(shù)據(jù)點(diǎn)在k維空間(如二維(x,y),三維(x,y,z),k維(x1,y,z..)中劃分的一種數(shù)據(jù)結(jié)構(gòu),主要應(yīng)用于多維空間關(guān)鍵數(shù)據(jù)的搜索(如:范圍搜索和最近鄰搜索)。本質(zhì)上說,Kd-樹就是一種平衡二叉樹。

    ? ? 首先必須搞清楚的是,k-d樹是一種空間劃分樹,說白了,就是把整個空間劃分為特定的幾個部分,然后在特定空間的部分內(nèi)進(jìn)行相關(guān)搜索操作。想像一個三維(多維有點(diǎn)為難你的想象力了)空間,kd樹按照一定的劃分規(guī)則把這個三維空間劃分了多個空間,如下圖所示:

    2.2、KD樹的構(gòu)建

    ? ? kd樹構(gòu)建的偽代碼如下圖所示:

    ? ? 再舉一個簡單直觀的實(shí)例來介紹k-d樹構(gòu)建算法。假設(shè)有6個二維數(shù)據(jù)點(diǎn){(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)},數(shù)據(jù)點(diǎn)位于二維空間內(nèi),如下圖所示。為了能有效的找到最近鄰,k-d樹采用分而治之的思想,即將整個空間劃分為幾個小部分,首先,粗黑線將空間一分為二,然后在兩個子空間中,細(xì)黑直線又將整個空間劃分為四部分,最后虛黑直線將這四部分進(jìn)一步劃分。

    ? ? 6個二維數(shù)據(jù)點(diǎn){(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)}構(gòu)建kd樹的具體步驟為:

  • 確定:split域=x。具體是:6個數(shù)據(jù)點(diǎn)在x,y維度上的數(shù)據(jù)方差分別為39,28.63,所以在x軸上方差更大,故split域值為x;
  • 確定:Node-data = (7,2)。具體是:根據(jù)x維上的值將數(shù)據(jù)排序,6個數(shù)據(jù)的中值(所謂中值,即中間大小的值)為7,所以Node-data域位數(shù)據(jù)點(diǎn)(7,2)。這樣,該節(jié)點(diǎn)的分割超平面就是通過(7,2)并垂直于:split=x軸的直線x=7;
  • 確定:左子空間和右子空間。具體是:分割超平面x=7將整個空間分為兩部分:x<=7的部分為左子空間,包含3個節(jié)點(diǎn)={(2,3),(5,4),(4,7)};另一部分為右子空間,包含2個節(jié)點(diǎn)={(9,6),(8,1)};
  • 如上算法所述,kd樹的構(gòu)建是一個遞歸過程,我們對左子空間和右子空間內(nèi)的數(shù)據(jù)重復(fù)根節(jié)點(diǎn)的過程就可以得到一級子節(jié)點(diǎn)(5,4)和(9,6),同時將空間和數(shù)據(jù)集進(jìn)一步細(xì)分,如此往復(fù)直到空間中只包含一個數(shù)據(jù)點(diǎn)。

    ? ? 與此同時,經(jīng)過對上面所示的空間劃分之后,我們可以看出,點(diǎn)(7,2)可以為根結(jié)點(diǎn),從根結(jié)點(diǎn)出發(fā)的兩條紅粗斜線指向的(5,4)和(9,6)則為根結(jié)點(diǎn)的左右子結(jié)點(diǎn),而(2,3),(4,7)則為(5,4)的左右孩子(通過兩條細(xì)紅斜線相連),最后,(8,1)為(9,6)的左孩子(通過細(xì)紅斜線相連)。如此,便形成了下面這樣一棵k-d樹:

    ?

    ? ? k-d樹的數(shù)據(jù)結(jié)構(gòu)

    ? ? 針對上表給出的kd樹的數(shù)據(jù)結(jié)構(gòu),轉(zhuǎn)化成具體代碼如下所示(注,本文以下代碼分析基于Rob Hess維護(hù)的sift庫)

    /** a node in a k-d tree */ struct kd_node {int ki; /**< partition key index *///關(guān)鍵點(diǎn)直方圖方差最大向量系列位置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,每個節(jié)點(diǎn)即為一個k維的點(diǎn)。每個非葉節(jié)點(diǎn)可以想象為一個分割超平面,用垂直于坐標(biāo)軸的超平面將空間分為兩個部分,這樣遞歸的從根節(jié)點(diǎn)不停的劃分,直到?jīng)]有實(shí)例為止。經(jīng)典的構(gòu)造k-d tree的規(guī)則如下:

  • 隨著樹的深度增加,循環(huán)的選取坐標(biāo)軸,作為分割超平面的法向量。對于3-d tree來說,根節(jié)點(diǎn)選取x軸,根節(jié)點(diǎn)的孩子選取y軸,根節(jié)點(diǎn)的孫子選取z軸,根節(jié)點(diǎn)的曾孫子選取x軸,這樣循環(huán)下去。
  • 每次均為所有對應(yīng)實(shí)例的中位數(shù)的實(shí)例作為切分點(diǎn),切分點(diǎn)作為父節(jié)點(diǎn),左右兩側(cè)為劃分的作為左右兩子樹。
  • ? ? 對于n個實(shí)例的k維數(shù)據(jù)來說,建立kd-tree的時間復(fù)雜度為O(k*n*logn)。

    ? ? 以下是構(gòu)建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; }

    ? ? 上面的涉及初始化操作的兩個函數(shù)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 ){ //葉節(jié)點(diǎn) //偽葉節(jié)點(diǎn)kd_node->leaf = 1;return;}assign_part_key( kd_node ); //get ki,kvpartition_features( kd_node ); //creat left and right children,特征點(diǎn)ki位置左樹比右樹模值小,kv作為分界模值//kd_node中關(guān)鍵點(diǎn)已經(jīng)排序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 ); }

    ? ? 構(gòu)建完kd樹之后,如今進(jìn)行最近鄰搜索呢?從下面的動態(tài)gif圖中,你是否能看出些許端倪呢?


    ? ? k-d樹算法可以分為兩大部分,除了上部分有關(guān)k-d樹本身這種數(shù)據(jù)結(jié)構(gòu)建立的算法,另一部分是在建立的k-d樹上各種諸如插入,刪除,查找(最鄰近查找)等操作涉及的算法。下面,咱們依次來看kd樹的插入、刪除、查找操作。

    2.3、KD樹的插入

    ? ? 元素插入到一個K-D樹的方法和二叉檢索樹類似。本質(zhì)上,在偶數(shù)層比較x坐標(biāo)值,而在奇數(shù)層比較y坐標(biāo)值。當(dāng)我們到達(dá)了樹的底部,(也就是當(dāng)一個空指針出現(xiàn)),我們也就找到了結(jié)點(diǎn)將要插入的位置。生成的K-D樹的形狀依賴于結(jié)點(diǎn)插入時的順序。給定N個點(diǎn),其中一個結(jié)點(diǎn)插入和檢索的平均代價(jià)是O(log2N)。

    ? ? 下面4副圖(來源:中國地質(zhì)大學(xué)電子課件)說明了插入順序?yàn)?a) Chicago, (b) Mobile, (c) Toronto, and (d) Buffalo,建立空間K-D樹的示例:


    ? ? 應(yīng)該清楚,這里描述的插入過程中,每個結(jié)點(diǎn)將其所在的平面分割成兩部分。因比,Chicago 將平面上所有結(jié)點(diǎn)分成兩部分,一部分所有的結(jié)點(diǎn)x坐標(biāo)值小于35,另一部分結(jié)點(diǎn)的x坐標(biāo)值大于或等于35。同樣Mobile將所有x坐標(biāo)值大于35的結(jié)點(diǎn)以分成兩部分,一部分結(jié)點(diǎn)的Y坐標(biāo)值是小于10,另一部分結(jié)點(diǎn)的Y坐標(biāo)值大于或等于10。后面的Toronto、Buffalo也按照一分為二的規(guī)則繼續(xù)劃分。

    2.4、KD樹的刪除

    KD樹的刪除可以用遞歸程序來實(shí)現(xiàn)。我們假設(shè)希望從K-D樹中刪除結(jié)點(diǎn)(a,b)。如果(a,b)的兩個子樹都為空,則用空樹來代替(a,b)。否則,在(a,b)的子樹中尋找一個合適的結(jié)點(diǎn)來代替它,譬如(c,d),則遞歸地從K-D樹中刪除(c,d)。一旦(c,d)已經(jīng)被刪除,則用(c,d)代替(a,b)。假設(shè)(a,b)是一個X識別器,那么,它得替代節(jié)點(diǎn)要么是(a,b)左子樹中的X坐標(biāo)最大值的結(jié)點(diǎn),要么是(a,b)右子樹中x坐標(biāo)最小值的結(jié)點(diǎn)。 也就是說,跟普通二叉樹(包括如下圖所示的紅黑樹)結(jié)點(diǎn)的刪除是同樣的思想:用被刪除節(jié)點(diǎn)A的左子樹的最右節(jié)點(diǎn)或者A的右子樹的最左節(jié)點(diǎn)作為替代A的節(jié)點(diǎn)(比如,下圖紅黑樹中,若要刪除根結(jié)點(diǎn)26,第一步便是用23或28取代根結(jié)點(diǎn)26)。 當(dāng)(a,b)的右子樹為空時,找到(a,b)左子樹中具有x坐標(biāo)最大的結(jié)點(diǎn),譬如(c,d),將(a,b)的左子樹放到(c,d)的右子樹中,且在樹中從它的上一層遞歸地應(yīng)用刪除過程(也就是(a,b)的左子樹) 。 下面來舉一個實(shí)際的例子(來源:中國地質(zhì)大學(xué)電子課件,原課件錯誤已經(jīng)在下文中訂正),如下圖所示,原始圖像及對應(yīng)的kd樹,現(xiàn)在要刪除圖中的A結(jié)點(diǎn),請看一系列刪除步驟: 要刪除上圖中結(jié)點(diǎn)A,選擇結(jié)點(diǎn)A的右子樹中X坐標(biāo)值最小的結(jié)點(diǎn),這里是C,C成為根,如下圖: 從C的右子樹中找出一個結(jié)點(diǎn)代替先前C的位置, 這里是D,并將D的左子樹轉(zhuǎn)為它的右子樹,D代替先前C的位置,如下圖: 在D的新右子樹中,找X坐標(biāo)最小的結(jié)點(diǎn),這里為H,H代替D的位置, 在D的右子樹中找到一個Y坐標(biāo)最小的值,這里是I,將I代替原先H的位置,從而A結(jié)點(diǎn)從圖中順利刪除,如下圖所示: 從一個K-D樹中刪除結(jié)點(diǎn)(a,b)的問題變成了在(a,b)的子樹中尋找x坐標(biāo)為最小的結(jié)點(diǎn)。不幸的是尋找最小x坐標(biāo)值的結(jié)點(diǎn)比二叉檢索樹中解決類似的問題要復(fù)雜得多。特別是雖然最小x坐標(biāo)值的結(jié)點(diǎn)一定在x識別器的左子樹中,但它同樣可在y識別器的兩個子樹中。因此關(guān)系到檢索,且必須注意檢索坐標(biāo),以使在每個奇數(shù)層僅檢索2個子樹中的一個。
    ? ? 從K-D樹中刪除一個結(jié)點(diǎn)是代價(jià)很高的,很清楚刪除子樹的根受到子樹中結(jié)點(diǎn)個數(shù)的限制。用TPL(T)表示樹T總的路徑長度。可看出樹中子樹大小的總和為TPL(T)+N。 以隨機(jī)方式插入N個點(diǎn)形成樹的TPL是O(N*log2N),這就意味著從一個隨機(jī)形成的K-D樹中刪除一個隨機(jī)選取的結(jié)點(diǎn)平均代價(jià)的上界是O(log2N) 。

    2.5、KD樹的最近鄰搜索算法

    ? ? 現(xiàn)實(shí)生活中有許多問題需要在多維數(shù)據(jù)的快速分析和快速搜索,對于這個問題最常用的方法是所謂的kd樹。在k-d樹中進(jìn)行數(shù)據(jù)的查找也是特征匹配的重要環(huán)節(jié),其目的是檢索在k-d樹中與查詢點(diǎn)距離最近的數(shù)據(jù)點(diǎn)。在一個N維的笛卡兒空間在兩個點(diǎn)之間的距離是由下述公式確定:

    2.5.1、k-d樹查詢算法的偽代碼

    ? ? k-d樹查詢算法的偽代碼如下所示:

    算法:k-d樹最鄰近查找 輸入:Kd, //k-d tree類型target //查詢數(shù)據(jù)點(diǎn) 輸出:nearest, //最鄰近數(shù)據(jù)點(diǎn)dist //最鄰近數(shù)據(jù)點(diǎn)和查詢點(diǎn)間的距離1. If Kd為NULL,則設(shè)dist為infinite并返回 2. //進(jìn)行二叉查找,生成搜索路徑Kd_point = &Kd; //Kd-point中保存k-d tree根節(jié)點(diǎn)地址nearest = Kd_point -> Node-data; //初始化最近鄰點(diǎn)while(Kd_point)push(Kd_point)到search_path中; //search_path是一個堆棧結(jié)構(gòu),存儲著搜索路徑節(jié)點(diǎn)指針I(yè)f Dist(nearest,target) > Dist(Kd_point -> Node-data,target)nearest = Kd_point -> Node-data; //更新最近鄰點(diǎn)Min_dist = Dist(Kd_point,target); //更新最近鄰點(diǎn)與查詢點(diǎn)間的距離 ***/s = Kd_point -> split; //確定待分割的方向If target[s] <= Kd_point -> Node-data[s] //進(jìn)行二叉查找Kd_point = Kd_point -> left;elseKd_point = Kd_point ->right;End while3. //回溯查找while(search_path != NULL)back_point = 從search_path取出一個節(jié)點(diǎn)指針; //從search_path堆棧彈棧s = back_point -> split; //確定分割方向If Dist(target[s],back_point -> Node-data[s]) < Max_dist //判斷還需進(jìn)入的子空間If target[s] <= back_point -> Node-data[s]Kd_point = back_point -> right; //如果target位于左子空間,就應(yīng)進(jìn)入右子空間elseKd_point = back_point -> left; //如果target位于右子空間,就應(yīng)進(jìn)入左子空間將Kd_point壓入search_path堆棧;If Dist(nearest,target) > Dist(Kd_Point -> Node-data,target)nearest = Kd_point -> Node-data; //更新最近鄰點(diǎn)Min_dist = Dist(Kd_point -> Node-data,target); //更新最近鄰點(diǎn)與查詢點(diǎn)間的距離的End while

    ? ?讀者來信點(diǎn)評@yhxyhxyhx,在“將Kd_point壓入search_path堆棧;”這行代碼后,應(yīng)該是調(diào)到步驟2再往下走二分搜索的邏輯一直到葉結(jié)點(diǎn),我寫了一個遞歸版本的二維kd tree的搜索函數(shù)你對比的看看:

    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); }

    ? ? 下面,以兩個簡單的實(shí)例(例子來自圖像局部不變特性特征與描述一書)來描述最鄰近查找的基本思路。

    2.5.2、舉例:查詢點(diǎn)(2.1,3.1)

    ? ? 星號表示要查詢的點(diǎn)(2.1,3.1)。通過二叉搜索,順著搜索路徑很快就能找到最鄰近的近似點(diǎn),也就是葉子節(jié)點(diǎn)(2,3)。而找到的葉子節(jié)點(diǎn)并不一定就是最鄰近的,最鄰近肯定距離查詢點(diǎn)更近,應(yīng)該位于以查詢點(diǎn)為圓心且通過葉子節(jié)點(diǎn)的圓域內(nèi)。為了找到真正的最近鄰,還需要進(jìn)行相關(guān)的‘回溯'操作。也就是說,算法首先沿搜索路徑反向查找是否有距離查詢點(diǎn)更近的數(shù)據(jù)點(diǎn)。

    ? ? 以查詢(2.1,3.1)為例:

  • 二叉樹搜索:先從(7,2)點(diǎn)開始進(jìn)行二叉查找,然后到達(dá)(5,4),最后到達(dá)(2,3),此時搜索路徑中的節(jié)點(diǎn)為<(7,2),(5,4),(2,3)>,首先以(2,3)作為當(dāng)前最近鄰點(diǎn),計(jì)算其到查詢點(diǎn)(2.1,3.1)的距離為0.1414,
  • 回溯查找:在得到(2,3)為查詢點(diǎn)的最近點(diǎn)之后,回溯到其父節(jié)點(diǎn)(5,4),并判斷在該父節(jié)點(diǎn)的其他子節(jié)點(diǎn)空間中是否有距離查詢點(diǎn)更近的數(shù)據(jù)點(diǎn)。以(2.1,3.1)為圓心,以0.1414為半徑畫圓,如下圖所示。發(fā)現(xiàn)該圓并不和超平面y = 4交割,因此不用進(jìn)入(5,4)節(jié)點(diǎn)右子空間中(圖中灰色區(qū)域)去搜索;
  • 最后,再回溯到(7,2),以(2.1,3.1)為圓心,以0.1414為半徑的圓更不會與x = 7超平面交割,因此不用進(jìn)入(7,2)右子空間進(jìn)行查找。至此,搜索路徑中的節(jié)點(diǎn)已經(jīng)全部回溯完,結(jié)束整個搜索,返回最近鄰點(diǎn)(2,3),最近距離為0.1414。

  • 2.5.3、舉例:查詢點(diǎn)2,4.5

    ? ? 一個復(fù)雜點(diǎn)了例子如查找點(diǎn)為(2,4.5),具體步驟依次如下:

  • 同樣先進(jìn)行二叉查找,先從(7,2)查找到(5,4)節(jié)點(diǎn),在進(jìn)行查找時是由y = 4為分割超平面的,由于查找點(diǎn)為y值為4.5,因此進(jìn)入右子空間查找到(4,7),形成搜索路徑<(7,2),(5,4),(4,7)>,但(4,7)與目標(biāo)查找點(diǎn)的距離為3.202,而(5,4)與查找點(diǎn)之間的距離為3.041,所以(5,4)為查詢點(diǎn)的最近點(diǎn);
  • 以(2,4.5)為圓心,以3.041為半徑作圓,如下圖所示。可見該圓和y = 4超平面交割,所以需要進(jìn)入(5,4)左子空間進(jìn)行查找,也就是將(2,3)節(jié)點(diǎn)加入搜索路徑中得<(7,2),(2,3)>;于是接著搜索至(2,3)葉子節(jié)點(diǎn),(2,3)距離(2,4.5)比(5,4)要近,所以最近鄰點(diǎn)更新為(2,3),最近距離更新為1.5;
  • 回溯查找至(5,4),直到最后回溯到根結(jié)點(diǎn)(7,2)的時候,以(2,4.5)為圓心1.5為半徑作圓,并不和x = 7分割超平面交割,如下圖所示。至此,搜索路徑回溯完,返回最近鄰點(diǎn)(2,3),最近距離1.5。
  • ? ? 上述兩次實(shí)例表明,當(dāng)查詢點(diǎn)的鄰域與分割超平面兩側(cè)空間交割時,需要查找另一側(cè)子空間,導(dǎo)致檢索過程復(fù)雜,效率下降。

    一般來講,最臨近搜索只需要檢測幾個葉子結(jié)點(diǎn)即可,如下圖所示:  

    但是,如果當(dāng)實(shí)例點(diǎn)的分布比較糟糕時,幾乎要遍歷所有的結(jié)點(diǎn),如下所示:

    ? ? 研究表明N個節(jié)點(diǎn)的K維k-d樹搜索過程時間復(fù)雜度為:tworst=O(kN1-1/k)。

    ? ? 同時,以上為了介紹方便,討論的是二維或三維情形。但在實(shí)際的應(yīng)用中,如SIFT特征矢量128維,SURF特征矢量64維,維度都比較大,直接利用k-d樹快速檢索(維數(shù)不超過20)的性能急劇下降,幾乎接近貪婪線性掃描。假設(shè)數(shù)據(jù)集的維數(shù)為D,一般來說要求數(shù)據(jù)的規(guī)模N滿足N?2D,才能達(dá)到高效的搜索。所以這就引出了一系列對k-d樹算法的改進(jìn):BBF算法,和一系列M樹、VP樹、MVP樹等高維空間索引樹(下文2.6節(jié)kd樹近鄰搜索算法的改進(jìn):BBF算法,與2.7節(jié)球樹、M樹、VP樹、MVP樹)。

    2.6、kd樹近鄰搜索算法的改進(jìn):BBF算法

    ? ? 咱們順著上一節(jié)的思路,參考統(tǒng)計(jì)學(xué)習(xí)方法一書上的內(nèi)容,再來總結(jié)下kd樹的最近鄰搜索算法:

    輸入:以構(gòu)造的kd樹,目標(biāo)點(diǎn)x;
    輸出:x 的最近鄰
    算法步驟如下:
  • 在kd樹種找出包含目標(biāo)點(diǎn)x的葉結(jié)點(diǎn):從根結(jié)點(diǎn)出發(fā),遞歸地向下搜索kd樹。若目標(biāo)點(diǎn)x當(dāng)前維的坐標(biāo)小于切分點(diǎn)的坐標(biāo),則移動到左子結(jié)點(diǎn),否則移動到右子結(jié)點(diǎn),直到子結(jié)點(diǎn)為葉結(jié)點(diǎn)為止。
  • 以此葉結(jié)點(diǎn)為“當(dāng)前最近點(diǎn)”。
  • 遞歸的向上回溯,在每個結(jié)點(diǎn)進(jìn)行以下操作:
    (a)如果該結(jié)點(diǎn)保存的實(shí)例點(diǎn)比當(dāng)前最近點(diǎn)距離目標(biāo)點(diǎn)更近,則更新“當(dāng)前最近點(diǎn)”,也就是說以該實(shí)例點(diǎn)為“當(dāng)前最近點(diǎn)”。
    (b)當(dāng)前最近點(diǎn)一定存在于該結(jié)點(diǎn)一個子結(jié)點(diǎn)對應(yīng)的區(qū)域,檢查子結(jié)點(diǎn)的父結(jié)點(diǎn)的另一子結(jié)點(diǎn)對應(yīng)的區(qū)域是否有更近的點(diǎn)。具體做法是,檢查另一子結(jié)點(diǎn)對應(yīng)的區(qū)域是否以目標(biāo)點(diǎn)位球心,以目標(biāo)點(diǎn)與“當(dāng)前最近點(diǎn)”間的距離為半徑的圓或超球體相交:
    如果相交,可能在另一個子結(jié)點(diǎn)對應(yīng)的區(qū)域內(nèi)存在距目標(biāo)點(diǎn)更近的點(diǎn),移動到另一個子結(jié)點(diǎn),接著,繼續(xù)遞歸地進(jìn)行最近鄰搜索;
    如果不相交,向上回溯。
  • 當(dāng)回退到根結(jié)點(diǎn)時,搜索結(jié)束,最后的“當(dāng)前最近點(diǎn)”即為x 的最近鄰點(diǎn)。
  • ? ? 如果實(shí)例點(diǎn)是隨機(jī)分布的,那么kd樹搜索的平均計(jì)算復(fù)雜度是O(NlogN),這里的N是訓(xùn)練實(shí)例樹。所以說,kd樹更適用于訓(xùn)練實(shí)例數(shù)遠(yuǎn)大于空間維數(shù)時的k近鄰搜索,當(dāng)空間維數(shù)接近訓(xùn)練實(shí)例數(shù)時,它的效率會迅速下降,一降降到“解放前”:線性掃描的速度。

    ? ? 也正因?yàn)樯鲜鰇最近鄰搜索算法的第4個步驟中的所述:“回退到根結(jié)點(diǎn)時,搜索結(jié)束”,每個最近鄰點(diǎn)的查詢比較完成過程最終都要回退到根結(jié)點(diǎn)而結(jié)束,而導(dǎo)致了許多不必要回溯訪問和比較到的結(jié)點(diǎn),這些多余的損耗在高維度數(shù)據(jù)查找的時候,搜索效率將變得相當(dāng)之地下,那有什么辦法可以改進(jìn)這個原始的kd樹最近鄰搜索算法呢?

    ? ? 從上述標(biāo)準(zhǔn)的kd樹查詢過程可以看出其搜索過程中的“回溯”是由“查詢路徑”決定的,并沒有考慮查詢路徑上一些數(shù)據(jù)點(diǎn)本身的一些性質(zhì)。一個簡單的改進(jìn)思路就是將“查詢路徑”上的結(jié)點(diǎn)進(jìn)行排序,如按各自分割超平面(也稱bin)與查詢點(diǎn)的距離排序,也就是說,回溯檢查總是從優(yōu)先級最高(Best Bin)的樹結(jié)點(diǎn)開始。

    ? ? 針對此BBF機(jī)制,讀者Feng&書童點(diǎn)評道:

  • 在某一層,分割面是第ki維,分割值是kv,那么 abs(q[ki]-kv) 就是沒有選擇的那個分支的優(yōu)先級,也就是計(jì)算的是那一維上的距離;
  • 同時,從優(yōu)先隊(duì)列里面取節(jié)點(diǎn)只在某次搜索到葉節(jié)點(diǎn)后才發(fā)生,計(jì)算過距離的節(jié)點(diǎn)不會出現(xiàn)在隊(duì)列的,比如1~10這10個節(jié)點(diǎn),你第一次搜索到葉節(jié)點(diǎn)的路徑是1-5-7,那么1,5,7是不會出現(xiàn)在優(yōu)先隊(duì)列的。換句話說,優(yōu)先隊(duì)列里面存的都是查詢路徑上節(jié)點(diǎn)對應(yīng)的相反子節(jié)點(diǎn),比如:搜索左子樹,就把對應(yīng)這一層的右節(jié)點(diǎn)存進(jìn)隊(duì)列。
  • ? ? 如此,就引出了本節(jié)要討論的kd樹最近鄰搜索算法的改進(jìn):BBF(Best-Bin-First)查詢算法,它是由發(fā)明sift算法的David Lowe在1997的一篇文章中針對高維數(shù)據(jù)提出的一種近似算法,此算法能確保優(yōu)先檢索包含最近鄰點(diǎn)可能性較高的空間,此外,BBF機(jī)制還設(shè)置了一個運(yùn)行超時限定。采用了BBF查詢機(jī)制后,kd樹便可以有效的擴(kuò)展到高維數(shù)據(jù)集上。

    ? ? 偽代碼如下圖所示(圖取自圖像局部不變特性特征與描述一書):

    ? ? 還是以上面的查詢(2,4.5)為例,搜索的算法流程為:

  • 將(7,2)壓人優(yōu)先隊(duì)列中;
  • 提取優(yōu)先隊(duì)列中的(7,2),由于(2,4.5)位于(7,2)分割超平面的左側(cè),所以檢索其左子結(jié)點(diǎn)(5,4)。同時,根據(jù)BBF機(jī)制”搜索左/右子樹,就把對應(yīng)這一層的兄弟結(jié)點(diǎn)即右/左結(jié)點(diǎn)存進(jìn)隊(duì)列”,將其(5,4)對應(yīng)的兄弟結(jié)點(diǎn)即右子結(jié)點(diǎn)(9,6)壓人優(yōu)先隊(duì)列中,此時優(yōu)先隊(duì)列為{(9,6)},最佳點(diǎn)為(7,2);然后一直檢索到葉子結(jié)點(diǎn)(4,7),此時優(yōu)先隊(duì)列為{(2,3),(9,6)},“最佳點(diǎn)”則為(5,4);
  • 提取優(yōu)先級最高的結(jié)點(diǎn)(2,3),重復(fù)步驟2,直到優(yōu)先隊(duì)列為空。
  • ? ? 如你在下圖所見到的那樣(話說,用鼠標(biāo)在圖片上寫字著實(shí)不好寫):

    2.7、球樹、M樹、VP樹、MVP樹

    2.7.1、球樹

    ? ? 咱們來針對上文內(nèi)容總結(jié)回顧下,針對下面這樣一棵kd樹:

    ? ? 現(xiàn)要找它的最近鄰。

    ? ? 通過上文2.5節(jié),總結(jié)來說,我們已經(jīng)知道:

    1、為了找到一個給定目標(biāo)點(diǎn)的最近鄰,需要從樹的根結(jié)點(diǎn)開始向下沿樹找出目標(biāo)點(diǎn)所在的區(qū)域,如下圖所示,給定目標(biāo)點(diǎn),用星號標(biāo)示,我們似乎一眼看出,有一個點(diǎn)離目標(biāo)點(diǎn)最近,因?yàn)樗湓谝阅繕?biāo)點(diǎn)為圓心以較小長度為半徑的虛線圓內(nèi),但為了確定是否可能還村莊一個最近的近鄰,我們會先檢查葉節(jié)點(diǎn)的同胞結(jié)點(diǎn),然葉節(jié)點(diǎn)的同胞結(jié)點(diǎn)在圖中所示的陰影部分,虛線圓并不與之相交,所以確定同胞葉結(jié)點(diǎn)不可能包含更近的近鄰。

    2、于是我們回溯到父節(jié)點(diǎn),并檢查父節(jié)點(diǎn)的同胞結(jié)點(diǎn),父節(jié)點(diǎn)的同胞結(jié)點(diǎn)覆蓋了圖中所有橫線X軸上的區(qū)域。因?yàn)樘摼€圓與右上方的矩形(KD樹把二維平面劃分成一個一個矩形)相交...

    ? ? 如上,我們看到,KD樹是可用于有效尋找最近鄰的一個樹結(jié)構(gòu),但這個樹結(jié)構(gòu)其實(shí)并不完美,當(dāng)處理不均勻分布的數(shù)據(jù)集時便會呈現(xiàn)出一個基本沖突:既邀請樹有完美的平衡結(jié)構(gòu),又要求待查找的區(qū)域近似方形,但不管是近似方形,還是矩形,甚至正方形,都不是最好的使用形狀,因?yàn)樗麄兌加薪恰?/p>

    ? ? ? ??

    ? ? 什么意思呢?就是說,在上圖中,如果黑色的實(shí)例點(diǎn)離目標(biāo)點(diǎn)星點(diǎn)再遠(yuǎn)一點(diǎn),那么勢必那個虛線圓會如紅線所示那樣擴(kuò)大,以致與左上方矩形的右下角相交,既然相交了,那么勢必又必須檢查這個左上方矩形,而實(shí)際上,最近的點(diǎn)離星點(diǎn)的距離很近,檢查左上方矩形區(qū)域已是多余。于此我們看見,KD樹把二維平面劃分成一個一個矩形,但矩形區(qū)域的角卻是個難以處理的問題。

    ? ? 解決的方案就是使用如下圖所示的球樹:

    先從球中選擇一個離球的中心最遠(yuǎn)的點(diǎn),然后選擇第二個點(diǎn)離第一個點(diǎn)最遠(yuǎn),將球中所有的點(diǎn)分配到離這兩個聚類中心最近的一個上,然后計(jì)算每個聚類的中心,以及聚類能夠包含它所有數(shù)據(jù)點(diǎn)所需的最小半徑。這種方法的優(yōu)點(diǎn)是分裂一個包含n個殊絕點(diǎn)的球的成本只是隨n呈線性增加。

    ? ? 使用球樹找出給定目標(biāo)點(diǎn)的最近鄰方法是,首先自上而下貫穿整棵樹找出包含目標(biāo)點(diǎn)所在的葉子,并在這個球里找出與目標(biāo)點(diǎn)最靠近的點(diǎn),這將確定出目標(biāo)點(diǎn)距離它的最近鄰點(diǎn)的一個上限值,然后跟KD樹查找一樣,檢查同胞結(jié)點(diǎn),如果目標(biāo)點(diǎn)到同胞結(jié)點(diǎn)中心的距離超過同胞結(jié)點(diǎn)的半徑與當(dāng)前的上限值之和,那么同胞結(jié)點(diǎn)里不可能存在一個更近的點(diǎn);否則的話,必須進(jìn)一步檢查位于同胞結(jié)點(diǎn)以下的子樹。

    ? ? 如下圖,目標(biāo)點(diǎn)還是用一個星表示,黑色點(diǎn)是當(dāng)前已知的的目標(biāo)點(diǎn)的最近鄰,灰色球里的所有內(nèi)容將被排除,因?yàn)榛疑虻闹行狞c(diǎn)離的太遠(yuǎn),所以它不可能包含一個更近的點(diǎn),像這樣,遞歸的向樹的根結(jié)點(diǎn)進(jìn)行回溯處理,檢查所有可能包含一個更近于當(dāng)前上限值的點(diǎn)的球。

    ? ? 球樹是自上而下的建立,和KD樹一樣,根本問題就是要找到一個好的方法將包含數(shù)據(jù)點(diǎn)集的球分裂成兩個,在實(shí)踐中,不必等到葉子結(jié)點(diǎn)只有兩個胡數(shù)據(jù)點(diǎn)時才停止,可以采用和KD樹一樣的方法,一旦結(jié)點(diǎn)上的數(shù)據(jù)點(diǎn)打到預(yù)先設(shè)置的最小數(shù)量時,便可提前停止建樹過程。

    ? ? 也就是上面所述,先從球中選擇一個離球的中心最遠(yuǎn)的點(diǎn),然后選擇第二個點(diǎn)離第一個點(diǎn)最遠(yuǎn),將球中所有的點(diǎn)分配到離這兩個聚類中心最近的一個上,然后計(jì)算每個聚類的中心,以及聚類能夠包含它所有數(shù)據(jù)點(diǎn)所需的最小半徑。這種方法的優(yōu)點(diǎn)是分裂一個包含n個殊絕點(diǎn)的球的成本只是隨n呈線性增加(注:本小節(jié)內(nèi)容主要來自參考條目19:數(shù)據(jù)挖掘?qū)嵱脵C(jī)器學(xué)習(xí)技術(shù),[新西蘭]Ian H.Witten 著,第4章4.7節(jié))。

    2.7.2、VP樹與MVP樹簡介

    ? ??高維特征向量的距離索引問題是基于內(nèi)容的圖像檢索的一項(xiàng)關(guān)鍵技術(shù),目前經(jīng)常采用的解決辦法是首先對高維特征空間做降維處理,然后采用包括四叉樹、kd樹、R樹族等在內(nèi)的主流多維索引結(jié)構(gòu),這種方法的出發(fā)點(diǎn)是:目前的主流多維索引結(jié)構(gòu)在處理維數(shù)較低的情況時具有比較好的效率,但對于維數(shù)很高的情況則顯得力不從心(即所謂的維數(shù)危機(jī)) 。

    ? ? 實(shí)驗(yàn)結(jié)果表明當(dāng)特征空間的維數(shù)超過20 的時候,效率明顯降低,而可視化特征往往采用高維向量描述,一般情況下可以達(dá)到10^2的量級,甚至更高。在表示圖像可視化特征的高維向量中各維信息的重要程度是不同的,通過降維技術(shù)去除屬于次要信息的特征向量以及相關(guān)性較強(qiáng)的特征向量,從而降低特征空間的維數(shù),這種方法已經(jīng)得到了一些實(shí)際應(yīng)用。

    ? ??然而這種方法存在不足之處采用降維技術(shù)可能會導(dǎo)致有效信息的損失,尤其不適合于處理特征空間中的特征向量相關(guān)性很小的情況。另外主流的多維索引結(jié)構(gòu)大都針對歐氏空間,設(shè)計(jì)需要利用到歐氏空間的幾何性質(zhì),而圖像的相似性計(jì)算很可能不限于基于歐氏距離。這種情況下人們越來越關(guān)注基于距離的度量空間高維索引結(jié)構(gòu)可以直接應(yīng)用于高維向量相似性查詢問題。

    ? ? 度量空間中對象之間的距離度量只能利用三角不等式性質(zhì),而不能利用其他幾何性質(zhì)。向量空間可以看作由實(shí)數(shù)坐標(biāo)串組成的特殊度量空間,目前針對度量空間的高維索引問題提出的索引結(jié)構(gòu)有很多種大致可以作如下分類,如下圖所示:

    其中,VP樹和MVP樹中特征向量的舉例表示為:

    ? ? ?讀者點(diǎn)評:

  • UESTC_HN_AY_GUOBO:現(xiàn)在主要是在kdtree的基礎(chǔ)上有了mtree或者mvptree,其實(shí)關(guān)鍵還是pivot的選擇,以及度量空間中算法怎么減少距離計(jì)算;
  • mandycool:mvp-tree,是利用三角形不等式來縮小搜索區(qū)域的,不過mvp-tree的目標(biāo)稍有不同,查詢的是到query點(diǎn)的距離小于某個值r的點(diǎn);另外作者test的數(shù)據(jù)集只有20維,不知道上百維以后效果如何,而減少距離計(jì)算的一個思路是做embedding,通過不等式排除掉一部分點(diǎn)。
  • ? ? 更多內(nèi)容請參見論文1:DIST ANCE-BASED INDEXING FOR HIGH-DIMENSIONAL METRIC SP ACES,作者:Tolga Bozkaya & Meral Ozsoyoglu,及論文2:基于度量空間高維索引結(jié)構(gòu)VP-tree及MVP-tree的圖像檢索王志強(qiáng),甘國輝,程起敏

    ? ? 當(dāng)然,如果你覺得上述論文還不夠滿足你胃口的話,這里有一大堆nearest neighbor algorithms相關(guān)的論文可供你看: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

    總結(jié)

    以上是生活随笔為你收集整理的决策树:特征分布空间划分方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。