这篇拖的时间真的有点太长了,距离上篇已经一个多月了.
回忆一下上篇我们讲了如何构造KD-TREE,这篇我们讲如何实现K近邻.
原理:
通俗来说就是我们利用KD-TREE,快速求出距离我们最近的K个点,然后这K个点中某类型样本最多,我们就把我们这个测试点归到这个类型中.
具体讲到实现就是一个二叉树的搜索函数,然后把搜索计算的所有点存储到一个列队queue中,最后来判断类型。
def search(kdtree,point):
global queue
global dis_min
global kdtree_min
d = kdtree.dim
print kdtree.root
if point[d] < kdtree.root[d]:
if kdtree.left !=None:
search(kdtree.left,point)
if abs(point[d] - kdtree.root[d]) <= dis_min:
if kdtree.right!= None:
search(kdtree.right,point)
else:
if kdtree.right != None:
search(kdtree.right,point)
if abs(point[d] - kdtree.root[d]) <= dis_min:
if kdtree.left != None:
search(kdtree.left,point)
dis = distance(kdtree,point)
queue.append([kdtree.root,dis])
if dis_min > dis:
dis_min = dis
return kdtree
search(kd_tree,point)
queue = sorted(queue,key = lambda x:x[1])
哇哦,又是一个递归函数。先思考两个问题:
1、我们为什么要构造KD-TREE?
是为了节约计算的时间,某些样本根本就不用计算。
2、什么标准构造的KD-TREE?
从第一个维度的中位数开始划分为左右两个子集,再从第二个维度的中位数开始划分为左右两个子集。
好了,思考完这两个问题,程序自然逻辑就清晰了。
上一张图大家看看:
整个范围被划为四块,可以看到右上角范围内有一个测试点,首先我们会计算测试点离这个范围内样本点的最小距离是多少,然后以这个测试点为中心画圆,如果画圆区域包含了另一个子集(右下区域),那么我们还得进入另一个子集搜索,如果没有包含,那么我们就可以省去搜索另一个自己的时间了!
if point[d] < kdtree.root[d]:
if kdtree.left !=None:
search(kdtree.left,point)
if abs(point[d] - kdtree.root[d]) <= dis_min:
if kdtree.right!= None:
search(kdtree.right,point)
如果测试点的d维值小于其划分根节点的值,那么它应该被划为左子树,搜索左子树,计算最小距离dis_min,如果测试点与根节点的距离小于等于dis_min,我们就需要进入到右子树进行搜索了。
queue.append([kdtree.root,dis])
程序中我们会把搜索过的节点以及其距离测试点的距离都存入到queue中,最后利用sorted函数对其按距离大小排序,最后的最后只要统计最近的K个样本情况就行了,我们的K近邻就完整了。
最后的最后: 更多更新文章关注我的公众号: