在计算机科学中,球树(ball tree)是一种空间划分数据结构,用于组织在多维空间中的点。球数之所有得到此名,是因为它将数据点划分为一组嵌套的超球体。这种类型的数据结构特征使其在很多方面都有用,特别是在最近邻搜索。
一般的在特征向量维度小于20的时候是可以用KD-Tree的,但是更高维度的时候建议使用Ball-Tree,这种算法的效率更高
非正式描述
球树是二叉树,其中每个结点定义一个d维的超球面,或称为球, 其中包含被搜索的点的子集。树的每个内部结点将数据点划分为两个不相交的集合,这两个集合与不同的球相关联。当球本身可能相交时,每个点根据它到球心的距离被分配到其中一个球中。树中每个叶结点定义了一个球并枚举该球内的所有数据点。
树里的每个结点定义了一个能包含这个子树所有数据点的最小球。这就产生一个有用的性质,对于给定的测试点 ,到树中球B中任意一点的距离大于或等于从 到该球的距离。
表示球B的任一点到某点
的最小距离。
构造球树(ball tree)
最简单的构造就是“k-d构造算法”,类比构造k-d树的过程。这是一种离线算法,也就是说,一种同时对整个数据集进行操作的算法。树是通过递归地将数据点分割成两个集合而自顶向下构建的,分割线是沿着单一维度的增大方向排列,用该维度上所有点的中值对集合进行划分。要找到每个内部节点的划分,要在该结点包含的样本数量上花费线性时间,从而得到时间复杂度为 ,n是数据点的个数。
伪代码:
function construct_ball_tree is
input: D, 数据点的数组
output:B,构造好的ball tree的根节点
if 只有一个数据点 then
创建一个叶子结点B包含这一单一的点
return B
else:
让c为最宽的维度
让p为这个维度的中心点,
让L, R设为左集合和右集合
创建带有两个孩子的B:
B.pivot := P
B.child1 := contruct_balltree(L),
B.child2 := contruct_balltree(R),
让B.radius 为p到孩子的最大距离
return B
end if
end function
最近邻搜索
球树最近邻算法以深度优先的顺序检查结点,从根节点开始。在搜索过程中,算法维护一个max-first优先队列(通常用堆实现),记作Q,表示到目前为止遇到的k个最近的点。在每个结点B上,它可能执行三个操作之一,然后最终返回一个更新版本的优先队列:
(1)如果测试点
到当前结点B的距离大于Q中最远的店,则忽略B,返回Q;
(2)如果B是一个叶结点,则扫面B中枚举的每个结点,然后更新队列,然后返回;
(3)如果B是一个内部节点,递归调用B的两个子结点算法,搜先搜索中心更靠近
的子结点。在每次调用后更新队列,然后返回。
伪代码:
function knn_search is
input:
t, the target point for the query
k, the number of nearest neighbors of t to search for
Q, max-first priority queue containing at most k points
B, a node, or ball, in the tree
output:
Q, containing the k nearest neighbors from within B
if distance(t, B.pivot) - B.radius ≥ distance(t, Q.first) then
return Q unchanged
else if B is a leaf node then
for each point p in B do
if distance(t, p) < distance(t, Q.first) then
add p to Q
if size(Q) > k then
remove the furthest neighbor from Q
end if
end if
repeat
else
let child1 be the child node closest to t
let child2 be the child node furthest from t
knn_search(t, k, Q, child1)
knn_search(t, k, Q, child2)
end if
end function[2]
参考资料:
【1】Ball tree