KNN分类(Python实现)

K-近邻算法(KNN)

工作原理

存入一个样本数据集合,也称训练样本数据集合,并且样本数据集中每个数据都存在标签(知道每一位样本数据与所分类的对应关系),输入新数据,将新数据的每个特征与样本集中数据的每个特征进行比较,然后提取样本集中特征最相似数据的分类标,一般取前k个最相似的数据,k值一般不大于20,这k个数据中出现次数最多的分类,作为新数据的分类

一般流程

1.收集数据

2.准备数据:距离计算所需要的数值,最好是结构化的数据格式

3.分析数据

4.测试数据:计算错误率

6.使用方法:先输出样本数据和结构化的输出结果,然后根据KNN算法判断输入数据属于哪个分类

优缺点:

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

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

使用范围:数值型和标称型

KNN算法实战案例

1.简单KNN算法实现

准备简单训练数据集样本

#导入科学计算包
from numpy import *
#导入运算符模块
import operator
#定义简单训练样本集
def createDataSet():
    group=array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
    #按照顺序定义标签
    labels=['A','A','B','B']
    return group,labels

这里提供一个简单训练数据样本

在这里插入图片描述

group矩阵的每一行代表一个数据坐标,label集合与group行数对应数据的类别标签

使用KNN算法分类器预测未知类别数据种类

#导入科学计算包
from numpy import *
#导入运算符模块
import operator
#导入训练数据集
import KNN as dateSet
#使用KNN算法
def classify(inX,dataSet,labels,k):
    #1.计算未知类别数据与训练数据集中各个数据的距离,使用欧拉距离公式计算
    #得到训练集样本个数
    dataSetSize=dataSet.shape[0]
    #将未知标签数据矩阵行复制成与训练集矩阵行数一样后再与训练集矩阵做减法,这里未知数据矩阵中只传了一个样本
    diffMat=tile(inX,(dataSetSize,1))-dataSet
    #将计算结果的矩阵做平方
    sqDiffMat=diffMat**2
    #平方后矩阵计算每行和并返回到一个数组中
    sqDistances=sqDiffMat.sum(axis=1)
    #开根号得到未知标签数据与训练集中所有数据的距离
    distance=sqDistances**0.5
    #2.对距离排序并且选择k个最小的点
    #对距离数组中的元素进行排序,返回数据从小到大的排序的索引数组
    sortedDistanceIndicies=distance.argsort()
    #定义集合统计存放未知类别数据距离训练样本集中最近的k个数据的类别-个数的kv型数据
    classCount={}
    for i in range(k):
        voteIlablel=labels[sortedDistanceIndicies[i]]
        classCount[voteIlablel]=classCount.get(voteIlablel,0)+1
    #按照字典中存放数据的第二个元素值大小类倒序排序,返回一个排序好的列表
    sortedClassCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
    #返回预测结果
    return sortedClassCount[0][0]

#测试
date,label=dateSet.createDataSet()
print(classify([0,0],date,label,2))

欧拉距离计算公式如图所示

在这里插入图片描述

构建好分类器后,后面案例还是会使用到。

2.使用KNN算法改进约会网站配对效果

1.解析收集好的数据,将其格式改变为分类器可以接受的数据,这里的分类器是简单KNN算法实现的分类器

#导入科学计算包
from numpy import *
#将文件中的数据进行处理
def filematrix(filename):
    f=open(filename)
    arrayOfLines=f.readlines()
    nunberofLines=len(arrayOfLines)
    #创建全零数组
    returnMat=zeros((nunberofLines,3))
    classLabelVector=[]
    index=0
    for line in arrayOfLines:
        line=line.strip("\n")
        listFromLine=line.split("\t")
        #特征属性
        returnMat[index,:]=listFromLine[0:3]
        #分类标签
        classLabelVector.append(int(listFromLine[-1]))
        index+=1
    return returnMat,classLabelVector

2.分析数据,在解析好数据之后,我们可以制作散点图来分析数据

#导入matplotlib
import matplotlib
import matplotlib.pyplot as plt
#导入科学计算法
from numpy import *
#导入knn算法
import 处理读取文件数据集及验证训练模型的准确率 as date
fig=plt.figure()
ax=fig.add_subplot(111)
returnMat,classLabelVector=date.filematrix("D:/学习资料/机器学习实战/《机器学习实战》源代码/machinelearninginaction/Ch02/datingTestSet2.txt")
ax.scatter(returnMat[:,0],returnMat[:,1],15.0*array(classLabelVector),15.0*array(classLabelVector))
plt.show()

