目录
一、实验目的
通过本实验掌握kNN算法的原理,熟悉kNN算法。
二、实验的软、硬件平台
python 3.6.5
CourseGrading在线实验环境
三、实验内容概述
1.kNN算法简介
k近邻法(k-nearest neighbor, kNN)是1967年由Cover T和Hart P提出的一种基本分类与回归方法。它的工作原理是:存在一个样本数据集合,也称作为训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一个数据与所属分类的对应关系。输入没有标签的新数据后,将新的数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本最相似数据(最近邻)的分类标签。一般来说,我们只选择样本数据集中前k个最相似的数据,这就是k-近邻算法中k的出处,通常k是不大于20的整数。最后,选择k个最相似数据中出现次数最多的分类,作为新数据的分类。
所谓K最近邻,就是k个最近的邻居的意思,说的是每个样本都可以用它最接近的k个邻居来代表。kNN算法的核心思想是如果一个样本在特征空间中的k个最相邻的样本中的大多数属于某一个类别,则该样本也属于这个类别,并具有这个类别上样本的特性。该方法在确定分类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。 kNN方法在类别决策时,只与极少量的相邻样本有关。由于kNN方法主要靠周围有限的邻近的样本,而不是靠判别类域的方法来确定所属类别的,因此对于类域的交叉或重叠较多的待分样本集来说,kNN方法较其他方法更为适合
上图中,绿色圆要被决定赋予哪个类,是红色三角形还是蓝色四方形?如果K=3,由于红色三角形所占比例为2/3,绿色圆将被赋予红色三角形那个类,如果K=5,由于蓝色四方形比例为3/5,因此绿色圆被赋予蓝色四方形类。
K最近邻(k-Nearest Neighbor,KNN)分类算法,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一。该方法的思路是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。KNN算法中,所选择的邻居都是已经正确分类的对象。该方法在定类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。 KNN方法虽然从原理上也依赖于极限定理,但在类别决策时,只与极少量的相邻样本有关。由于KNN方法主要靠周围有限的邻近的样本,而不是靠判别类域的方法来确定所属类别的,因此对于类域的交叉或重叠较多的待分样本集来说,KNN方法较其他方法更为适合。
KNN算法不仅可以用于分类,还可以用于回归。通过找出一个样本的k个最近邻居,将这些邻居的属性的平均值赋给该样本,就可以得到该样本的属性。更有用的方法是将不同距离的邻居对该样本产生的影响给予不同的权值(weight),如权值与距离成反比。
2.kNN计算流程
计算已知类别数据集中的点与当前点之间的距离;
按照距离递增次序排序;
选取与当前点距离最小的k个点;
确定前k个点所在类别的出现频率;
返回前k个点所出现频率最高的类别作为当前点的预测分类。
根据上述流程实现KNN核心算法
四、实验设计方案
如前所述,kNN算法流程如下:
a.计算已知类别数据集中的点与当前点之间的距离;
b.按照距离递增次序排序;
c.选取与当前点距离最小的k个点;
d.确定前k个点所在类别的出现频率;
e.返回前k个点所出现频率最高的类别作为当前点的预测分类。
在kNN.py中,添加一个函数classify0作为kNN算法的核心函数,该函数的完整形式为:
def classify0(inX, dataSet, labels, k):
其中各个参数的含义如下:
inX - 用于要进行分类判别的数据(来自测试集)
dataSet - 用于训练的数据(训练集)
lables - 分类标签
k - kNN算法参数,选择距离最小的k个点
在上述参数列表中,dataSet为所有训练数据的集合,也就是表示所有已知类别数据集中的所有点,dataSet为一个矩阵,其中每一行表示已知类别数据集中的一个点。inX为一个向量,表示当前要判别分类的点。按照上述算法流程,我们首先应该计算inX这个要判别分类的点到dataSet中每个点之间的距离。dataSet中每个点也是用一个向量表示的,点与点之间的距离怎么计算呢?没错,就是求两向量之间的距离,数学上,我们知道有很多距离计算公式,包括但不限于:
欧氏距离
曼哈顿距离
切比雪夫距离
闵可夫斯基距离
标准化欧氏距离
马氏距离
夹角余弦
汉明距离
杰卡德距离& 杰卡德相似系数
信息熵
这里,我们选择最简单的欧式距离计算方法。设p和q为两向量,则两向量间的欧氏距离为:
在算法流程,输入参数含义,以及距离计算公式都明确了以后,按照kNN算法的流程,我们就可以实现kNN算法了。
五、实验内容
1、KNN算法原理介绍
K-最近邻(K-Nearest Neighbors,KNN)算法是一种基于距离的简单而有效的分类和回归方法。KNN算法的核心思想是:如果一个样本在特征空间中的K个最相似(即K个最近邻)的样本中的大多数属于某个类别,则该样本也很可能属于这个类别。
2、操作步骤详细描述
计算已知类别数据集中的点与当前点之间的距离;
按照距离递增次序排序;
选取与当前点距离最小的k个点;
确定前k个点所在类别的出现频率;
返回前k个点所出现频率最高的类别作为当前点的预测分类。
import numpy as np
import sys
def classify0(inX,dataSet,labels,k):
num = len(dataSet)
n=num-1
ans=np.asarray(inX)
tmp=np.asarray(inX)
while n!=0:
ans = np.append(ans,tmp)
n-=1
ans = np.reshape(ans,[num,2])
ans = ans-dataSet
ans = ans*ans
dis = np.zeros([num,1],dtype=int)
for i in range(num):
dis[i] = ans[i][0]+ans[i][1]
ans = np.reshape(dis,[1,num])
y = np.argsort(ans)
y=list(y[0])
dic = dict.fromkeys(list(set(labels)), 0)
for i in range(k):
dic[labels[y[i]]]+=1
dic = sorted(dic.items(),key =lambda item:item[1],reverse=True)
return dic[0][0]
dataSet=np.array([[250,100],[270,120],[111,230],[130,260],[200,80],[70,190]])
labels=["理科生","理科生","文科生","文科生","理科生","文科生"]
inX=[105,210]
print(classify0(inX,dataSet,labels,3))
if __name__ == "__main__":
sys.stdout.encoding = 'utf-8'
dataSet = np.array([[250, 100], [270, 120], [111, 230], [130, 260], [200, 80], [70, 190]])
labels = ["理科生", "理科生", "文科生", "文科生", "理科生", "文科生"]
inX = [105, 210]
print(classify0(inX, dataSet, labels, 3))
- 记录实验结果
- 实验现象描述
运行结果显示“文科生”,输出符合预期
5、实验结果分析
kNN算法的指导思想是“近朱者赤,近墨者黑”,由你的邻居来推断出你的类别。先计算待分类样本与已知类别的训练样本之间的距离,找到距离与待分类样本数据最近的k个邻居;再根据这些邻居所属的类别来判断待分类样本数据的类别。用空间内两个点的距离来度量。距离越大,表示两个点越不相似。距离的选择有很多,通常用比较简单的欧式距离。
六、实验反思
根据这次实验实现了一个基本的K-最近邻(K-NN)分类器。K-NN是一种简单的机器学习算法,它根据测试数据点与训练数据集中的点之间的距离来预测测试数据点的类别。以下是对这段代码和K-NN算法的一些思考:
其优点在于:
简单,易于理解,易于实现,无需估计参数,无需训练;
适合对稀有事件进行分类;
特别适合于多分类问题(multi-modal,对象具有多个类别标签), kNN比SVM的表现要好。
缺点:
懒惰算法,对测试样本分类时的计算量大,内存开销大,评分慢;
当样本不平衡时,如一个类的样本容量很大,而其他类样本容量很小时,有可能导致当输入一个新样本时,该样本的K个邻居中大容量类的样本占多数;
可解释性较差,无法给出决策树那样的规则。
对于K值的设定:
k值选择过小,得到的近邻数过少,会降低分类精度,同时也会放大噪声数据的干扰;而如果k值选择过大,并且待分类样本属于训练集中包含数据数较少的类,那么在选择k个近邻的时候,实际上并不相似的数据亦被包含进来,造成噪声增加而导致分类效果的降低。