① 01 KNN算法 - 概述
KNN算法 全称是K近邻算法 (K-nearst neighbors,KNN)
KNN是一种基本的机器学习算法,所谓K近邻,就是k个最近的邻居。即每个样本都可以用和它 最接近的k个邻近位置的样本 来代替。
KNN是个相对比较简单的算法,比起之前提过的回归算法和分类算法更容易。如果一个人从来没有接触过机器学习的算法,拿到数据后最容易想到的分类方式就是K近邻。打个比方:你们想了解我是个怎样的人,然后你们发现我的身边关系最密切的朋友是一群逗逼,所以你们可以默认我也是一个逗逼。
KNN算法即可以应用于 分类算法 中,也可以应用于 回归算法 中。
KNN在做回归和分类的主要区别,在于最后做预测时候的决策不同。在分类预测时,一般采用 多数表决法 。在做回归预测时,一般使用 平均值法 。
多数表决法: 分类时,哪些样本离我的目标样本比较近,即目标样本离哪个分类的样本更接近。
平均值法: 预测一个样本的平均身高,观察目标样本周围的其他样本的平均身高,我们认为平均身高是目标样本的身高。
再举个例子:
分别根据甜度和脆度两个特征来判断食物的种类。
根据样本我们普遍发现:
比较甜,比较脆的食物都是水果。
不甜,不太脆的食物是蛋白质。
不甜,比较脆的食物是蔬菜。
于是根据目标的样本甜度和脆度两个特征,我们可以对其进行分类了。
k值的选择:
先选一个较小的值,然后通过交叉验证选择一个合适的最终值。
k越小,即使用较小的领域中的样本进行预测,训练误差会减小,但模型会很复杂,以至于过拟合。
k越大,即使用交大的领域中的样本进行预测,训练误差会增大,模型会变得简单,容易导致欠拟合。
距离的度量:
使用欧几里得距离:欧几里得度量(euclidean metric)(也称欧氏距离)是一个通常采用的距离定义,指在m维空间中两个点之间的真实距离,或者向量的自然长度(即该点到原点的距离)。在二维和三维空间中的欧氏距离就是两点之间的实际距离。
决策规划:
分类:多数表决法、加权多数表决法。
回归:平均值法、加权平均值法。
加权多数表决法:
平均值法和加权平均值法:
同样看上面的图,上方的三个样本值为3,下面两个样本值为2,预测?的值。
如果不考虑加权,直接计算平均值:
(3 * 3 + 2 * 2) / 5 = 2.6
加权平均值:权重分别为1/7和2/7。计算加权平均值:
(3 * 3* 1/7 + 2 * 2 * 2/7) / 5 = 2.43
1、蛮力实现(brute):
计算预测样本到所有训练集样本的距离,然后选择最小的k个距离,即可得到k个最邻近点。
缺点:当特征数多、样本数多时,算法的效率比较低。
2、KD树 (kd_tree):
首先对训练数据进行建模,构建KD树,然后根据建好的模型来获取邻近样本数据。
后续内容会介绍KD树搜索最小值的方式,让大家直观感受到KD树比蛮力实现要少检索多少数据。
② K-近邻算法简介
1.K-近邻(KNearestNeighbor,KNN)算法简介 :对于一个未知的样本,我们可以根据离它最近的k个样本的类别来判断它的类别。
以下图为例,对于一个未知样本绿色小圆,我们可以选取离它最近的3的样本,其中包含了2个红色三角形,1个蓝色正方形,那么我们可以判断绿色小圆属于红色三角形这一类。
我们也可以选取离它最近的5个样本,其中包含了3个蓝色正方形,2个红色三角形,那么我们可以判断绿色小圆属于蓝色正方形这一类。
3.API文档
下面我们来对KNN算法中的参数项做一个解释说明:
'n_neighbors':选取的参考对象的个数(邻居个数),默认值为5,也可以自己指定数值,但不是n_neighbors的值越大分类效果越好,最佳值需要我们做一个验证。
'weights': 距离的权重参数,默认uniform。
'uniform': 均匀的权重,所有的点在每一个类别中的权重是一样的。简单的说,就是每个点的重要性都是一样的。
'distance':权重与距离的倒数成正比,距离近的点重要性更高,对于结果的影响也更大。
'algorithm':运算方法,默认auto。
'auto':根绝模型fit的数据自动选择最合适的运算方法。
'ball_tree':树模型算法BallTree
'kd_tree':树模型算法KDTree
'brute':暴力算法
'leaf_size':叶子的尺寸,默认30。只有当algorithm = 'ball_tree' or 'kd_tree',这个参数需要设定。
'p':闵可斯基距离,当p = 1时,选择曼哈顿距离;当p = 2时,选择欧式距离。
n_jobs:使用计算机处理器数目,默认为1。当n=-1时,使用所有的处理器进行运算。
4.应用案例演示
下面以Sklearn库中自带的数据集--手写数字识别数据集为例,来测试下kNN算法。上一章,我们简单的介绍了机器学习的一般步骤:加载数据集 - 训练模型 - 结果预测 - 保存模型。这一章我们还是按照这个步骤来执行。
[手写数字识别数据集] https://scikit-learn.org/stable/moles/generated/sklearn.datasets.load_digits.html#sklearn.datasets.load_digits
5.模型的方法
每一种模型都有一些它独有的属性方法(模型的技能,能做些什么事),下面我们来了解下knn算法常用的的属性方法。
6.knn算法的优缺点
优点:
简单,效果还不错,适合多分类问题
缺点:
效率低(因为要计算预测样本距离每个样本点的距离,然后排序),效率会随着样本量的增加而降低。
③ 02 KNN算法 - KD Tree
KD Tree 是KNN算法中用于计算最近邻的快速简便的构建方式。
当样本量少的时候,用 brute 直接搜索最近邻的方式是可行的。即计算到所有样本的距离。但当样本量庞大时,直接计算所有样本距离的工作量很大,这种情况使用 KD Tree 可以节约大量时间成本。
KD树采用从m个样本的n维特征中,分别计算n个特征取值的方差,用 方差最大 的第k维特征n k 作为 根节点 。对于这个特征,选择取值中的 中位数 n kv 作为样本的划分点,对于小于该值的样本划分到 左子树 ,对于大于等于该值的样本划分到 右子树 ,对左右子树采用同样的方式找 方差最大的特征 作为 根节点 ,递归产生KD Tree。
为什么要选择方差最大的进行划分?
构建树的目的是加快我的搜索过程。
既然我想加快我的搜索过程,要就意味着我最终的数据落在某个叶子节点上。我希望只需搜索整个二叉树的某一些列即可,那么最好的划分方式,就是让我的每个分支上数据的差异性最大化。
那么衡量数据差异性的最基础的数学指标是什么?
是方差。方差越大,意味着数据的离散程度就越大,我将离散程度由大到小的数据一分为二,方差小意味着数据更集中到了一起。
现在有一个二维样本: {(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)}
1、计算x1和x2每一列对应的方差
a、通过pandas计算出的是 样本方差:
/ (n-1)
0| 6.966667
1| 5.366667
dtype: float64
b、通过numpy计算出的是 总体方差:
/ n
[[2 3]
[5 4]
[9 6]
[4 7]
[8 1]
[7 2]]
[ 5.80555556 4.47222222]
[ 5.80555556 4.47222222]
第一个树的划分:基于x 1 进行划分
[2,4,5,7,8,9]的中位数是5和7的平均值6。
虽然严格意义上说中位数是6,但是在计算机中我们人为得定义x 1 的中位数是7。
左侧:(2,3)(5,4)(4,7) (7,2)
右侧: (9,6)(8,1)
第二个树的划分:根据右侧(9,6)(8,1)的x 2 进行划分
下侧:x 2 ≤ 6;上侧x 2 >6
第二个树的划分:根据左侧(2,3)(5,4)(4,7) (7,2)的x 2 进行划分
寻找2、3、4、7的中位数 4 进行划分
....
注意:每次生成的划分都是一个矩形。当叶子节点无法被继续划分的时候,KD树的构建完成,递归结束。
我们生成了KD Tree后,现在就可以去预测测试集里面的样本目标点了。
1、对于一个目标点,先在KD树里找到包含目标点的叶子节点。
2、以目标点为圆心,以 目标点 到 叶子节点样本实例 的距离为半径,得到一个超球体,最近邻的点一定在这个超球体内部。
3、然后返回叶子节点的父节点,检查另一个子节点包含的超矩形体是否和超球体相交。
4、如果相交就倒这个子节点寻找着是否有更加近的近邻,有的话就更新最近邻。
5、如果不相交,直接返回父节点中的父节点,在另一个子树继续搜索最近邻。当回溯到根节点时,算法结束。
6、此时保存的最近邻节点就是最终的最近邻。
如果现在想找(2,4.5)这点的最近邻,该如何操作?
1、画出二叉树:
2、寻找(2,4.5)这点:
一个比较好的理解方式:首先找到第一个最近邻,然后画出一个圆。然后逐渐收缩圆的半径,查看每次缩小后的圆是否能够和矩形相交于一个更小的最近邻点,如果有则更新。直到回到根节点。