K-近邻算法学习总结

最近学习了K-近邻算法,在这里进行一个总结。

简单地说,K 近邻算法采用测量不同特征值之间的距离方法进行分类。它具有的优缺点如下:

  • 优点:精度高、对异常值不敏感、无数据输入假定。
  • 缺点:计算复杂度高、空间复杂度高。

K 近邻算法适用数据范围为:数值型和标称型。

在输入想要得到标签得的数据之后,将输入数据的每个特征与样本集中的数据相对应的特征进行比较,之后通过提取前k个最相似的分类标签,这也是K近邻算法中K的出处,通常K的值是不大于20的证书。最后根据K个最相似数据中出现最多的标签分类作为输入数据的分类。

K 近邻算法的一般流程

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

这里,自己设值标签以及类别,如下。

import numpy as np

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

准备数据:将数据转换为测试向量

假设输入为32*32的图像,那么我们就需要将图像转换为测试向量,所以将32*32的二进制图像矩阵转换为1*1024的向量,因为这里是一张图片,所以为1*1024,如果为m张图片,则应该为m*1024,根据情况而定。

我们首先编写一段函数 img2vector,用于将图像转换为向量:该函数创建 1x1024 的 NumPy 数组,然后打开给定的文件,循环读出文件的前 32 行,并将每行的头 32 个字符值存储在 NumPy 数组中,最后返回数组。

def img2vector(filename):
    # 创建向量
    returnVect = np.zeros((1, 1024))
    # 打开数据文件,读取每行内容
    fr = open(filename)
    for i in range(32):
        # 读取每一行
        lineStr = fr.readline()
        # 将每行前 32 字符转成 int 存入向量
        for j in range(32):
            returnVect[0, 32*i+j] = int(lineStr[j])
            
    return returnVect

分析数据

算法实现过程:

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

 这里,使用欧氏距离公式,计算两个向量点 𝑋𝑎Xa 和 𝑋𝑏Xb 之间的距离:d = \sqrt{(xa0-xb0)^2 +(xa1-xb1)^2 }

计算完所有点之间的距离后,可以对数据按照从小到大的次序排序。然后,确定前K个距离最小元素所在的主要分类,输入K总是正整数;最后,将 classCount 字典分解为元组列表,然后使用程序第二行导入运算符模块的itemgetter方法,按照第二个元素的次序对元组进行排序。
此处的排序为逆序,即按照从最大到最小次序排序,最后返回发生频率最高的元素标签。
import operator


def classify0(inX, dataSet, labels, k):
    
    """
    参数: 
    - inX: 用于分类的输入向量
    - dataSet: 输入的训练样本集
    - labels: 样本数据的类标签向量
    - k: 用于选择最近邻居的数目
    """
    
    # 获取样本数据数量
    dataSetSize = dataSet.shape[0]

    # 矩阵运算,计算测试数据与每个样本数据对应数据项的差值
    diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet

    # sqDistances 上一步骤结果平方和
    sqDiffMat = diffMat**2
    sqDistances = sqDiffMat.sum(axis=1)

    # 取平方根,得到距离向量
    distances = sqDistances**0.5

    # 按照距离从低到高排序
    sortedDistIndicies = distances.argsort()
    classCount = {}

    # 依次取出最近的样本数据
    for i in range(k):
        # 记录该样本数据所属的类别
        voteIlabel = labels[sortedDistIndicies[i]]   
        print(voteIlabel)
        classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1  
        print(classCount)
    # 对类别出现的频次进行排序,从高到低
    sortedClassCount = sorted(
        classCount.items(), key=operator.itemgetter(1), reverse=True)

    # 返回出现频次最高的类别
    return sortedClassCount[0][0]

 代码中列表sortedDistIndicies记录了出现前K次的索引号,通过循环,将这些索引号取出,即循环sortedDistIndicies[i]表示所选择的0-K次的索引号,labels[sortedDistIndicies[i]]表示取出的K个数据所代表的类别。

classCount.get(voteIlabel, 0)返回字典classCount中votelabel元素对应的值,若无,则进行初始化。

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

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

进行测试。

group, labels = createDataSet()
classify0([0, 5], group, labels, 3)

 

学习了K近邻算法可是尝试使用K近邻算法识别手写数字数据集,莺尾花分类等实际问题。K近邻算法是分离数据最简单有效的算法,但是计算复杂度高,空间复杂度高。K决策树就是K近邻算法的优化版,可以减少存储空间和计算时间的开销。

以上是关于学习K近邻算法的一些总结,如内容有误,欢迎指正。

关于get()函数作用参考文章: (2条消息) 【Python】get()函数作用_Mr.Gu的博客-CSDN博客

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值