k-近邻算法

K-近邻算法的简介和Python实现

1、k-近邻算法(kNN)简介

k-近邻算法的原理:测量不同特征值之间的距离

k-近邻算法
优点:精度高、对异常值不敏感、无数据输入假定
缺点:计算复杂度高、空间复杂蹲高
适用数据范围:数值型和标称型

【注】标称型目标变量的结果只在有限目标集中取值, 如真与假、 动物分类集合 { 爬行类、 鱼类、 哺乳类、 两栖类 } ; 数值型目标变量则可以从无限的数值集合中取值, 如 0.100、 42.001、 1000.743 等。

kNN的工作原理:存在一个带标签(即知道样本集中每一个数据与所属分类的对应关系)的训练样本集S。输入无标签的新数据后,将新数据的每个特征与样本集S中数据对应的特征进行比较,然后通过算法从样本集中提取出与新数据特征最为相似的前k个数据,并统计这k个数据中出现次数最多的分类,将此作为新数据的分类。
【注】一般来说,只选择样本数据集中前k个最相似的数据,这就是kNN中k的出处,通常k取不大于20的整数。

下面,我们利用电影分类的例子,来加深对kNN的了解。我们都知道,爱情片中接吻的镜头是较多的,而动作片中打斗的镜头是偏多的,因此,我们利用kNN来分类爱情片和动作片。下面表1是几部影片的统计结果。

表1 每部电影的打斗镜头数、接吻镜头数以及电影评估类型
电影名称打斗镜头(x)接吻镜头(y)电影类型
电影13104爱情片
电影22100爱情片
电影3181爱情片
电影410110动作片
电影5995动作片
电影6982动作片
1890未知

即使不知道未知电影属于哪种类型,我们也可以通过某种方法计算出来。首先计算未知电影与样本集中其他电影的距离,将打斗镜头记为x,接吻镜头记为y,通过欧式距离公式
在这里插入图片描述
计算各个电影与未知电影的距离。具体数值如表2所示。

表2 已知电影与未知电影的距离
电影名称与未知电影的距离
电影120.5
电影218.7
电影319.2
电影4115.3
电影5117.4
电影6118.9

按照距离递增排序,可以找到k个距离最近的电影。假定k=3,则三个最靠近的电影依次是电影2、电影3、电影1。统计这三个靠前的电影的类型(均为爱情片),则未知电影的类型为爱情片。

k-近邻算法的一般流程
(1) 收集数据:可以使用任何方法。
(2) 准备数据:距离计算所需要的数值,最好是结构化的数据格式。
(3) 分析数据:可以使用任何方法。
(4) 训练算法:此步骤不适用于k-近邻算法。
(5) 测试算法:计算错误率。
(6) 使用算法:首先需要输入样本数据和结构化的输出结果,然后运行k-近邻算法判定输入数据分别属于哪个分类,最后应用对 计算出的分类执行后续的处理。

2、kNN的python实现

对未知类别属性的数据集中的每个点依次执行以下操作:
(1) 计算已知类别数据集中的点与当前点之间的距离;
(2) 按照距离递增次序排序;
(3) 选取与当前点距离最小的k个点;
(4) 确定前k个点所在类别的出现频率;
(5) 返回前k个点出现频率最高的类别作为当前点的预测分类。

下面,我们通过python来实现上述的操作。

def classify0(inX, dataSet, labels, k):
    """
    :param inX: 用于分类的输入向量
    :param dataSet: 输入的训练样本集
    :param labels: 标签向量
    :param k: 用于选择最近邻居的数目
    :return: inX的分类结果
    注:标签向量的元素数目和矩阵dataSet的行数相同
    """
    dataSetSize = dataSet.shape[0]
    # ===================== 欧氏距离计算公式 =====================
    diffMat = tile(inX, (dataSetSize, 1) - dataSet)
    sqDiffMat = diffMat ** 2
    sqDistances = sqDiffMat.sum(axis=1)
    distances = sqDistances ** 0.5
    # 计算完所有点之间的距离后,对数据按照从小到大的次序排序。
    sortedDistIndices = distances.argsort()
    classCount={}
    for i in range(k):
        # 确定前k个距离最小元素所在的主要分类
        voteIlabel = labels[sortedDistIndices[i]]
        # 将classCount字典分解为元组列表
        classCount[voteIlabel] - classCount.get(voteIlabel, 0) + 1
    # 按照第二个元素的次序对元组进行排序(此处的排序为逆序)
    sortedClassCount = sorted(classCount.itertems(), key=operator.itemgetter(1), reverse=True)
    return sortedClassCount[0][0]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值