k-近邻算法
开篇
k-近邻算法
是比较简单的一种机器学习算法,其核心思想可以用一句话来概括:近朱者赤,近墨者黑。
在具体介绍该算法之前,先通过一个栗子对该算法做一个感性上的认识。
Python爱好者 or C爱好者 ?
上图中,每一个形状(三角形,圆形)都代表了一个人。总共有两种形状,说明这些人总共可以分为两类:Python爱好者、C爱好者。
三角形一共有7个,代表喜欢写Python的总共有7人;
圆形一共有6个,代表喜欢写C语言的总共有6人。
现在,突然来了一个不知道是喜欢写Python还是C语言(并且只可能属于其中之一)的人—–五角星,要求你来判定这个人所属的类别。
emm…
你可能会说,那看看图上距离这个人(五角星)最近的几个人所属类别就可以了啊!比如就看距离这个人最近的3
个人:其中有两个人喜欢写Python,而只有一个人喜欢写C语言(如下图所示)
按照少数服从多数的原则,将这个新来的人(五角星)归类到三角形(Python爱好者)类别就搞定啦!
最终分类结果
上面的栗子其实就使用了k-近邻算法的思想。现在,让我们对该算法做一个完整的定义。
什么是k-近邻算法 ?
k-近邻算法是一种有监督的机器学习算法,对于有监督的机器学习算法来说,其训练数据集的一般格式如下(0:类别1;1:类别2):
当n取4,m取3时,就是一个含有4个样本,每个样本有3个特征的数据集了,如下图
k-近邻算法的核心思想为:对于一个给定的训练集,当新的样本到来时,找到训练集中与新样本距离最近的k
个样本,然后查看这k个样本所属类别,并将新样本归类到这k个样本中大多数样本所属类别中。
没错,k-近邻算法的思想就是这么简洁。接下来,我们将用Python来实现该算法。
用Python实现k-近邻算法
首先明确,k-近邻算法中的k
是我们自己指定的(当然k的选取是有技巧的,这个稍后会说,这里我们仅仅关心如何用Python实现该算法),训练数据集也是自己的(废话,训练集肯定要自行准备的啊),所以有两个参数需要我们自行传入,其一为k
,其二为训练集data
。
在实现k-近邻算法之前,先自行定义训练集:
1 | class DataSet(): |
然后查看下训练数据集的分布(0和1代表样本所属的类别)
1 | data=DataSet() |
现在开始实现k-近邻算法:
1 | class MyKNN(): |
由于k-近邻算法涉及到了距离,因此需要写一个计算距离的方法。距离的度量方式有很多,这里我们采用大家最为熟悉的L2距离,也就是欧氏距离:
1 | def cal_dist(self,sample1,sample2): |
接下来是k-近邻算法的核心实现步骤:
- 1.分别计算新的样本与训练集中所有样本之间的距离;
- 2.按照距离从小到大排序;
- 3.选取距离新样本最近的k个距离及其对应样本所属类别;
- 4.将新样本归类到与其距离最近的k个样本中大多数样本所属类别。
1 | def run(self,new_sample_feature): |
这样,我们就实现了k-近邻算法,完整代码如下:
1 | import numpy as np |
测试k-近邻算法
我们前面已经实现了k-近邻算法,那么它的分类能力究竟如何呢?
现在,自定义一个测试集,用刚刚实现的k-近邻算法对测试集样本进行分类(这里的k不妨取3):
1 | test_samples_feature=np.array([[2.4,2.5], |
输出:
1 | 第1个样本所属类别为1 |
那这个结果可不可靠呢? 我们需要评估一下。千言万语不及一张图,所以这里我们还是用可视化的方式来演示。
在训练数据可视化结果图的基础上,将测试数据也绘制在这张图上,完整代码如下:
1 | data=DataSet() |
观察上图,当k取3时:
与样本1距离最近的3个样本中,大多数样本都是属于类别1的(本例是特例,全部3个样本都属于类别1),因此样本1应该归类到类别1;
与样本2距离最近的3个样本中,大多数样本都是属于类别0的,因此样本2应该归类到类别0;
与样本3距离最近的3个样本中,大多数样本都是属于类别1的,因此样本3应该归类到类别1;
与样本4距离最近的3个样本中,大多数样本都是属于类别0的,因此样本4应该归类到类别0。
所以,最终的分类结果应该是:[1,0,1,0],这与程序跑出来的结果是对应的,从而我们实现的k-近邻算法是成功的。
更多关于k-近邻算法的使用技巧
- k值通常取奇数,这是因为,当k取偶数,比如k=2时,有可能距离新样本最近的2个样本分别属于两个不同的类别,此时无法判定新样本所属类别;
- k不宜过大,也不宜过小,通常采用交叉验证的方式进行k值的选取;
- 同大多数机器学习算法一样,在实际应用k-近邻算法时,为了减少特征的量纲不同而导致的各特征重要程度不一致现象,往往在将数据喂入机器学习算法之前,先对数据做归一化或者标准化等预处理工作。举个例子,对于具有3个特征的两个样本:[0.2,0.3,999], [0.3,0.2, 899],由于第三个特征数值相对于前两个特征较大,因此在计算这两个样本的距离时,第三个特征将主导最后的距离计算结果,而前两个特征的作用几乎被忽略不计了,这样的话,就相当于前两个特征传递的信息丢失了,这可不是我们所希望的!因此这一步很有必要。
参考:
- [1] [李航-统计学习方法]
- [2] [Peter Harrington-机器学习实战]