目录
- KNN算法
- KD-Tree
1. KNN算法原理
1.1 基本原理
- KNN(K-nearest-neighbors)是一种基本的机器学习算法,所谓K近邻,就是K个最近的邻居的意思,说的是每个样本都可以用与它最近的K个邻居来表示。比如,判断一个人的人品,只需要观察与之最密切的几个人的品行即可;KNN算法即可以用到分类应用中,也可以用到回归应用中;
- KNN在做回归和分类的主要区别在于最后做预测的时候的决策方式不同。KNN在做分类预测时,一般采用多数表决法,在做回归预测时,一般用平均值法;
1.2 实现步骤
- 从训练集合中获取k个离待预测样本距离最近的样本数据;
- 根据获取得到的K个样本数据来测试当前待预测样本的目标属性值;
- K越小,模型越复杂,模型容易过拟合;K越大,模型越简单,容易产生欠拟合;
1.3 KNN的三要素
-
在KNN算法中,非常重要的主要是三个要素:
- K值得选择:对于K值得选择,一般根据样本的分布选择一个较小的值,然后通过交叉验证的方式,来选择一个比较合适的最终值;当选择比较小的k值时,表示使用较小领域中的样本进行预测,训练误差会减小,但是会导致模型变得复杂,容易发生过拟合;当选择较大的K值得时候,表示使用较大领域中的样本进行预测,训练误差会增大,同时会使模型变得简单,容易导致欠拟合;
- 距离的度量:一般使用欧氏距离(欧几里得距离)
- 决策规则:在分类任务中,一般使用多数表决法或者加权多数表决法;在回归任务中,主要使用平均值法,或者加权平均值法;
-
在KNN分类应用中,一般采用多数表决法或者加权多数表决法;
| Item | description |
|---|---|
| 多数表决法 | 每个近邻样本的权重是一样的,也就是说最终预测的结果为出现类别最多的那个类;【简单粗暴的多数表决】 |
| 加权多数表决法 | 每个近邻样本的权重不一样,一般情况下,采用权重和距离成反比的方式来计算。也就是说最终预测结果为出现权重最大的那个类别 |
- 在KNN分类应用中,一般采用平均值法或者加权平均值法;
| Item | description |
|---|---|
| 平均值法 | 每个近邻样本的权重是一样的,也就是说最终预测的结果为所有近邻样本目标属性值得均值;【简单粗暴的平均值法】 |
| 加权平均值法 | 每个近邻样本的权重不一样,一般情况下,采用权重和距离成反比的方式来计算。也就是说计算均值的时候采用加权操作; |
1.4 KNN算法的实现方式
- KNN算法的重点在于找出K个最近邻的点,主要方式有以下几种:
- 蛮力实现(brute):计算预测样本到所有训练集样本的距离,然后选择最小的K个距离即可得到K个最近邻的点。缺点在于:当特征数量比较多、样本数量比较多的时候,算法的执行效率比较低;
- KD树(kd_tree):KD树算法中,首先是对训练数据进行建模,构建KD树,然后再根据建好的模型来获取邻近样本数据;
- 除此之外,还有一些从KD_Tree修改后求解最近领点的算法,比如:Ball Tree;BBF tree;MVP Tree;
2. KD Tree
2.1 KD Tree的优势
- 如果用暴力搜索法假设训练集中有1KW数据,而K=10,那么预测的话需要计算10*1kw,时间开销太大;
- KD Tree是KNN算法中,用于计算最近邻的快速、便捷的构建方式;
- 当样本数据量比较少的时候,我们可以使用brute这种暴力的方式求解最近邻,即计算到所有样本的距离。但是当样本量比较大的时候直接计算所有样本的距离,工作量有点大。所以在这种情况下,我们可以使用kd tree来快速计算;
2.2 KD Tree的构建方式
- KD Tree采用从m个样本中的n维特征中,分别计算n个特征取值的方差,用方差最大的第k维特征作为根节点。对于这个特征,选择取值的中位数作为样本的划分点,对于小于该值得样本划分到左子树,对于大于等于该值的样本划分到右子树,对于左右子树采用同样的方式找到方差最大的特征作为根节点,递归即可产生KD树。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b9fWbMld-1574954315847)(attachment:image.png)] - 二维样本{(2, 3), (5, 4), (9, 6), (4, 7), (8, 1), (7, 2)}
- 当我们生成KD Tree之后,就可以去预测测试集里面的样本目标点了;对于一个目标点,我们首先要在KD树里面找到包含目标点的叶子节点。以目标点为圆心,以目标点到叶子节点样本实例的距离为半径,得到一个超球体,最近邻的点一定在这个超球体的内部。然后返回叶子节点的父节点,检查另一个叶子节点包含的超矩形体是否与超球体相交,如果相交就是找到了这个子节点寻找是否有更加近的近邻。如果不想交那就简单了,我们直接返回父节点的父节点,在另一个子树继续最邻近。当回溯到根节点时,算法结束,此时保存的最近邻节点就是最终的最近邻。
- 找到所属的叶子节点后,以目标点为圆心,以目标点到最近样本点为半径画圆。从最近样本点往根节点进行遍历,如果这个圆和分割节点的分割线有交线,那么就考虑分割点的另外一个子树;如果在遍历过程中,找到距离比刚开始距离近的样本,那就进行更新操作。一致遍历迭代到根节点。
2.3 KNN参数说明
| 参数 | KNeighborsClassifier | KNeighborsRegressor |
|---|---|---|
| weights | 样本权重,可选参数:uniform(等权重)、distance(权重和距离成反比,越近影响越强);默认为uniform | |
| n_neighbors | 近邻数,默认为5 | |
| algorithm | 计算方式,默认为auto,可选参数:auto、ball_tree、kd_tree、brute,推荐选择kd_tree | |
| leaf_size | 在使用kd_tree的时候,叶子数量,默认为30; | |
| metric | 样本之间的距离度量公式,默认为minkowski;当参数为2的时候,其实就是欧几里得距离 | |
| p | 给定minkowski距离中p的值,默认为2; |
3. KD-Tree的构建和搜索
3.1 如何构建KD-Tree
3.1.1 几个概念
- 构建KD树的过程,就是不断地选择垂直于坐标轴(切分轴)的超平面将样本集所在的K维空间二分,生成一系列不重叠的k维超矩形区域;
3.选择切分轴:有多种方法可以选择切分超平面,最常见的是选择数值方差最大的轴【选择max-min】最大的轴; - 切分点:选择既定切分轴的中位数,这样切分后可以保证得到的左右子树的深度差不超过1,所得的二叉树为平衡二叉树;
3.1.2构建过程
对于输入的数据集T={, ,…, },其中 = (, , )
- 构建根节点,根节点为对应于包含T的K维超矩形区域。选择T中方差最大的特征为切分轴,列向量的中位数为切分点,使用过切分点且与垂直于切分轴的超平面将超矩形区域切分成两个子区域,并对应于其左右子节点。其中,左节点各区域中的不大于切分点,右节点区域个点的大于切分点,并将切分点保存在根节点;
- 对子节点重复步骤1,即对于深度为j的节点,选择为切分轴、包含的区域中所有点的中位数,其中s=(j+1)%k ,将对应的区域划分成两个子区域,并对应其左右两个子节点,直至两个子区域没有实例为止;
- 构建好的二维KD树为:
3.2 KD树的搜索
3.2.1 KD树搜索的时间复杂度
利用kd树搜索最近邻的样本,可以省去对大部分数据的搜索,从而减少计算量。当数据随机分布时,搜索最近邻的时间复杂度为O(logN),N为样本量,当空间维数接近N时,效率迅速下降;
3.2.2 KD树最近邻搜索算法步骤
对于给定的一个样本,首先根据KD树找到包含输入实例的叶节点。然后从该叶节点出发,依次回退到父节点。输入样本与其最近邻样本点形成的超球体的内部一定没有其他的样本点。
- 从根节点出发,找到包含输入实例的叶节点,如果输入样本的和切分点相同维的坐标值小于切分点时落入到左节点,否则落入到右节点,直到达到叶节点。并将当前叶节点作为“当前最近点”,递归地向上回退,对每个节点执行以下操作:
- 若该节点保存的样本比“当前最近点”距离更近,则将此样本作为“当前最近点”;
- “当前最近点”一定存在于该节点一个子节点对应的区域,检查该子节点的兄弟节点对应区域是否有更近的点。即若“当前最近点”与输入样本形成的超球体与“当前最近点”的父节点的分割超平面相交,则“当前最近点”的兄弟节点有可能又更近的点,此时该兄弟节点作为根节点一样,执行步骤1.若不相交,则向上回退;
- 当回退到根节点时,搜索结束。最后的“当前最近点”,即为输入实例的最近邻点。