机器学习(3)

Knn-----K近邻算法

  • knn简介
  • 距离的定义(多种形式)
  • 海伦约会代码
  • 手写数字识别代码
    1.K最近邻(k-Nearest Neighbor,KNN),是一种常用于分类的算法,是有成熟理论支撑的、较为简单的经典机器学习算法之一。该方法的基本思路是:如果一个待分类样本在特征空间中的k个最相似(即特征空间中K近邻)的样本中的大多数属于某一个类别,则该样本也属于这个类别,即近朱者赤,近墨者黑。显然,对当前待分类样本的分类,需要大量已知分类的样本的支持,因此KNN是一种有监督学习算法。
    它是一个既是分类又是回归的算法。

2.距离的量度
距离
距离的定义是一个宽泛的概念:只要满足非负、自反、三角不等式就可以称之为距离。其中非负是指任意两个相异点的距离为正;自反是Dis(y,x)=Dis(x,y);三角不等式是Dis(x,z)<=Dis(x,y)+Dis(y,z),其中Dis指(绝对值)
马氏距离(闵可夫斯基距离)
在这里插入图片描述
其中d是维数,p是阶数,也称为p范数。

当p=1时,是曼哈顿距离

当p=2时,是欧氏距离

当p→∞时,是切比雪夫距离

当p=0时,是海明距离
欧氏距离:(欧拉距离)
两点间的直线距离(一般用两条竖线||w||代表w的2范数)代入公式:
在这里插入图片描述
曼哈顿距离(城市街区距离)
各坐标数值差的和,就像汽车只能行驶在横平竖直的街道上,代入公式:在这里插入图片描述
切比雪夫距离
 各坐标数值差的最大值,当马氏距离的p→∞时,最终的结果取决于距离最大的维度上的距离:

Dis∞=maxj|xj-yj|

在二维的情况下:c=max(a,b) 海明距离  L0范数并不是一个真正的范数,它主要被用来度量向量中非零元素的个数。 在这里插入图片描述 在这里插入图片描述 图片从上到下依次显示a与b点的三种距离:欧氏距离(蓝色),切比雪夫距离(红色),曼哈顿距离(绿色) 摘自https://www.jianshu.com/p/95a4bcff2198 本章只考虑欧拉距离 在这里插入图片描述 通过计算,我们可以得到如下结果: (101,20)->动作片(108,5)的距离约为16.55
(101,20)->动作片(115,8)的距离约为18.44
(101,20)->爱情片(5,89)的距离约为118.22
(101,20)->爱情片(1,101)的距离约为128.69
k-近邻算法步骤如下:
计算已知类别数据集中的点与当前点之间的距离;
按照距离递增次序排序;
选取与当前点距离最小的k个点;
确定前k个点所在类别的出现频率;
返回前k个点所出现频率最高的类别作为当前点的预测分类。
数据集 https://github.com/Jack-Cherish/Machine-Learning/blob/master/kNN/2.海伦约会/datingTestSet.txt

import numpy as np
import matplotlib.pyplot as plt
def fileopen(filename):
    fr=open(filename)
    fe=fr.readlines()(打开文件并读取所有内容)
    a=[]
    while "\n" in fe:
       fe.remove("\n")
    zeronp=np.zeros((len(fe),3))
    index = 0
    for line in fe:
        line=line.strip()
        datalist=line.split("\t")
        zeronp[index,:]=datalist[0:3](将数据的前三列存到zeronp中)
        index+=1
        if datalist[-1] == 'didntLike':
           a.append(1)
        elif datalist[-1] == 'smallDoses':
            a.append(2)
        elif datalist[-1] == 'largeDoses':
            a.append(3)
    return zeronp,a
def showdates(zeronp,a):(数据可视化)
    plt.figure(figsize=(15,15))
    plt.subplot2grid((2,2),(0,0))
    b=[]
    for i in a:
        if i==1:
            b.append("red")
        elif i==2:
            b.append("green")
        elif i==3:
            b.append("black")
    plt.scatter(x=zeronp[:,0],y=zeronp[:,1],color=b)
    plt.xlabel(r"每年获得的飞行常客里程数",fontproperties="SimHei",color="r")
    plt.ylabel(r"玩视频游戏所消耗时间占",fontproperties="SimHei",color="r")        
    plt.title(r"每年获得的飞行常客里程数与玩视频游戏所消耗时间占比",fontproperties="SimHei")
    plt.show() 
zeronp,a=fileopen("data.txt")
print(zeronp)
showdates(zeronp,a)
#数据归一化  在处理这种不同取值范围的特征值时,我们通常采用的方法是将数值归一化,如将取值范围处理为0到1或者-1到1之间。下面的公式可以将任意取值范围的特征值转化为0到1区间内的值:(不改变detax,与detay的量度,大的对应大的,小的对应小的,只是缩小了而已,是数据对距离的影响程度一直,防置一个,另一个特别小,对应的距离不清晰,即有可能和一个比它小的数相同,减小误差)
def guiyihua(data):
    datamin=data.min(0)
    datamax=data.max(0)
    minus=datamax-datamin
    m=data.shape[0]
    guiyidata1=data-np.tile(datamin,(m,1))
    guiyidata2=guiyidata1/np.tile(minus,(m,1))
    return guiyidata2,datamin,minus
