k近邻法(k nearest neighboralgorithm,k-NN)是机器学习中最基本的分类算法,在训练数据集中找到k个最近邻的实例,类别由这k个近邻中占最多的实例的类别来决定,当k=1时,即类别为最近邻的实例的类别。
k-d树
k-dtree是一颗平衡二叉树,kd代表k-dimension,每个节点即为一个k维的点。每个非叶节点可以想象为一个分割超平面,用垂直于坐标轴的超平面将空间分为两个部分,这样递归的从根节点不停的划分,直到没有实例为止。
经典的构造k-d tree的规则如下:
1、随着树的深度增加,循环的选取坐标轴,作为分割超平面的法向量。对于3-dtree来说,根节点选取x轴,根节点的孩子选取y轴,根节点的孙子选取z轴,根节点的曾孙子选取x轴,这样循环下去。
2、每次均为所有对应实例的中位数的实例作为切分点,切分点作为父节点,左右两侧为划分的作为左右两子树。
对于n个实例的k维数据来说,建立kd-tree的时间复杂度为O(k*n*logn)。
例如存在6个实例点,分别为(2,3), (5,4), (9,6), (4,7), (8,1),(7,2),下图(引自wiki)为平面对应的切分和对应的k-d tree。
以最近邻搜索(nearest neighborsearch(NN))算法为例,说明对kd-tree进行搜索的过程。首先从根节点出发找到包含目标点的叶节点,目标点的最近邻一定在以目标点为中心,并通过当前叶节点的超球体内部,然后从该叶节点出发,依次回退到父节点,如果父节点的另一子节点的区域与超球体相交,则到该区域继续查找,不断的查找与目标点最近邻的节点,直到不能查找最近邻的节点为止。在实例随机分布的情况下,找到最近邻的时间复杂度为O(logn)。在最差的情况下为O(k*N^(1-1/k)),可以看出,当维数和实例数相当的时候,近似于进行线性扫描,kd-tree更适合N≫2^k的情形。
如下图(引自wiki)为一个简单的NNS查找示例:
改进的方案包括一些近似算法,如在实际应用中的BBF(best-bin-firstsearch)算法,源代码可以参见相关的SIFT源码实现。
在经典的SIFT算法中,SIFT特征点的维度为128,进行特征匹配的时候,对其中一幅图像的特征点建立k-dtree,SIFT特征点匹配为了消除误匹配点,需要找到2个最近邻的特征点,此时即为k=2,采用BBF算法从k-dtree中找出2-NN,并对两个距离进行比较,当二者相差较大才接受最近邻点为匹配点。
k近邻法也可应用到文本分类问题,在文本特征通常采用TF*IDF,对特征数据一般都会要求对数据进行规则化处理,包括进行SIFT特征的规则化。