KNN算法及其应用案例

1.常见的分类算法:
(1).KNN算法
(2).贝叶斯算法
(3).决策树算法
(4)人工神经网络算法
(5)支持向量机(SVM)算法
2.今天我们用KNN算法解决手写体数字的识别问题(包括验证码识别,二维码识别等都可以归属为同一类问题)
KNN算法又名K-近邻算法,总体思想是:通过把现实中的数据映射到坐标系,然后通过计算"点"之间的距离(欧几里得公式)sqr[(x1-xm)**2+(y1-ym)**2]
可以翻译成如下步骤:
(1).计算欧式距离
(2).按照递增顺序排位
(3).选取与当前距离最小的K个点
(4).确定前K个点所在的类的出现频率
(5)返回前K个点出现频率最高的类别作为当前点的预测分类
3.算法实现步骤:
(1)处理数据
(2)数据向量化
(3)计算欧几里得距离
(4)根据距离分类
4.KNN算法优点:
(1).简单、易实现、易理解,无需参数估计及训练
(2).适用于多分类问题
(3).总的思想是:"物以类聚"
KNN算法模块:

#KNN算法模块:
def knn(k,testdata,traindata,labels):   
    #k代表分类数,测试数据,训练数据,所得到的测试结果属于哪一类(labels)
    traindata.shape[0]      
    #shape返回两个参数(数组),shape[0]得到训练集行数
    dif=np.tile(testdata,(traindata,1))-traindata    
    #利用numpy中的tile扩展维数后,才能进行计算,列数确定一直,扩展行(行扩展一直,列不变)
    sqdif=dif**2   
    #对差值的每个元素取平方
    sumsqdif=sqdif.sum(axis=1)  
    #按行进行计算,得到列向量组,axis=0则得到的是行向量
    distance=sumsqdif**0.5
    sortdistance=distance.argsort()     
    #按照升序去排
    count={}  #建立一个空字典
    for i in range(0,k):
        vote=labels[sortdistance[i]]
        count[vote]=count.get(vote,0)+1  
        #get(5,0)+1,意思是在count字典中出现一次vote值,则对应加1{5:1,,,},多次循环累加
    sortcount=sorted(count.items(),key=operator.itemgetter(1),reverse=True) 
    #排序依据字典中的第一个词去排序,默认是升序(False)
    #key指定依据哪个区排,operator.itemgeter(1)指定第一个元素去排  
    return sortcount[0][0]


手写体字体的识别(数字、图片、二维码、验证码(1-26个字母)等与此类似):
手写体--->拍照--->标准化(设定长和宽的像素大小)--->转文本--->加载数据--->训练数据---用测试数据调用KNN算法去测试,看是否能够清晰识别。
1.首先将手字体字体拍照保存为图片,并将其标准化处理(长和宽设定固定高度比如32*32等)
2.转化为文本数据
3.读取每个像素

处理图像模块:

#处理图像模块
from PIL import Image
from os import listdir
#import numpy as np
im=Image.open("C:/Users/Administrator/Desktop/pandashesuanfa/shouxie.jpg")
fh=open("C:/Users/Administrator/Desktop/pandashesuanfa/shouxie.txt","a")
#im.save("C:/Users/Administrator/Desktop/pandashesuanfa/shouxie2.png")
width=im.size[0]   #im.size 获得宽和高的像素,返回两个参数,第一个为width(宽)(行对应宽),,第二个像素为height
height=im.size[1]
#获取图片像素的颜色
#k=im.getpixel((1,9))
#print(k)
for i in range(0,width):
    for j in range(0,height):
        cl=im.getpixel((i,j))
        c1all=cl[0]+cl[1]+cl[2]
        if(c1all==0):
            #黑色
            fh.write("1")
        else:
            fh.write("0")
    fh.write("\n")
fh.close()

 加载数据模块:

#加载数据(traindata)模块,定义一个加载函数
def datatoarray(fname):
    arr=[]
    fh=open(fname)
    for i in range(0,32):
        thisline=fh.readline()
        for j in range(0,32):
            arr.append(int(thisline[j]))
    return arr
arr1=datatoarray("C:/Users/Administrator/Desktop/pandashesuanfa/0_8.txt")

'''建立一个seplabel函数取文件名前缀'''
def seplabel(fname):
    filestr=fname.split(".")[0]  #通过"."作为分隔符,并取第一个元素
    label=int(filestr.split("_")[0])  #再通过"_"下划线分割,得到第一个元素
    return label

测试训练数据模块: 

#测试训练数据模块
def traindata():
    labels=[]
    trainfile=listdir("D:/shujufenxi/traindata")    #listdir函数读取当前文件夹下所有的文件名,得到的是一个列表
    num=len(trainfile)
    '''#c长度为1024(列),每一行存储一个文件
    #用一个数组存储所有训练数据,行:文件总数,列:1024'''
    trainarr=np.zeros((num,1024))
    for i in range(0,num):
        thisfname=trainfile[i]  #此时得到的是一个文件
        #需要取文件的前缀(163.txt),建立seplabel函数
        thislabel=seplabel(thisfname)
        labels.append(thislabel)
        trainarr[i,:]=datatoarray("traindata/"+thisfname)   #调用datatoarray函数读取当前所有文件
    return trainarr,labels