在这里插入图片描述

根据两个特征散点图很容易区分出数据所属的类别

3.进一步处理数据

由于在计算距离时,每年获得的飞行常客里程数特征值远远大于其它特征值,为了减小该影响,我们可以对数据进行进一步处理–归一化数值,三者特征值都在0-1之间。这里归一化数值使用到公式为

newValue=(oldValue-min)/(max-min)
#导入科学计算包
from numpy import *
#导入knn
import 处理读取文件数据集及验证训练模型的准确率 as dataSet
#定义归一化特征值处理函数
def autoNorm(dataSet):
    minvals=dataSet.min(0)
    maxVals=dataSet.max(0)
    ranges=maxVals-minvals
    normDateSet=zeros(shape(dataSet))
    m=dataSet.shape[0]
    normDateSet=dataSet-tile(minvals,(m,1))
    normDateSet=normDateSet/tile(ranges,(m,1))
    return normDateSet,ranges,minvals

#测试
if __name__=='__main__':
    returnMat, classLabelVector = dataSet.filematrix("D:/学习资料/机器学习实战/《机器学习实战》源代码/machinelearninginaction/Ch02/datingTestSet2.txt")
    normDateSet, ranges, minvals=autoNorm(returnMat)
    print(normDateSet, ranges, minvals)

4.测试算法的准确率

数据准备好之后,我们一般使用数据集的10%来测试算法的准确度,在测试之前我们还需要先制作knn分类器,这里使用的是简单knn算法所用的分类器

#导入科学计算包
from numpy import *
#导入运算符模块
import operator

#使用KNN算法核心
def classify(inX,dataSet,labels,k):
#1.根据欧拉距离公式计算未知分类数据点与训练数据样本点的距离
    #得到训练集样本个数
    dataSetSize=dataSet.shape[0]
    #将未知标签数据矩阵行复制成与训练集矩阵行数一样后再与训练集矩阵做减法,
    diffMat=tile(inX,(dataSetSize,1))-dataSet
    #将计算结果的矩阵做平方
    sqDiffMat=diffMat**2
    #平方后矩阵计算每行和并返回到一个数组中
    sqDistances=sqDiffMat.sum(axis=1)
    #开根号得到未知标签数据与训练集中所有数据的距离
    distance=sqDistances**0.5
#2.根据距离来排序并统计最近的k个数据点分类信息
    #对距离数组中的元素进行排序,返回数据从小到大的排序的索引数组
    sortedDistanceIndicies=distance.argsort()
    #定义集合统计存放未知类别数据距离训练样本集中最近的k个数据的类别-个数的kv型数据
    classCount={}
    for i in range(k):
        voteIlablel=labels[sortedDistanceIndicies[i]]
        classCount[voteIlablel]=classCount.get(voteIlablel,0)+1
#3.选择这k个数据点中种类出现最多的作为预测值
    #按照字典中存放数据的第二个元素值大小类倒序排序,返回一个排序好的列表
    sortedClassCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
    #返回预测结果

    return sortedClassCount[0][0]

测试算法

#测试准确率算法

def datingClassTest():
    hoRatio=0.10
    datingDate,datingLabels=filematrix("D:/学习资料/机器学习实战/《机器学习实战》源代码/machinelearninginaction/Ch02/datingTestSet2.txt")
    normMat,range,minVals=date.autoNorm(datingDate)
    m=normMat.shape[0]
    numTestVeces=int(m*hoRatio)
    errorCount=0.0
    i=0
    while i<numTestVeces:
        classifierResult=order.classify(normMat[i,:],normMat[numTestVeces:m,:],\
        datingLabels[numTestVeces:m],3)
        print(f"knn预测结果是:{classifierResult},真实结果是:{datingLabels[i]}")
        if (classifierResult!=datingLabels[i]):
            errorCount+=1.0
        i+=1
    print(f"错误了率是{errorCount / float(numTestVeces)}")

根据测试之后,该算法的错误率为0.05,当然这与数据集的选择也有很大关系

5.预测未知分类数据的类别

在测试问准确率后,就可以根据该算法来预测未知分类数据类别,

