1.k-近邻算法的特点
优点:精度高、对异常值不敏感、无数据输入假定。
缺点:计算复杂度高、空间复杂度高。
适用数据范围:数值型和标称型。
2.工作原理
训练样本集中的每个数据都有标签,我们清楚的知道样本集中每一个数据与所属分类的对应关系,将输入的无标签的新数据与样本集中数据对应的特征进行比较,算法提取样本集中特征最相似数据的分类标签,一般来说我们只选择样本数据集中前K个最相似的数据,通常k是不大于20的整数。最后选择k个最相似数据中出现次数最多的分类,作为新数据的分类。
3.实现算法
3.1 使用python导入数据
def createDataSet():
group = array([[1.0, 1.1], [1.0, 1.0], [0,0], [0, 0.1]])
labels = ['A', 'A', 'B', 'B']
return group, labels
把每个数据都赋予标签(这是个简单的例子,没有什么规律)
3.2 实施kNN算法
伪代码:
对未知类别属性的数据集中的每个点依次执行以下操作:
(1) 计算已知类别数据集中的点与当前点之间的距离;
(2) 按照距离递增次序排序;
(3) 选取与当前点距离最小的k个点;
(4) 确定前k个点所在类别的出现频率;
(5) 返回前k个点出现频率最高的类别作为当前点的预测分类。
3.3 算法整体实现
代码:
from numpy import *
import operator
def createDataSet():
group = array([[1.0, 1.1], [1.0, 1.0], [0, 0], [0, 0.1]])
labels = ['A', 'A', 'B', 'B']
return group, labels
#inX表示用于分类的输入向量是inX,输入的训练样本集为dataSet,标签向量是labels,参数k表示用于选择最近邻居的数目
def classify0(inX, dataSet, labels, k):
#shape以数组的形式获取数组的维数[行,列],shape[0]就是获取行的数值
dataSetSize = dataSet.shape[0]
"""
step1:计算距离
inX:[0。0, 0.0]
dataSet:
[1.0, 1.1]
[1.0, 1.0]
[0.0, 0.0]
[0.0, 0.1]
计算过程
1.求差
[1.0, 1.1] [0。0, 0.0] [1.0, 1.1]
[1.0, 1.0] -- [0。0, 0.0] = [1.0, 1.0]
[0.0, 0.0] [0。0, 0.0] [0.0, 0.0]
[0.0, 0.1] [0。0, 0.0] [0.0, 0.1]
2.对差值求平方
[1.0, 1.21]
[1.0, 1.0]
[0.0, 0.0]
[0.0, 0.01]
3.将平方后的差值累加
[2.21, 2, 0, 0.01]
4.将上一步求的值开方
[1.486, 1.414, 0, 0.1]
"""
#tile(要重复的矩阵,(以列的方向重复次数,以行的方向重复次数)),tile是瓷砖的意思,意味着是把整个数组看成一个瓷砖然后按行或列方向重复
#把输入向量按照列的方向重复(训练样本集的行数)次,再减去训练样本集
diffMat = tile(inX, (dataSetSize, 1)) - dataSet
#求diffMat的平方
sqDiffMat = diffMat**2
#没有axis参数表示全部相加,axis=0表示按列相加,axis=1表示按照行的方向相加
sqDistances = sqDiffMat.sum(axis = 1)
distances = sqDistances**0.5
"""
step2:对距离进行排序
索引值排序
[2, 3, 1, 0]
对应标签
['B','B','A','A']
"""
#argsort将数据从小到大排列,并返回其索引值
sortedDistIndicies = distances.argsort()
#字典类型
classCount={}
#k是函数的参数,表示选择k个临近点 以3为列
for i in range(k):
"""
step3:选择k个临近
第一次循环:voteIlabel='B' classCount['B']=1
第二次循环:voteIlabel='B' classCount['B']=2
第三次循环:voteIlabel='A' classCount['A']=1
"""
#sortedDistIndicies[i]存储的distances从小到大的索引值,用labels取出这个位置对应的标签
voteIlabel = labels[sortedDistIndicies[i]]
"""
step4:计算k个最近邻中各类别出现的次数
"""
classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
"""
step5:返回出现次数最多的类别标签
"""
#sorted(iterable, cmp=None, key=None, reverse=False)
#iterable -- 可迭代对象。
#cmp -- 比较的函数,这个具有两个参数,参数的值都是从可迭代对象中取出,此函数必须遵守的规则为,大于则返回1,小于则返回-1,等于则返回0。
#key -- 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。
#reverse -- 排序规则,reverse = True 降序 , reverse = False 升序(默认)。
#classCount的形式是字典["标签”,次数],用key获取出次数,按降序排列
sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
return sortedClassCount[0][0]