机器学习实战之k-近邻算法

本文介绍了k-近邻算法的基本原理,包括其优点、缺点和适用范围,并详细阐述了算法的工作流程。此外,还提供了Python语言的具体实现案例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一,概述

简单地说,k-近邻算法采用测量不同特征值之间的距离方法进行分类。

优点:精度高,对异常值不敏感,无数据输入假定。

缺点:计算复杂度高,空间复杂度高。

适用范围:数值型和标称型(离散型)

工作原理:

存在一个样本数据集合,也称作训练样本集,且每组数据都存在标签(如色泽是青绿,根蒂是蜷缩,敲声是浊响的瓜,是好瓜。好瓜是标签,色泽根蒂敲声都是特征,青绿蜷缩浊响都是特征数值,每组数据都有一个标签),在输入没有标签的新数据后,将新数据的每个特征数值与样本集中的各组数据对应的特征数值进行比较,然后提取样本中特征数值最相似的数据的分类标签。

k的含义是,选择前k组最相似的数据中出现次数最多的标签,即为新数据的标签。通常k是不大于20的整数。

k-近邻算法的一般流程

  1. 收集数据
  2. 准备数据
  3. 分析数据
  4. 测试算法:计算错误率
  5. 使用算法首先需要输入样本数据和结构化的输出结果,然后运行k-近邻算法判定输入数据分别属于哪个分类,最后应用对计算出的分类执行后续的处理。

k-近邻算法的伪代码

  1. 计算已知标签数据集中的点与当前点之间的距离
  2. 按照距离递增次序排序
  3. 选取与当前点距离最小的k个点
  4. 确定前k个点所在类别的出现频率
  5. 返回前k个点出现频率最高的标签作为当前点的预测分类 

二,python实现

 

#kNN.py


import numpy
import operator

def createDataSet():
    group = numpy.array([[1.0, 1.1], [1.0, 1.0], [0, 0], [0, 0.1]])
    labels = ['A', 'A', 'B', 'B']
    return group,labels

#classify0()有四个输入参数:用于分类的输入向量inX,输入的训练样本集dataSet,标签向量labels,k用于选择最近邻居的数目
# 其中标签向量的元素数目和矩阵dataSet的行数相同
def classify0(inX,dataSet,labels,k):
    dataSetSize = dataSet.shape[0] #最外围的维度 即为4
    diffMat = numpy.tile(inX, (dataSetSize, 1)) - dataSet
    sqDiffMat = diffMat**2 #平方 即x**2 y**2
    sqDistances = sqDiffMat.sum(axis = 1) #计算每行元素的和 即x**2 + y**2
    distances = sqDistances**0.5 #(x**2 + y**2)**0.5
    sortedDistIndicies = distances.argsort() #把原有列表的元素进行从小到大排序后,返回对应元素的索引
    classCount = {} #键为标签 值为前k个最小值中含有该标签的个数
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]] #得到第i小的元素的标签
        classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1 #返回字典classCount中voteIlabel元素对应的值,若无,则进行初始化
    #classCount.items()将字典中的每对键值转换为了元组,operator.itemgetter(1)获取元组中的第二个元素,即对应标签的个数,reverse = true为降序
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
    return sortedClassCount[0][0] #返回字典中标签数量最多的标签

涉及函数及参数用法

  1. shape[0]表示最外围的数组的维数,shape[1]表示次外围的数组的维数,数字不断增大,维数由外到内。如shape为(2,3),说明这是一个2行3列的矩阵,即2*3。见numpy.array 的shape属性理解
  2. 原型:numpy.tile(A,reps)   tile共有2个参数,A指待输入数组,reps则决定A重复的次数。整个函数用于重复数组A来构建新的数组。若reps为(4,1),意思是在一个4*1的矩阵中,每个对应位置上的元素都是A,若A为[0, 0],则numpy.tile([0, 0],(4, 1))为[[0, 0], [0, 0], [0, 0], [0, 0]]。见Numpy中的tile方法

  3. axis的取值就是这个精确定位某个元素需要经过多少数组的长度 ,如果一个矩阵为2*3*4,维数为三,精确定位到某个元素可以用a[n0][n1][n2]表示。n0的取值是0,1(数组两维),代表第一个索引;n1的取值是0,1,2(每一维数组拥有3个子数组),代表第二个索引;n2的取值是0,1,2,3(每个子数组有4个元素),代表第三个索引。则axis可以取0,1,2。axis=0,对应n0已经确定下来,即n0取值定为0,1。所以sum每个元素的求和公式是sum = a[0][n1][n2]+a[1][n1][n2]。接下来确定sum的行数和列数,n1的取值是0,1,2,为3个数,代表行数,n2的取值是0,1,2,3,为4个数,代表列数,所以sum为3*4的数组。python 中 np.sum()函数 通俗易懂理解!

  4. classCount.get(voteIlabel,0)返回字典classCount中voteIlabel元素对应的值,若无,则进行初始化      get()函数作用

    (1)若不存在voteIlabel,则字典classCount中生成voteIlabel元素,并使其对应的数字为0,即classCount = {voteIlabel:0},此时classCount.get(voteIlabel,0)作用是检测并生成新元素,括号中的0只用作初始化,之后再无作用

    (2)当字典中有voteIlabel元素时,classCount.get(voteIlabel,0)作用是返回该元素对应的值,即0

  5. item()方法把字典中每对key和value组成一个元组,并把这些元组放在列表中返回。 Python中使用item()方法遍历字典的例子

  6. sorted(iterable, cmp=None, key=None, reverse=False)   iterable -- 可迭代对象。
    cmp -- 比较的函数,这个具有两个参数,参数的值都是从可迭代对象中取出,此函数必须遵守的规则为,大于则返回1,小于则返回-1,等于则返回0。
    key -- 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。
    reverse -- 排序规则,reverse = True 降序 , reverse = False 升序(默认)。Python sorted() 函数

  7. operator模块提供的itemgetter函数用于获取对象的哪些维的数据,参数为一些序号。Python中的sorted函数以及operator.itemgetter函数

检验 

import kNN
group, labels = kNN.createDataSet()
print(kNN.classify0([0, 0], group, labels, 3))

 可得到结果B。

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

若水菱花

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值