zeronp,datamin,minus=guiyihua(zeronp)
def fenlei(ceshidata,xunliandata,k,a):
    index_x=xunliandata.shape[0]
    datacha=np.tile(ceshidata,(index_x,1))-xunliandata
    datafang=datacha**2
    datahe=datafang.sum(axis=1)
    datajuli=np.sqrt(datahe)
    datajuli_index=datajuli.argsort()
    datadict={}
    for i in range(k):
        keys=a[datajuli_index[i]]
        datadict[keys]=datadict.get(keys,0)+1
    datadict=sorted(datadict.items())
    return datadict[0][0] 
percent=0.1
m=int(zeronp.shape[0]*percent)
errorcount=0
for i in range(m):
    fenleidata=fenlei(zeronp[i,:],zeronp[m:zeronp.shape[0],:],5,a[m:zeronp.shape[0]])
    print("分类结果:%d  真实类别:%d" % (fenleidata,a[i]))
    if fenleidata != a[i]:
            errorcount += 1
print("错误率:%f%%" %((errorcount/m)*100))
def shilihua():
    resultlist=["讨厌","喜欢","非常喜欢"]
    precentTats = float(input("玩视频游戏所耗时间百分比:"))
    ffMiles = float(input("每年获得的飞行常客里程数:"))
    iceCream = float(input("每周消费的冰激淋公升数:"))
    ceshi=np.array([precentTats ,ffMiles ,iceCream])
    ceshi=ceshi-datamin/minus
    result=fenlei(ceshi,zeronp,5,a )
    print("你可能%s这个人"%(resultlist[result-1]))
shilihua()    

结果
分类结果:3 真实类别:3
分类结果:2 真实类别:2
分类结果:1 真实类别:1
分类结果:1 真实类别:1
分类结果:1 真实类别:1
分类结果:1 真实类别:1
分类结果:1 真实类别:3
分类结果:3 真实类别:3
分类结果:1 真实类别:1
分类结果:3 真实类别:3
分类结果:1 真实类别:1
分类结果:1 真实类别:1
分类结果:2 真实类别:2
分类结果:1 真实类别:1
分类结果:1 真实类别:1
分类结果:1 真实类别:1
分类结果:1 真实类别:1
分类结果:1 真实类别:1
分类结果:2 真实类别:2
分类结果:3 真实类别:3
分类结果:2 真实类别:2
分类结果:1 真实类别:1
分类结果:1 真实类别:2
分类结果:1 真实类别:3
分类结果:2 真实类别:2
分类结果:3 真实类别:3
分类结果:2 真实类别:2
分类结果:3 真实类别:3
分类结果:2 真实类别:2
分类结果:1 真实类别:1
分类结果:3 真实类别:3
分类结果:1 真实类别:1
分类结果:2 真实类别:3
分类结果:1 真实类别:1
分类结果:2 真实类别:2
分类结果:1 真实类别:1
分类结果:1 真实类别:1
分类结果:2 真实类别:2
分类结果:3 真实类别:3
分类结果:3 真实类别:3
分类结果:1 真实类别:1
分类结果:2 真实类别:2
分类结果:3 真实类别:3
分类结果:3 真实类别:3
分类结果:3 真实类别:3
分类结果:1 真实类别:1
分类结果:1 真实类别:1
分类结果:1 真实类别:1
分类结果:1 真实类别:1
分类结果:2 真实类别:2
分类结果:2 真实类别:2
分类结果:1 真实类别:1
分类结果:3 真实类别:3
分类结果:2 真实类别:2
分类结果:2 真实类别:2
分类结果:2 真实类别:2
分类结果:2 真实类别:2
分类结果:3 真实类别:3
分类结果:1 真实类别:1
分类结果:2 真实类别:2
分类结果:1 真实类别:1
分类结果:2 真实类别:2
分类结果:2 真实类别:2
分类结果:2 真实类别:2
分类结果:2 真实类别:2
分类结果:2 真实类别:2
分类结果:2 真实类别:3
分类结果:2 真实类别:2
分类结果:3 真实类别:3
分类结果:1 真实类别:1
分类结果:2 真实类别:2
分类结果:3 真实类别:3
分类结果:2 真实类别:2
分类结果:2 真实类别:2
分类结果:1 真实类别:1
分类结果:3 真实类别:3
分类结果:1 真实类别:1
分类结果:1 真实类别:1
分类结果:3 真实类别:3
分类结果:3 真实类别:3
分类结果:1 真实类别:1
分类结果:2 真实类别:2
分类结果:3 真实类别:3
分类结果:1 真实类别:1
分类结果:3 真实类别:3
分类结果:1 真实类别:1
分类结果:2 真实类别:2
分类结果:2 真实类别:2
分类结果:1 真实类别:1
分类结果:1 真实类别:1
分类结果:3 真实类别:3
分类结果:2 真实类别:3
分类结果:1 真实类别:1
分类结果:2 真实类别:2
分类结果:1 真实类别:1
分类结果:3 真实类别:3
分类结果:3 真实类别:3
分类结果:1 真实类别:2
分类结果:1 真实类别:1
分类结果:1 真实类别:1
错误率:7.000000%
游戏所耗时间百分比:12 每年获得的飞行常客里程数:50000每周消费的冰激淋公升数:54
你可能讨厌这个人
在这里插入图片描述
手写数字识别:

