k k k近邻算法
k k k 近邻学习是一种常用的监督学习方法,比如:判断一个人的人品,只需要观察与他来往最密切的几个人的人品好坏就可以得出,即“近朱者赤,近墨者黑”。
理论/原理:“物以类聚,人以群分”
- 相同/近似样本在样本空间中是比较接近的,所以可以使用和当前样本比较近的其他样本的目标属性值作为当前样本的预测值。
k k k 近邻法的工作机制很简单:
- 给定测试样本,基于某种距离度量(一般使用欧几里德距离)找出训练集中与其最靠近的k个训练样本,然后基于这k个“邻居”的信息来进行预测。
K N N KNN KNN在做回归和分类的主要区别在于最后做预测时的决策方式不同:
(1)分类预测规则:一般采用多数表决法或者加权多数表决法
假设图中 “?”表示待预测样本,红色圆表示一类,蓝色方块表示一类,2和3表示到待预测样本的距离
1. 多数表决法:
- 每个邻近样本的权重是一样的,也就是说最终预测的结果为出现类别最多的那个类;
- 如图,待预测样本被预测为红色圆
2. 加权多数表决法:
- 每个邻近样本的权重是不一样的,一般情况下采用权重和距离成反比的方式来计算,也就是说最终预测结果是出现权重最大的那个类别;
- 如图,红色圆到待预测样本的距离为3,蓝色方块到待预测样本的距离为2,权重与距离成反比,所以蓝色的权重比较大,待预测样本被预测为蓝色方块。
(2)回归预测规则:一般采用平均值法或者加权平均值法
假设上图中的2和3表示邻近样本的目标属性值(标签值),此时没有类别,只有属性值
- 每个邻近样本的权重是一样的,也就是说最终预测的结果为所有邻近样本的目标属性值的均值;
- 如图,均值为 ( 3 + 3 + 3 + 2 + 2 ) / 5 = 2.6 (3+3+3+2+2)/5 = 2.6 (3+3+3+2+2)/5=2.6
图中,双箭头线上的数表示到待预测样本的距离
- 每个邻近样本的权重是不一样的,一般情况下采用权重和距离成反比的方式来计算,也就是说在计算均值的时候进行加权操作;
- 如图,权重分别为(各自距离反比占距离反比总和的比例):
属性值为3的权重: 1 7 = 1 2 1 2 ∗ 3 + 1 ∗ 2 \frac{1}{7} = \frac{\frac{1}{2}}{\frac{1}{2} * 3 + 1*2} 71=21∗3+1∗221
属性值为2的权重: 2 7 = 1 1 2 ∗ 3 + 1 ∗ 2 \frac{2}{7} = \frac{1}{\frac{1}{2} * 3 + 1*2} 72=21∗3+1∗21- 待预测样本的加权平均值为:
3 ∗ 1 7 ∗ 3 + 2 ∗ 2 7 ∗ 2 = 2.43 3 * \frac{1}{7}*3 + 2 * \frac{2}{7}*2 = 2.43 3∗71∗3+2∗72∗2=2.43
实现kNN分类算法的伪代码:
对未知类别属性的数据集中的每个点依次执行一下操作:
欧氏距离公式:
d = ∑ i = 1 m ( x i − y i ) 2 d = \sqrt{\sum_{i=1}^m(x_i - y_i)^2} d=i=1∑m(xi−yi)2
例如求点 ( 1 , 0 , 0 , 1 ) (1,0,0,1) (1,0,0,1)和 ( 7 , 6 , 9 , 4 ) (7,6,9,4) (7,6,9,4)之间的距离:
( 7 − 1 ) 2 + ( 6 − 0 ) 2 + ( 9 − 0 ) 2 + ( 4 − 1 ) 2 \sqrt{(7-1)^2+(6-0)^2+(9-0)^2+(4-1)^2} (7−1)2+(6−0)2+(9−0)2+(4−1)2
检测分类器效果:
- 可以使用已知类别的数据(当然不告诉分类器),检验分类器给出的结果是否与已知类别相同,通过大量的测试数据,我们可以计算出分类器的错误率。
以上算法的实现是用于分类的,决策规则使用了多数表决法;此算法通过改变决策规则,同样可以用于回归。
源代码可见:Github下 01_k近邻算法.py
样本包括3种特征:
样本包括3种标签:
部分数据格式为:
每年获得的飞行常客里程数 | 玩视频游戏所耗时间百分比 | 每周消费的冰淇淋公升数 | 标签 |
---|---|---|---|
40920 | 8.326976 | 0.953952 | 3 |
14488 | 7.153469 | 1.673904 | 2 |
26052 | 1.441871 | 0.805124 | 1 |
代码可见:02_约会网站的配对效果.py
如下是0的一种表示:
00000000000001100000000000000000
00000000000011111100000000000000
00000000000111111111000000000000
00000000011111111111000000000000
00000001111111111111100000000000
00000000111111100011110000000000
00000001111110000001110000000000
00000001111110000001110000000000
00000011111100000001110000000000
00000011111100000001111000000000
00000011111100000000011100000000
00000011111100000000011100000000
00000011111000000000001110000000
00000011111000000000001110000000
00000001111100000000000111000000
00000001111100000000000111000000
00000001111100000000000111000000
00000011111000000000000111000000
00000011111000000000000111000000
00000000111100000000000011100000
00000000111100000000000111100000
00000000111100000000000111100000
00000000111100000000001111100000
00000000011110000000000111110000
00000000011111000000001111100000
00000000011111000000011111100000
00000000011111000000111111000000
00000000011111100011111111000000
00000000000111111111111110000000
00000000000111111111111100000000
00000000000011111111110000000000
00000000000000111110000000000000
预测错误的总数为:10
手写数字识别系统的错误率为:0.010571
代码可见:03_手写数字识别系统.py
KNN算法的重点在于找出K个最邻近的点,主要方法如下:
1、蛮力实现(brute)
2、KD树(KD_Tree)
除此之外,还有一些从KD_Tree修改后的求解最邻近点的算法,比如:Ball Tree、BBF Tree、MVP Tree等
- 当样本数据量少的时候,我们可以使用brute这种暴力的方式进行求解最近邻,即计算到所有样本的距离。
- 当样本量比较大的时候,直接计算所有样本的距离,工作量有点大,所以在这种情况下,我们可以使用kd tree来快速的计算。
\quad\quad KD树采用从 m m m 个样本的 n n n 维特征中,分别计算 n n n 个特征取值的方差,用方差最大的第 k k k 维特征 n k n_k nk作为根节点。对于这个特征,选择取值的中位数 n k v n_{kv} nkv 作为样本的划分点,对于小于该值的样本划分到左子树,对于大于等于该值的样本划分到右子树,对左右子树采用同样的方式找方差最大的特征作为根节点,递归即可产生KD树。
假设二维样本为: { ( 2 , 3 ) , ( 5 , 4 ) , ( 9 , 6 ) , ( 4 , 7 ) , ( 8 , 1 ) , ( 7 , 2 ) } \{(2,\ 3),\ (5,\ 4),\ (9,\ 6),\ (4,\ 7),\ (8,\ 1),\ (7,\ 2)\} {(2, 3), (5, 4), (9, 6), (4, 7), (8, 1), (7, 2)},下面我们来构建KD树:
x ˉ 1 = 2 + 5 + 9 + 4 + 8 + 7 6 = 5 \bar{x}_1 = \frac{2+5+9+4+8+7}{6} = 5 xˉ1=62+5+9+4+8+7=5
x ˉ 2 = 3 + 4 + 6 + 7 + 1 + 2 6 ≈ 3.83 \bar{x}_2 = \frac{3+4+6+7+1+2}{6} \approx 3.83 xˉ2=63+4+6+7+1+2≈3.83
s x 1 2 = ( 2 − 5 ) 2 + ( 5 − 5 ) 2 + ( 9 − 5 ) 2 + ( 4 − 5 ) 2 + ( 8 − 5 ) 2 + ( 7 − 5 ) 2 6 = 6.5 s^2_{x_1} = \frac{(2-5)^2+(5-5)^2+(9-5)^2+(4-5)^2+(8-5)^2+(7-5)^2}{6} = 6.5 sx12=6(2−5)2+(5−5)2+(9−5)2+(4−5)2+(8−5)2+(7−5)2=6.5
s x 2 2 ≈ 4.7 s^2_{x_2} \approx 4.7 sx22≈4.7
方差表示数据的离散程度,离散程度越大,值越大
因此,选择第1维特征 x 1 x_1 x1 作为根节点
x 1 x_1 x1取值为 2 , 4 , 5 , 7 , 8 , 9 2,4,5,7,8,9 2,4,5,7,8,9中位数取7来划分,小于该值的放在左子树,大于该值的放在右子树
当我们生成KD树以后,就可以取预测测试集里面的样本目标点了。
假设要寻找点 ( 2 , 2.5 ) (2,2.5) (2,2.5)的最近邻点:
使用Logistic算法和KNN算法对鸢尾花数据进行分类,比较结果;
具体内容在代码的注释中有介绍
画出下面两张图,需要将代码整合起来,才能画出来。
代码可见:Github下的02_Logistic回归
目录下05_鸢尾花数据分类.py
,以及03_KNN
目录下04_鸢尾花数据分类.py
。
具体内容将代码介绍
代码可见:Github下的02_Logistic回归
目录下03_信贷审批.py
,以及03_KNN
目录下05_信贷审批.py
。
sklearn
库下的KNeighborsClassifier
实现了两个案例,来属性KNN模型的构建有关机器学习、深度学习的可加QQ交流,博主也在学习中: