近鄰搜尋是一種很基礎的又相當重要的操作,除了資訊檢索以外,還被廣泛用於計算機視覺、機器學習等領域,如何快速有效的做近鄰查詢一直是一項熱門的研究。較早提出的方法多基於空間劃分(space partition),最具有代表性的如kd-tree(kdt),球樹等。本篇將介紹基於空間劃分方法中的一種,制高點樹(vantage point tree,vpt),最初在2023年提出,比kdt稍晚,提供了乙個不一樣的建樹思路。
和kdt一樣,vpt也是一類二叉樹,不同的是在每個節點的劃分策略。略微回顧一下kdt,它在每個節點擊擇乙個維度,根據資料點在該維度上的大小將資料均分為二。而在vpt中,首先從節點中選擇乙個資料點(可隨機選)作為制高點(vp),然後算出其它點到vp的距離大小,最後根據該距離大小將資料點均分為二。建樹演算法如下:
選擇某資料點v作為vp
計算其它點到v的距離
求出中值m,小於m的資料點分給左子樹,大於m的資料點分給右子樹
遞迴地建立左子樹和右子樹
這裡提供乙個簡單的例子如圖,框中為平面上的點,其中紅框為選中的vp,根據其它點到vp的距離進行了子樹劃分。
vpt查詢是 準確近鄰查詢,較適合範圍查詢,可方便擴充套件為k近鄰查詢。
進行近鄰查詢時,
假定查詢點為
q
,當前的制高點為
v
,距離中值為
m
,則有如下策略搜尋到
q點距離小於
r
的點集:
(1) 若 dist(q,v)+r≥m,遞迴地搜尋右子樹(球外區域)
(2) 若 dist(q,v)-r≤m,遞迴地搜尋左子樹(球內區域)
為了方便寫公式,用文本來進行證明,其實就是簡單的三角形不等式的應用。
最後上點乾貨,乙個簡易c++實現如下:
#ifndef _vptree_header_
#define _vptree_header_
#include #include #include #include #include #include //#include "fnn.h"
templateclass vptree
~vptree()
void create( const std::vector& items )
void search( const t& target, int k, std::vector* results,
std::vector* distances)
std::reverse( results->begin(), results->end() );
std::reverse( distances->begin(), distances->end() );
printf("vp search dist = %f\n",distances->at(0));
brute(target);
}void search(const t& target,std::vector* results,std::vector* distances)
int range_search(const t& target, double range, int *list, int &listnum)*/
//-debug
if(dist<=range)
} /*_tau = range;
rsearch( _root, target, hit, list, listnum);*/
return hit;
}private:
std::vector_items;
double _tau;
struct node
~node()
}* _root;
struct heapitem
int index;
double dist;
bool operator
};struct distancecomparator
bool operator()(const t& a, const t& b)
};node* buildfrompoints( int lower, int upper )
node* node = new node();
node->index = lower;
if ( upper - lower > 1 )
return node;
}double brute(const t& target)
if ( node->left == null && node->right == null )
if ( dist < node->threshold )
if ( dist + _tau >= node->threshold )
} else
if ( dist - _tau <= node->threshold )
}} void search( node* node, const t& target, int k,
std::priority_queue& heap )
if ( node->left == null && node->right == null )
if ( dist < node->threshold )
if ( dist + _tau >= node->threshold )
} else
if ( dist - _tau <= node->threshold ) }}
};#endif
利用kd樹實現最近鄰搜尋
輸入 已經構造的kd樹,目標點x 輸出 x的最近鄰 1在kd樹中找出包含目標點x的葉節點 從根結點出發,遞迴地向下訪問kd樹。若目標點x當前維的座標小於切分點的座標,則移動到左葉子結點,否則移動到右葉子結點。直到子節點為葉節點為止。2以此葉節點為 當前最近點 3遞迴地向上回退,在每個結點進行以下操作...
最近鄰查詢最優演算法 k d樹的最近鄰搜尋演算法
在k d tree樹中進行資料的k近鄰搜尋是特徵匹配的重要環節,其目的是檢索在k d tree中與待查詢點距離最近的k個資料點。最近鄰搜尋是k近鄰的特例,也就是1近鄰。將1近鄰改擴充套件到k近鄰非常容易。下面介紹最簡單的k d tree最近鄰搜尋演算法。基本的思路很簡單 首先通過二叉樹搜尋 比較待查...
統計學習方法 KD樹最近鄰搜尋
李航老師書上的的演算法說明沒怎麼看懂,看了網上的部落格,悟出一套迴圈 建立好kd樹以後的最近鄰搜尋 我想應該是這樣的 例子是李航 統計學習演算法 第三章56頁 例3.3 步驟結點查詢標記 棧內元素 本次迴圈結束後 最近點最近距離說明a bcde fg初始化000 0000 0abd m 空mdis ...