from os import listdir
import numpy as np
import operator
def fileopen1(filename):
    zeronp1=np.zeros(1024,dtype=np.int)
    filetext1=open("C:\\Users\\24308\\Desktop\\trainingDigits\\"+filename)
    for i in range(32):    
        filetext2=filetext1.readline()
        for j in range(32):
            zeronp1[32*i+j]=int(filetext2[j])
    return zeronp1
def fileopen2(filename):
    zeronp2=np.zeros(1024,dtype=np.int)
    filetext1=open("C:\\Users\\24308\Desktop\\kNN\\3.数字识别\\testDigits\\"+filename)
    for i in range(32):    
        filetext2=filetext1.readline()
        for j in range(32):
            zeronp2[32*i+j]=int(filetext2[j])
    return zeronp2
trainingfilelist = listdir('C:\\Users\\24308\\Desktop\\trainingDigits')
m=len(trainingfilelist)
training=np.zeros((m,1024))
a=[]
errorcount=0
def fenlei(ceshidata,xunliandata,k,a):
    index_x=xunliandata.shape[0]
    datacha=np.tile(ceshidata,(index_x,1))-xunliandata
    datafang=datacha**2
    datahe=datafang.sum(axis=1)
    datajuli=(datahe)
    datajuli_index=datajuli.argsort()
    datadict={}
    for i in range(k):
        keys=a[datajuli_index[i]]
        datadict[keys]=datadict.get(keys,0)+1
    datadict=sorted(datadict.items(),key=operator.itemgetter(1),reverse=True)
    return datadict[0][0] 
for i in range(m):(每一个数的二进制码都不一样,所以对应的向量也不一致)
    filename=trainingfilelist[i]
    number=int(filename.split("_")[0])
    a.append(number)
    training[i,:]=fileopen1(filename)
trainingceshi=listdir("C:\\Users\\24308\Desktop\\kNN\\3.数字识别\\testDigits")
lentrainingceshi=len( trainingceshi)
for i in range( lentrainingceshi):
    filename=trainingceshi[i]
    number=int(filename.split("_")[0])
    canshu1=fileopen2(filename)
    ceshiresult=fenlei(canshu1,training,5,a)
    print("分类返回结果为%d\t真实结果为%d" % (ceshiresult,number))
    if(ceshiresult != number):
            errorcount += 1.0
print("总共错了%d个数据\n错误率为%f%%" % (errorcount, errorcount/lentrainingceshi * 100))
def zhuanhua():
    flag2=1
    while flag2==1:
        flag=0
        shurunumber=int(input("请输入一个数字"))
        count=0
        for i in a:
            if shurunumber==i:
                str1=trainingfilelist[count]
                xianshi=open("C:\\Users\\24308\\Desktop\\trainingDigits\\"+str1)
                for j in range(32):
                    print(xianshi.readline())
                    flag=1
                if flag==1 :
                    break
            count+=1
        jixu=str(input("是否继续y/n"))
        if jixu=="y":
            flag2=1
        else :
            flag2=0
zhuanhua()

结果(选取一部分):
分类返回结果为9 真实结果为9
分类返回结果为9 真实结果为9
分类返回结果为9 真实结果为9
分类返回结果为9 真实结果为9
分类返回结果为9 真实结果为9
分类返回结果为9 真实结果为9
分类返回结果为9 真实结果为9
分类返回结果为9 真实结果为9
分类返回结果为9 真实结果为9
分类返回结果为9 真实结果为9
分类返回结果为9 真实结果为9
分类返回结果为9 真实结果为9
分类返回结果为9 真实结果为9
分类返回结果为9 真实结果为9
分类返回结果为9 真实结果为9
分类返回结果为9 真实结果为9
分类返回结果为9 真实结果为9
总共错了17个数据
错误率为1.797040%
在这里插入图片描述
总结:
优点

  • 简单好用,容易理解,精度高,理论成熟,既可以用来做分类也可以用来做回归;
  • 可用于数值型数据和离散型数据;
  • 对异常值不敏感。

缺点

  • 计算复杂性高;空间复杂性高;
  • 样本不平衡问题(即有些类别的样本数量很多,而其它样本的数量很少);

博客学习
https://blog.csdn.net/c406495762/article/details/75172850

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我! 毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值