#建立测试函数,用测试数据调用KNN算法去测试,看能否准确识别
def datatest():
    trainarr,labels=traindata() #调用函数,加载训练集
    testlist=listdir("tesdata") #得到测试集数据
    tnum=len(testlist)
    '''批量识别'''
    for i in range(0,tnum):
        thistestfile=testlist[i]
        testarr=datatoarray("testdata/"+thistestfile)
        rknn=knn(3,testarr,trainarr,labels)
        print(rknn)
datatest()

'''抽取某一个测试文件出来进行试验'''
'''
thistestfile=testlist[i]
testarr="3_58.txt"
rknn=knn(3,testarr,trainarr,labels)
print(rknn)
'''

完整代码如下:

# -*- coding: utf-8 -*-
#KNN手写体数字的识别
#C:/Users/Administrator/Desktop/pandashesuanfa/shouxie.jpg

#KNN算法及手写体字体的识别
'''
算法实现步骤:
1.处理数据
2.数据向量化
3.计算欧几里得距离
4.根据距离分类
'''
import numpy as np
import operator
def knn(k,testdata,traindata,labels):    #k代表分类数,测试数据,训练数据,所得到的测试结果属于哪一类(labels)
    traindata.shape[0]      #shape返回两个参数(数组),shape[0]得到训练集行数
    dif=np.tile(testdata,(traindata,1))-traindata    #利用numpy中的tile扩展维数后,才能进行计算,列数确定一直,扩展行(行扩展一直,列不变)
    sqdif=dif**2   #对差值的每个元素取平方
    sumsqdif=sqdif.sum(axis=1)  #按行进行计算,得到列向量组,axis=0则得到的是行向量
    distance=sumsqdif**0.5
    sortdistance=distance.argsort()     #按照升序去排
    count={}  #建立一个空字典
    for i in range(0,k):
        vote=labels[sortdistance[i]]
        count[vote]=count.get(vote,0)+1  #get(5,0)+1,意思是在count字典中出现一次vote值,则对应加1{5:1,,,},多次循环累加
    sortcount=sorted(count.items(),key=operator.itemgetter(1),reverse=True) #排序依据字典中的第一个词去排序,默认是升序(False)
    #key指定依据哪个区排,operator.itemgeter(1)指定第一个元素去排  
    return sortcount[0][0]

'''
手写字体数字识别思路
1.首先将手字体字体拍照保存为图片,并将其标准化处理(长和宽设定固定高度比如32*32等)
2.转化为文本数据
3.读取每个像素
'''
#处理图像模块
from PIL import Image
from os import listdir
#import numpy as np
im=Image.open("C:/Users/Administrator/Desktop/pandashesuanfa/shouxie.jpg")
fh=open("C:/Users/Administrator/Desktop/pandashesuanfa/shouxie.txt","a")
#im.save("C:/Users/Administrator/Desktop/pandashesuanfa/shouxie2.png")
width=im.size[0]   #im.size 获得宽和高的像素,返回两个参数,第一个为width(宽)(行对应宽),,第二个像素为height
height=im.size[1]
#获取图片像素的颜色
#k=im.getpixel((1,9))
#print(k)
for i in range(0,width):
    for j in range(0,height):
        cl=im.getpixel((i,j))
        c1all=cl[0]+cl[1]+cl[2]
        if(c1all==0):
            #黑色
            fh.write("1")
        else:
            fh.write("0")
    fh.write("\n")
fh.close()
"""加载数据(traindata),定义一个函数"""
def datatoarray(fname):
    arr=[]
    fh=open(fname)
    for i in range(0,32):
        thisline=fh.readline()
        for j in range(0,32):
            arr.append(int(thisline[j]))
    return arr
arr1=datatoarray("C:/Users/Administrator/Desktop/pandashesuanfa/0_8.txt")

'''建立一个seplabel函数取文件名前缀'''
def seplabel(fname):
    filestr=fname.split(".")[0]  #通过"."作为分隔符,并取第一个元素
    label=int(filestr.split("_")[0])  #再通过"_"下划线分割,得到第一个元素
    return label

'''建立训练数据'''
def traindata():
    labels=[]
    trainfile=listdir("D:/shujufenxi/traindata")    #listdir函数读取当前文件夹下所有的文件名,得到的是一个列表
    num=len(trainfile)
    '''#c长度为1024(列),每一行存储一个文件
    #用一个数组存储所有训练数据,行:文件总数,列:1024'''
    trainarr=np.zeros((num,1024))
    for i in range(0,num):
        thisfname=trainfile[i]  #此时得到的是一个文件
        #需要取文件的前缀(163.txt),建立seplabel函数
        thislabel=seplabel(thisfname)
        labels.append(thislabel)
        trainarr[i,:]=datatoarray("traindata/"+thisfname)   #调用datatoarray函数读取当前所有文件
    return trainarr,labels
#建立测试函数,用测试数据调用KNN算法去测试,看能否准确识别
def datatest():
    trainarr,labels=traindata() #调用函数,加载训练集
    testlist=listdir("tesdata") #得到测试集数据
    tnum=len(testlist)
    '''批量识别'''
    for i in range(0,tnum):
        thistestfile=testlist[i]
        testarr=datatoarray("testdata/"+thistestfile)
        rknn=knn(3,testarr,trainarr,labels)
        print(rknn)
datatest()

'''抽取某一个测试文件出来进行试验'''
'''
thistestfile=testlist[i]
testarr="3_58.txt"
rknn=knn(3,testarr,trainarr,labels)
print(rknn)
'''

关注思路,以及KNN算法的应用是重点
 

猜你喜欢

转载自blog.csdn.net/Analyst128/article/details/81869901