K-近邻(KNN)算法

因为自己的好奇心,所以做了这一篇关于KNN 算法的笔记。

一、简介

K-近邻算法是一种常用的监督学习的方法,其与K-Means算法有点类似,其原理是:在给定的样本数据中,基于某种距离(欧式距离或马氏距离等等)找出与当前样本数据距离最近的K个样本数据,然后再基于这K个“邻居”的信息来进行预测。

这个算法在生活中应用的其实也很多,比如电影、新闻等信息的归类,它可以很简单的就做到将电影、新闻进行分门别类。

除此之外呢,就是K近邻算法有着不同于其他学习方法的独特之处,它几乎没有显式训练的过程,它的训练时间为零,也就是说它是对测试样本直接进行处理,它这种方式被称为“懒惰学习”;相应的,那些在训练阶段就对样本进行学习处理的方法,被称为“急切学习”。

二、KNN算法实现

2.1实现步骤

在真正实现之前,首先理一下思路。

(1)分别计算已知类别数据的点到当前点(未知类别)之间的距离,通常选用欧式距离,当然也可以使用其他距离来进行计算。
(2)按照距离将已知类别的点进行从小到大排序。
(3)选取距离当前点最近的前k个点,并统计前k个点中各个类别出现的频率。
(4)返回前k个点中出现频率最高的类别,以此作为当前点的预测类别。

2.2代码实现

#-*- coding=utf-8 -*-
#@Time : 2020/9/21 13:49
#@File : KNN1.0.py
#@Software : PyCharm

from numpy import *
import operator
import matplotlib.pyplot as plt
# 通用的一些函数
"""
函数说明:创建数据集
"""
def createDataSet():
    group=array([[1,1.1],[1.0,1.0],[0,0],[0,0.1]])
    labels=['A','A','B','B']
    return group, labels

"""
函数说明:KNN分类器,找到距离inX最近的前k个样本
"""
def classify(inX,dataSet,labels,k):
    dataSetSize=dataSet.shape[0]
    diffMat=tile(inX,(dataSetSize,1))-dataSet       #tile,瓦片之意,也就是按照某个东西来拼接出新的东西,这里是用于计算出已知点到当前点的距离
    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[voteIlabel]=classCount.get(voteIlabel,0)+1
    sortedClassCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True) #按照键值对中的值进行排序
    return sortedClassCount[0][0]

if __name__ == '__main__':
    group,labels=createDataSet()
    print("group:\n",group,'\n',"labels:\n",labels)

    #绘制图像
    fig=plt.figure()        #创建画布
    ax=fig.add_subplot(111) #添加子图,并获取坐标轴
    ax.scatter(group[:,0],group[:,1],c='b',marker='o')  #通过坐标轴添加散点图
    ax.scatter(0,0,c="r",marker='*')
    plt.show()      #显示图像

    result = classify([0,0],group,labels,3)
    print("预测结果为:",result)

实现效果:


三、相关测试

关于一个算法,有两点的问题是我们每一个人都会关心的:效率和正确率。因为处于一种学习算法的阶段,所以我对Python的效率问题就没有什么高的要求,那么下面主要会对KNN算法的正确率方面进行相关的测试。

测试的例子就采用了一本书中的例子“海伦约会”,代码如下所示:

#-*- coding=utf-8 -*-
#@Time : 2020/9/21 16:54
#@Author : wangjy
#@File : KNN2.0.py
#@Software : PyCharm

from numpy import *
import operator
from tkinter import filedialog
import matplotlib.pyplot as plt

"""
函数说明:KNN分类器,找到距离inX最近的前k个样本
"""
def classify(inX,dataSet,labels,k):
    dataSetSize=dataSet.shape[0]
    diffMat=tile(inX,(dataSetSize,1))-dataSet       #tile,瓦片之意,也就是按照某个东西来拼接出新的东西
    sqDiffMat=diffMat**2
    sqDistances=sqDiffMat.sum(axis=1)
    distances=sqDistances**0.5
    sortedDistIndices=distances.argsort()
    classCount={}
    for i in range(k):
        voteIlabel=labels[sortedDistIndices[i]]
        classCount[voteIlabel]=classCount.get(voteIlabel,0)+1
    sortedClassCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
    return sortedClassCount[0][0]

"""
函数说明:读取文件中的数据,转为矩阵
"""
def file2matrix(filename):
    if filename==None:
        return ;
    fr=open(filename)
    arrayOfLines=fr.readlines()
    numberOfLines=len(arrayOfLines)
    returnMat=zeros((numberOfLines,3))
    classLabelVector=[]
    types={}
    index=0
    for line in arrayOfLines:
        line=line.strip()
        listFromLine=line.split('\t')
        returnMat[index,:]=listFromLine[0:3]
        typeName=listFromLine[-1]
        if types.get(typeName.strip(),-1)==-1:
            types[typeName]=len(types)
        classLabelVector.append(types[typeName])
        index+=1
    return returnMat,classLabelVector

"""
函数说明:归一化特征值
"""
def autoNorm(dataSet):
    minVals=dataSet.min(0)
    maxVals=dataSet.max(0)
    ranges=maxVals-minVals
    normDataSet=zeros(shape(dataSet))
    m=dataSet.shape[0]
    normDataSet=dataSet-tile(minVals,(m,1))
    normDataSet=normDataSet/tile(ranges,(m,1))

    return normDataSet,ranges,minVals

"""
函数说明:测试KNN算法对数据预测的错误率
"""
def datingClassTest():
    #打开的文件名
    dlg = filedialog.askopenfile(title='打开文件', filetypes=[("文本文件", "*.txt"), ('Python源文件', '*.py')])
    fileName = dlg.name  # 获取数据文件路径
    datingDataMat, datingLabels = file2matrix(fileName)
    hoRatio = 0.10      #取所有数据的百分之十作为测试样本
    normMat, ranges, minVals = autoNorm(datingDataMat)   #因为各类数据的范围有大有小,所以需要进行数据归一化(等权重)
    m = normMat.shape[0]
    numTestVecs = int(m * hoRatio)
    errorCount = 0.0    #记录分类错误个数

    for i in range(numTestVecs):
        classifierResult = classify(normMat[i,:], normMat[numTestVecs:m,:],
            datingLabels[numTestVecs:m], 3)
        print("classifierResult:%s\tdatingLabels:%d" % (classifierResult, datingLabels[i]))
        if classifierResult != datingLabels[i]:
            errorCount += 1.0
    print("the total error rate is:%%%.3f" %(errorCount/float(numTestVecs)*100))
    print("the total error count is :%d" % errorCount)

if __name__ == '__main__':
    datingClassTest()

测试结果:


四、小结

总的来说,KNN算法虽然简单,但在处理数据进行分类时仍是一个优秀的方法,限制其应用的主要是其在处理大量数据时所带来的效率问题,像Python或MATLAB中虽然有着很优秀的矩阵处理的模块,但是仍不能避免大量的数值运算这种情况。所以如果对数据处理效率有着更高的要求,可以考虑借助k-d树、四叉树或八叉树等数据结构来进一步提高获取最邻近点的速度。

参考资料:《机器学习》《机器学习实战》

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,125评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,293评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,054评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,077评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,096评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,062评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,988评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,817评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,266评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,486评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,646评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,375评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,974评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,621评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,642评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,538评论 2 352

推荐阅读更多精彩内容