#导入科学计算包
from numpy import *
#导入数据集
import 处理读取文件数据集及验证训练模型的准确率 as algorithm
#导入分类器
import KNN算法核心 as prodict
#导入归一化特征值
import 将数据进行归一化特征值 as format
#预测函数
def classifyPerson():
    result=["不喜欢","魅力一般的人","极具魅力的人"]
    percentTats=float(input("玩游戏所耗时间百分比?"))
    ffMiles=float(input("每年获得飞行常客里程数?"))
    iceCream=float(input("每周消耗冰淇淋公升数"))
    datingDataMat,datingLables=algorithm.filematrix("D:/学习资料/机器学习实战/《机器学习实战》源代码/machinelearninginaction/Ch02/datingTestSet2.txt")
    normMat, range, minVals = format.autoNorm(datingDataMat)
    inArr=array([ffMiles,percentTats,iceCream])

    classifierResult=prodict.classify((inArr-minVals)/range,normMat,datingLables,3)
    print(f"很有可能喜欢{result[classifierResult]}")

#测试
if __name__=="__main__":
    classifyPerson()
3.手写数字识别系统

1.解析收集好的数据,将其32X32矩阵转换1X1024的矩阵

#导入科学计算包
from numpy import *
#数据处理文件
def imgvector(filename:str):
    returnVect=zeros((1,1024))
    f=open(filename,'r')
    for i in range(32):
        lineStr=f.readline()
        for j in range(32):
            returnVect[0,32*i+j]=int(lineStr[j])
    return  returnVect

2.导入分类器,同时预测算法的准确率

#导入科学计算包
from numpy import *
#导入os包
from os import listdir
#导入knn分类器
import KNN算法核心 as algorithm
#数据处理文件
def imgvector(filename:str):
    returnVect=zeros((1,1024))
    f=open(filename,'r')
    for i in range(32):
        lineStr=f.readline()
        for j in range(32):
            returnVect[0,32*i+j]=int(lineStr[j])
    return  returnVect

#测试算法准确度
def handwritingClassTest():
    hwLabels=[]
    trainingFileList=listdir("D:/学习资料/机器学习实战/《机器学习实战》源代码/machinelearninginaction/Ch02/trainingDigits")
    m=len(trainingFileList)
    trainingMat=zeros((m,1024))
    for i in range(m):
        fileNameStr=trainingFileList[i]
        fileStr=fileNameStr.split('.')[0]
        classNumStr=int(fileStr.split('_')[0])
        hwLabels.append(classNumStr)
        # print(f"D:/学习资料/机器学习实战/《机器学习实战》源代码/machinelearninginaction/Ch02/trainingDigits/{fileNameStr}")
        trainingMat[i,:]=imgvector("D:/学习资料/机器学习实战/《机器学习实战》源代码/machinelearninginaction/Ch02/trainingDigits/"+fileNameStr)
    testFileList=listdir("D:/学习资料/机器学习实战/《机器学习实战》源代码/machinelearninginaction/Ch02/testDigits")
    errorCount=0.0
    mTest=len(testFileList)
    for i in range(mTest):
        fileNameStr=testFileList[i]
        fileStr=fileNameStr.split('.')[0]
        classNumStr=int(fileStr.split("_")[0])
        vectorUnderTest=imgvector("D:/学习资料/机器学习实战/《机器学习实战》源代码/machinelearninginaction/Ch02/testDigits/"+fileNameStr)
        classifierResult=algorithm.classify(vectorUnderTest,trainingMat,hwLabels,3)
        print(f"预测结果是{classifierResult},真实结果是{classNumStr}")
        if (classifierResult!=classNumStr):
            errorCount+=1.0
    print(f"总计错误数是{errorCount}")
    print(f"错误率是{errorCount/float(mTest)}")
#测试
if __name__=='__main__':
    # print(imgvector("D:/学习资料/机器学习实战/《机器学习实战》源代码/machinelearninginaction/Ch02/trainingDigits/0_25.txt"))
    handwritingClassTest()

预测结果错误率为0.01

总结

knn算法是基于实例的学习,使用算法时必须有接近实际数据的训练样本数据,同时必须要花费大量存储空间保存训练数据集,而且还要计算每个数据的距离值,非常耗时,另外一个却显示是,他无法给出任何数据的基础结构信息我们无法知晓平均实例样本,和典型实例样本有什么特征

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值