KNN算法实现-代码详细解析

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]

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值