使用此算法的前提:
k—紧邻算法属于监督学习算法。监督学习指的就是数据中有样本的标签。即我们知道样本集中的每一数据与所属分类的对应关系。
举个例子:(分类)
属性one | 属性two | 属性three | 标签 |
---|---|---|---|
aa | bb | cc | x |
比如:假设体重、翼展、后背颜色、脚蹼这四个特征可以决定一只鸟属于什么种类。那么这里的体重、翼展、后背颜色、脚蹼这四个属于我们表中的属性。鸟属于什么种类就属于我们说的标签。所以,总而言之,k-近邻临算法其实是属于一种分类算法。注意:标签并不是说所有的样本都要有,比如我们拿来判断的样本就不需要有。因为我们的任务就是根据现有的知识去判断样本的标签。如果有了标签,那么就判断就没有意义。当然可以用来检测算法的准确度。看自己的具体应用情况
算法步骤
对未知标签的数据集中的每个样本执行以下操作:
- 计算已知类别数据集中的每个点与当前点的距离;
- 按照距离递增次序排序
- 选取与当前点距离最小的k个点(k是自己定义的,可以直接任意取,当然目的是使算法准确度更高)
- 确定k个点所在类别的出现频率
- 返回前k个点出现频率最高的类别作为当前点的预测分类
代码实现(Python版)
import numpy as np
import operator
def k_nearest(sample,dataSet,label,k):
#计算样本之间的距离
dataSetSize = dataSet.shape[0]
diffMat = np.tile(sample,(dataSetSize,1))-dataSet
sqDiffMat = diffMat**2
sqDistances = sqDiffMat.sum(axis=1)
distances = sqDistances**0.5
#选择k个最近的距离
sortedDistIndices = distances.argsort()
classCount = {}
for i in range(k):
voteLabel = label[sortedDistIndices[i]]
classCount[voteLabel] = classCount.get(voteLabel,0)+ 1
#对距离进行排序
sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
return sortedClassCount[0][0]
代码解读:
函数中的参数:
sample:待分类的样本
dataSet:已知样本的属性集
label:已知样本的标签
k:算法中的k值
每一行的解读:(从函数开始,带#号的不记录行号)
前面的import是导入相应的包
1:定义函数,python中的参数是不需要定义数据类型的。
2:获取数组的行数。在这里就是样本集中的数据个数。因为shape属性返回的是数组各维的维数。[0]代表第一维,即数组的行数。dataSetSize是一个整数
3:tile函数:通过后面指定的形式重复前面的数组。更多见后面的函数解读。后面的(dataSetSize,1)刚好是样本的个数。所以相当于将待分类样本副本成已经样本数,这样方便后面的计算。np.tile(sample,(dataSetSize,1))-dataSet :将待分类样本重复之后与已知样本作差,得到各个属性的差值;diffMat是numpy.ndarray类型,大小是n*m。n:dataSetSize,m:属性的个数
4:将各个属性的插值做平方.sqDiffMat是numpy.ndarray类型,大小是n*m。
5:将各个属性的值横向相加,axis=1说明横向相加,axis=0则说明是纵向相加。 sqDistances 是numpy.ndarray类型,大小是n*1。
6:将横向相加的结果开方。所以这里计算距离用的是欧式距离。distances是numpy.ndarray类型,大小是n*1。
7:按照距离的大小对数组中的元素进行排序,返回其在数组中的第几位。详情看下方面的函数解读中的argsort。sortedDistIndices是numpy.ndarray类型,大小是n*1。
8:创建一个字典
9:进行for循环。range函数是产生一个取值范围。
10:取出第i个最近的邻居的标签
11:将字典中键对应的值加1。若字典中没有这样的数据,则将键加入,操作之后,对应的值为1.因为classCount.get(voteLabel,0)说明的是,取字典中键为voteLabel的值,若没有,则将其值设为0;
11:对字典按照值的大小进行排序。reverse为True说明是反序,从大到小
12:返回第一个元素的键,即数据的分类。
函数解读:
numpy.tile
numpy.tile(A, reps)
Parameters:
A : (array_like) The input array.
reps : (array_like)The number of repetitions of A along each axis.
Returns:(ndarray)The tiled output array.
案例见:[tile函数](https://docs.scipy.org/doc/numpy/reference/generated/numpy.tile.html?highlight=tile#numpy.tile)
这里也可以用
[numpy.broadcast_to](https://docs.scipy.org/doc/numpy/reference/generated/numpy.broadcast_to.html#numpy.broadcast_to)
相应语句替换:
diffMat = np.broadcast_to(sample,(dataSetSize,len(sample)))-dataSet
argsort
举个例子:
>>>x = np.array([3, 1, 2])
>>> np.argsort(x)
输出:array([1, 2, 0])
解释:对于x这个数组([3,1,2]),按照从小到大的顺序对数组进行排序,那么结果应该是[1,2,3]。输出的结果就是表明:应该排在第一的数字1,他在原先的数组位置在第1位(第2个,数组的索引从0开始)。应该排在的第二的数字2,他在原先数组位置的第2位,应该排在第三的数字3,他在原先数组位置的第0位。
算法优点
精度高、对异常值敏感、无数据输入假定
算法缺点
计算复杂度高、空间复杂度高