ML:Scikit-Learn 学习笔记(3) --- Nearest Neighbors 最近邻 回归及相关算法

1 最近邻回归

最近邻回归是用在标签值是连续取值的场景智商的,而不是离散取值,而是用最近邻回归进行查询的点,最后得到的结果是其所有最近邻居的平均值。

scikit-learn 在回归部分,同样实现了两种回归算法,和之前的一样,和KNN思想近似的KNeighborsRegressor ,和RNN思想近似的RadiusNeighborsRegressor 。其中KNR依然是使用K个最相近的点,RNR使用半径r范围内的点,他们俩的具体参数都可以由用户指定。

最原始的最近邻回归算法,在考虑每一个邻居点时,都给与他相同的权重。不过和最近邻分类一样的是,在很多情况下,如果给距离近的点更高的权重,那么效果会更加不错。在Scikit-learn当中,可以使用weight这个参数来指定(uniform或distance,可以参考上一章的内容)。下图就是这两种取值的一个示例
ML:Scikit-Learn 学习笔记(3) --- Nearest Neighbors 最近邻 回归及相关算法_第1张图片
scikit-learn对于最近邻回归,给了一个例子,即给定上一半的人脸,推测其下一半的人脸
ML:Scikit-Learn 学习笔记(3) --- Nearest Neighbors 最近邻 回归及相关算法_第2张图片
感兴趣的小伙伴可以到这里查看人脸推测示例

2 最近邻搜索相关算法

1 Brute Force

在根据官方文档介绍之前,首先贴一个来自于百度百科的介绍:

BF(Brute
Force)算法是普通的模式匹配算法,BF算法的思想就是将目标串S的第一个字符与模式串T的第一个字符进行匹配,若相等,则继续比较S的第二个字符和
T的第二个字符;若不相等,则比较S的第二个字符和T的第一个字符,依次比较下去,直到得出最后的匹配结果。BF算法是一种蛮力算法。

好了,这里介绍的最近邻算法是什么意思?不是已经介绍了KNN RNN等了么?
恩,这里的算法是指如何搜索最近邻局,要知道最近邻的算法每次都需要在所有取值点当中进行搜索,因此有合适的算法去加速这个过程是很有必要的。

Brute Force 算法就是一个最原始(蛮力)邻居搜索做法,Brute Force在寻找邻居时,会把输入的点同所有样本中的点做一个距离计算,然后再排序选择最近的点。因此,对于一个有N个D维样本的情况下,这个做法的时间复杂度是O[D N^2].正因如此,这个算法只适合用在一些样本容量不太大的场景当中,但是在真正的机器学习场景中,往往样本量也会很大吧,这时候BF也不那么使用。
如果你想在scikit-learn当中使用这个算法,可以设置关键词algorithm为‘brute’就可以了,计算的细节可以参照sklearn.metrics.pairwise.

2 KD-Tree

KD-Tree 也就是我们熟知的KD树,也是一个很适合用来搜索最近邻的做法。为了解决BF算法效率低下的问题,人们提出了很多树形结构的算法,树形结构的主要贡献在于,它们一般通过事先的合理组织,降低了我们搜索中的开销,也就是使用树形结构的算法,我们在搜索时可以不用每个样本都去计算距离了,这无疑降低了很多的开销。
ML:Scikit-Learn 学习笔记(3) --- Nearest Neighbors 最近邻 回归及相关算法_第3张图片
我这里有一个资料,可帮助大家理解KD-树,因为我单单贴出解释,估计大家也不懂
KD树核心思想简介
如果我们知道一个点A,他和B的距离很远,而B的距离又和C很近,那么我们也可以推出A和C的距离很远,那么我们就不用去考虑他们之间的距离了。基于这一类的算法,搜索的时间复杂度可以下降到O[D N \log(N)] 或者更好,这样我们就可以抛弃那效率低下的BF算法了。

而KD树,则是最早被广泛用于代替BF进行搜索的算法,并且KD树是一个比四叉树(2维)和八叉树(3维)更加抽象的K维树。KD树使用了二叉树作为基本结构,他用递归的方式对数据进行划分(每一层进行一个维度的划分)。KD树的构建过程是十分迅速的,因为他只需要根据坐标轴进行划分,不用计算多维度的距离。而且只要KD树建立起来,对于每一个点的搜索,其时间复杂度都只有O[\log(N)] 了。在不太高的维度(小于20)下,KD树的效果是很不错的,不过当维度走向更高时,KD树的效率也会随之下降,这也呼应了我们之前提到的“维度之殇”的问题。
在scikit-learn当中,如果需要使用这个算法,设置algorithm为‘kd_tree’就可以了,具体的计算代码可以参照KDTree里的代码。

3 Ball-Tree

Ball-Tree的资料比较少,特别是中文的,这个我之前也没有接触到,这里留一个Wiki的连接Ball tree
好了,KD-Tree是为了解决Brute Force的效率问题,那么Ball-Tree也就是为了解决KD-Tree在高维情况下的效率不佳的另一个做法了。KD树是在笛卡尔坐标系中进行数据划分的,而Ball树则是在 nesting hyper-spheres当中(大概是网状超球面下,我也不大好翻译)划分的。Ball树在构建的时候,比起KD树要复杂许多,不过在最后的搜索过程中,其表现就会非常好。

Ball树根据质心(或者理解为圆心,原词 centroid 质心,但我看他的描述 很像圆心,等我查明了,再更新)C和半径r对数据进行递归的划分,每一个数据点都会被划分到一个特定的圆心C和半径r的的超球体里面,在搜索的时候,候选的点会使用如下的不等式进行筛选:
|x+y| <= |x| + |y|
通过这样的筛选,只用根据半径和圆心就可以计算出一个球体里包含点的距离的上界和下界,那么这样就可以减少很多的减少很多点的计算了。一个超球体里面包含的点,距离其质心都是有一定的距离范围的,那么对于这一个球体里的所有值,我们只需要首先计算和质心的距离,就可以(根据上下界)判定我们是否需要进一步的搜索了。

在scikit-learn当中,如果要使用Ball树,可以algorithm = ‘ball_tree’的设置,相关代码在sklearn.neighbors.BallTree里

恩,下一章里我们谈谈这些算法的具体选择策略好了。

附录

1、本系列第一篇:ML:Scikit-Learn 学习笔记(1) — Nearest Neighbors 最近邻 综述
http://blog.csdn.net/mebiuw/article/details/51051453

2、本系列第二篇:ML:Scikit-Learn 学习笔记(2) — Nearest Neighbors 最近邻 分类
http://blog.csdn.net/mebiuw/article/details/51064063

本文官方文档地址:
http://scikit-learn.org/stable/modules/neighbors.html

你可能感兴趣的:(机器学习,Python++)