09-06 周二 Python之KNN算法的实现

09-06 周二 Python之KNN算法的实现
时间版本修改人描述
2022年9月6日19:25:32V0.1宋全恒新建文档

简介

文档描述

 文档主要是描述了KNN算法的原理和代码实现。并对源程序进行解读。

img

 使用KNN算法,如上图所示,首先我们要有一组数据集,这组数据集分别属于不同的类型标签。当我们又了一个新的样本时,我们通过比较该样本与其他所有样本的距离,找出其最近的K个邻居,根据这K个邻居中的数量最多的标签而确定为该样本的标签。其核心思想为: 物以类聚,人以群分

 使用KNN算法可以用于多分类,也可以用于回归,回归时,取最近邻的几个值,通过平均或者加权投票的方式可以解决。

KNN算法

 最近邻算法(K-Nearest Neighbour, KNN)算法是ML经典算法质疑,属于监督学习的领域。

img

KNN原理

距离度量

 一般常用的距离度量包括曼哈顿距离、欧氏距离、闵可夫斯基距离、切比雪夫距离,也可以基于相似度或者相异度进行度量。关于距离度量可以参见《周志华-机器学习P200》

img

img

基本流程

[外链图片转存中…(img-JJg1gQID-1662727488752)]

优缺点

 KNN易于理解,易于实现,适合处理多分类问题。训练时间复杂度为o(n).对离群值不敏感,缺点计算量比较大。

源程序

KNN-流程图

主体程序

 KNN的主体程序如下所示:KNN.py

#coding:utf-8
from numpy import *
import operator
##给出训练数据以及对应的类别
def createDataSet():
    group = array([[1.0,2.0],[1.2,0.1],[0.1,1.4],[0.3,3.5]])
    labels = ['A','A','B','B']
    return group,labels
###通过KNN进行分类
def classify(input,dataSet,label,k):
    dataSize = dataSet.shape[0]
    ####计算欧式距离
    diff = tile(input,(dataSize,1)) - dataSet
    sqdiff = diff ** 2
    squareDist = sum(sqdiff,axis = 1)###行向量分别相加,从而得到新的一个行向量
    dist = squareDist ** 0.5    
    ##对距离进行排序
    sortedDistIndex = argsort(dist)##argsort()根据元素的值从大到小对元素进行排序,返回下标

    classCount={}
    for i in range(k):
        voteLabel = label[sortedDistIndex[i]]
        ###对选取的K个样本所属的类别个数进行统计
        classCount[voteLabel] = classCount.get(voteLabel,0) + 1
    ###选取出现的类别次数最多的类别
    maxCount = 0
    for key,value in classCount.items():
        if value > maxCount:
            maxCount = value
            classes = key
    return classes

测试程序

#-*-coding:utf-8 -*-
import sys
sys.path.append("...文件路径...")
import KNN
from numpy import *
dataSet,labels = KNN.createDataSet()
input = array([1.1,0.3])
K = 3
output = KNN.classify(input,dataSet,labels,K)
print("测试数据为:",input,"分类结果为:",output)

程序运行结果

测试数据为: [1.1 0.3] 分类结果为: A

程序解读

整体阅读

 首先我们看测试程序,测试程序的主要作用是准备数据,在这里创建了数据局和样本,样本为array的类型。

机器学习与几个库非常密切,scipy,numpy,matplotlib、scikit-Learn ,kearas, Pandas关系密切。可以专门进行学习。

 这里的KNN实现,主要是使用numpy:支持高级的、大量的维度数据组与矩阵运算。

image-20220906200903103

jupyter运行

计算欧式距离

 首先dataSet代表的是训练数据集,我们查看一下其内容。

image-20220906201134571

 因此关键要理解的是该命令:

diff = tile(input,(dataSize,1)) - dataSet

 这也是困惑读者的点,我们把完整的过程展示一下:

image-20220906201553324

 我们观察一下欧式距离的公式:

img

 其实上述的tile复制构造与训练集同等规模,然后相减,便可以直接得到差值。上面是二维公式,相当于(x2-x1) 和(y2-y1)的结果已经求了出来了。此时,可以看到还缺少平方和的运算以及开根号的运算。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ie0FfEc5-1662727488755)(https://cdn.jsdelivr.net/gh/yanchenmochen/imgs/imgs202209062020834.png)]

 此时,可以看出输入样本和训练集中的四个数据的距离已经求出来了。

array([ 2.9 ,  0.05,  2.21, 10.88])
距离排序

 接下来,使用了numpy的排序函数,对距离进行排序,这个过程也需要简单的理解:

image-20220906202540054

 当我们看到这个数字的时候,相信这个程序也就可以理解了。

统计分类

image-20220906202823936

 看到这里,整体的代码程序应该也就清楚了。最复杂的点是计算欧式距离哪里,其他的就应该程序流程控制,统计标记了

类库

 上述的程序中广泛的使用了如下的函数:

  • numpy

    • array()构造numpy的基础数组数据

    • dataSet.shape[0]返回的是numpy中数组的0号维度的数量

    • tile(input,(dataSize,1)) 类似于构造函数,使用第二个参数确定重复的维数

    • sortedDistIndex = argsort(dist) 根据数组中元素进行排序

    • squareDist = sum(sqdiff,axis = 1)###行向量分别相加,从而得到新的一个行向量

  • operator

    • sqdiff = diff ** 2
    • diff = tile(input,(dataSize,1)) - dataSet 数组相减
    • dist = squareDist ** 0.5 数组开根号,相当于对数组中每一个数开根号。

注: 如果能自然的理解上述的类库函数的含义,然后冠以程序流程就能实现我们基本的KNN。这是基础。

 所以算法的流程是贯穿其中的脉络,而类库的各个细节,则是一串珠子,流程控制整体的结构。细节实现流程的目的。这两方面一个是宏观,一个是微观,都是比较重要的。都是自己需要加强的。

总结

 作为自己进入算法框架组,自己最近也是开始认真的阅读算法有关的内容。自己现在也算是一个Java老开发了,只不过现在自己要加快对于Python的学习,因为算法,我觉得比Java开发有搞头,是一个可以深耕的领域。自己最近呢也是刚从老东家离开,现在在之江实验室工作,还是挺开心的,新的环境,新的同事,新的领域,一切都是崭新的,就连自己也是崭新的。时间一直日新月异的过去,我希望自己也能苟日新,日日新,又日新,然后日新月异。以后自己就好好的写一些ML有关的文章吧。

2022年9月6日20:46:27于之江实验室

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值