KNN面试题——click here
导论
sklearn.neighbors提供了基本的用于非监督学习和监督学习的方法。非监督最近邻算法是其它许多学习方法的基础,基于近邻的监督学习方法主要用在两方面:离散标签的分类问题和连续标签的回归问题。
最近邻方法背后的原则就是去寻找预先定义好的一个数,(这个数描述的是训练样本到某个新的点的距离最近点的个数),从这些点的标签中去预测。这个数(最近邻样本的个数)可以是用户自定义的常数(k-近邻学习),或者是基于局部点的密度(基于半径的近邻学习)。
1、最近邻算法
*1、Brute Force
这是一种暴力求解的方法,对 个维度的 个样本,这种方法的规模达到 。在小数据规模的时候,Brute Force是非常具有竞争力的,但是随着样本数据 的增加,brute-force方法就会迅速变得不可行。
*2、K-D Tree
为了解决Brute Force计算无效的问题,一种基于树结构的数据类型被发明出来。通常这些结构常常都是通过对样本进行有效编码聚集距离信息来减少必要的计算。基本的想法是:如果点A离点B非常远,而点B离点C非常近,我们就知道点A和点C是非常远的,不需要具体的去计算它们的距离就可以得出这个结果。通过这种方式,计算最近邻搜索的消耗就减少到 甚至更好。这对于大规模数据 相较于 brute-force是有显著提升的。
KD Tree就是采用了这种思想。K-D Tree是一种二叉树结构,它沿着数据轴的递归地划分参数空间,将其划分为嵌套的正交各向异性区域,数据点对于放入其中。KD Tree的构造非常快,因为分区只是沿着数据轴执行吗,不用计算D-维的距离。一旦构造完成,一个查询点的最近邻只需 步的计算就可以被确定。尽管在低纬度(D < 20)的近邻查询的时候,KD tree方法非常快,但是当D增加时,这种方法也会失效。
*3、Ball Tree
为了解决KD Tree在高维空间无效的问题,ball tree 数据结构被发展出来了。kD tree 划分数据是沿着笛卡尔坐标轴的,但是ball tree是沿着一系列的嵌套的超球面。这使得在构造树方面要比KD tree消耗多,但是这种结构也会让其在近邻搜索方面非常高效,甚至在很高的维度上。
一个 ball tree递归地将数据分到被定义中心为 、半径为 地节点中,这样节点中的每一个点都在由 、 定义的超球面内。利用三角形不等式来减少一个邻居点搜索的候选点:
在这种设置下,只需计算测试点和质心之间的距离就足以确定到节点内所有点的距离的上界和下界。由于球树节点的球面几何特性,尽管实际性能高度依赖于训练数据的结构,但它在高维上的性能优于KD-tree。
*4、最近邻算法选择(关键)
对于给定的数据集,寻找最佳算法是很复杂的一件事,依靠很多因素:
· 样本数 和维度
Brute Force查询时间——
Ball Tree查询时间——
KD Tree查询时间——对 ——
——对 ——
对于小数据集 小于30,选择brute force方法比基于tree的方法更高效。
· 数据结构
数据的内在维数和/或数据的稀疏性。内在维数是指数据所在流形的维数d≤D,可以线性嵌入或非线性嵌入到参数空间中。稀疏性是指数据填充参数空间的程度。
Brute Fore 查询时间不受数据结构的影响
Ball Tree 和 KD Tree会收到数据结构很大影响。通常说,稀疏数据而且内在维度小会导致加快查询时间。
在机器学习中的数据结构通常都是很结构化的,非常适合基于树结构的查询。
· 邻居点数目k
Brute Forece 查询时间很大程度不受k值影响。
Ball Tree 和 KD Tree的查询时间会随着k的增加而变慢。
当 与 相当时,这种情况用Brute Force更高效。
*5、leaf_size的影响
对于小的样本数,brute force搜索比基于树结构的查询更有效。但是实际上对ball tree和KD tree来说,可以在内部转换成brute force通过叶子节点。这种转换可以通过参数left_size来指定。这个参数的选择有很多影响:
· 构造时间
一个大的 left_size 会导致加快构造树的时间,因为更少的节点需要被创造。
·查询时间
大的或者小的 left_sie都会导致次最优的查询损耗。对于 left_size 接近1,在遍历节点的时候显著减慢查询时间;对于 left_size 接近训练集大小的时候,查询时间接近brute force。一个好的折中方法就是选择 left_size = 30,这是默认的参数。
· 内存
随着left_size的增加,存储树结构的内存就会减少。
2、最近邻在分类问题的应用(最近邻分类)
基于近邻的分类是一种基于基类的距离的学习,没有显式的学习的方法:它并没有尝试去构造一个模型,而是简单的存储训练数据的样本。分类就是从最近邻的每个点去得出大部分表决的那个类。
在 scikit-learn的实现中有两类最近邻分类器:KNeighborsClassifier基于查询点的最邻近k个点去实现学习,k是用户定义的一个整数,RadiusNeighborsClassifier基于对每个训练点的固定半径为 的圆中邻居数量实现学习, 是用户定义的一个值。
基本的最近邻分类用的是统一的权重,但是在有些情况下,为近邻点加上权重让近邻点贡献的更多会比前面用统一的权重要好。可以通过 来设置统一权重,这是默认情况,基于距离的权重设置 。还可以是用户自定义的。
3、最近邻在回归问题上的应用(最近邻回归)
基于近邻的回归问题可以用在数据标签是连续的而不是离散的。对于查询点的标签就是计算它最近邻点的标签的均值。
同样在 scikit-learn的实现中有两类最近邻回归器:KNeighborsRegressor基于查询点最近邻的k个点来实现学习,k是用户定义的一个整数, RadiusNeighborsRegressor基于查询点的固定半径 内的邻居来实现学习, 是用户定义的一个值。
同样的,跟上面一样,权重也分为三类: ‘uniform’, ‘distance’, user-defined,设置方法也与上面一样。
4、最近邻中心分类器(Nearest centroid classifier)
每个类都用中心去表示,在测试样本被分类到离它最近的中心的类。
Nearest Shrunken Centroid
NearestCenteroid分类器有一个 shrink_threshold 参数,实现最近收缩中心分类器。实际上,每个质心的每个特征值除以该特征的类内方差。然后通过shrink_threshold降低特性值。最值得注意的是,如果某个特定特征值过零,则将其设置为零。实际上,这消除了该特性对分类的影响。这是有用的,例如,删除噪声特征。
5、近邻成分分析(Neighborhood Components Analysis)
近邻成分分析(NCA)是一种距离度量学习算法,旨在提高基于标准欧氏距离的最近邻分类的准确率。这个算法直接最大化训练集上留一法KNN分组的随机变量。它可以学习到一个在数据上的低维线性投射,被用开数据可视化和快速分类。
*1、classification
结合最近类分类器,NCA在分类方面非常有效,因为它很自然的处理多分类问题而不需要增加模型大小,不需要引入用户微调的而外参数。
*2、降维
NCA可以用在执行监督降维。
*3、数学公式
NCA的目标是学习一个最优的线性转换矩阵,大小为 (n_components, n_features),这个矩阵能够最大化所有样本 被正确分类的正确概率 的和:
这里 是样本 被正确分类的概率,
这里 表示和样本 相同类的一个点集, 是一个在欧氏距离上的softmax作用:
NCA 被视作在学习Mahalanobis 距离矩阵:
这里 是一个大小为(n_features, n_features)的对称半正定矩阵。
参考资料:
[1] Nearest Neighbors