python实现KNN,并用KNN实现手写数字识别

python实现KNN,并用KNN实现手写数字识别

from numpy import*
import operator
from PIL import Image
from os import listdir
def knn (k,textdata,traindata,labels):
    traindatasize = traindata.shape[0]   #shapr[0]为矩阵的行数,shape[1]为矩阵的列数

    sub_result = tile(textdata,(traindatasize,1))-traindata
    #将测试集的格式扩展到与训练集的格式一致,然后在与训练集做差,在后面求欧氏距离时有用
    #tile函数是一个扩展函数,第一个参数是要扩展的矩阵,第二个参数
    # 可以是一个常数,表示在扩展列数的倍数,若为一个元组,
    # 则元组第一个参数表示扩展行数的倍数,第个二参数表示扩展列数的倍数

    sqrt_sub_result = sub_result**2                     #对差直求方
    sum_sqrt_sub_result = sqrt_sub_result.sum(axis = 1) #得到了测试集到各个训练集的距离的平方
    #参数axis是用来指定求和的位置,=0时表示每一列上的各行求和(矩阵原本有多少列结果就多少列)
    #=1时相反,是每一行上的各列求和(原本有多少行结果就有多少行)

    distance = sum_sqrt_sub_result**0.5                 #开方求出距离
    distance_for_sort=distance.argsort()                #对求出的距离进行排序,argsort的排序结果是输出元素的下标,默认为升序
    count = {}                                          #创建一个空字典,用于存放结果

    for i in range(0,k):       #找出排序后前k个结果中,某一标签最多的类别
        vote = labels[distance_for_sort[i]]     #当前第i个结果的类别
        count[vote] = count.get(vote,0)+1       #把当前类别与类别出现的次数存到字典count中去

    sort_count = sorted(count.items(),key = operator.itemgetter(1),reverse=True)
    #第一个参数是排序的对象,第二个参数表示对谁排序,operator.itemgetter=0
    #表示对类别来排序,operator.itemgetter=1,表示对类别出现的次数来排序
    #reverse=True表示按降序排
    #此时得到的count中第一个即为最可能的类别
    return sort_count[0][0]

#将图片转化为文本的形式
def image_change_to_txt():
    im = Image.open("E:/杂物/壁纸1")    #用Image.open函数打开一张图片
    fh = open("E:/杂物/壁纸","a")       #创建一个文件的句柄
    #im.save("E:/杂物/壁纸")    #用来保存图片的函数
    #k = im.getpixel((1,9))     #用来取出某一点的像素点
    width = im.size(0)          #size(0)表示图片的宽
    height = im.size(1)         #size(1)表示图片的高
    for i in range(0,width):
        for j in range(0,height):
            p_pix  = im.getpixel((i,j))
            p_pix_sum = p_pix[0]+p_pix[1]+p_pix[2]
            if(p_pix_sum==0):
                fh.write("1")
            else:
                fh.write("0")
    fh.close()

#加载数据(把每张图片的文本转到一维数组中保存)
def data_to_array(fname):
    arr = []            #把数据加载 到一维数组arr里
    fh = open(fname)    #打开加载数据的文件夹
    for i in range(0,32):
        thisline = fh.readline()    #每次读取一行
        for j in range(0,32):       #读取每一行的像素点的值,并存到arr数组中
            arr.append(int(thisline[j]))
    return arr

#arr1 = data_to_array("E:/py_application/shu_ju_fen_xi_yu_wa_jue/testdata//0_0.txt")
#print(arr1)

#建立一个取前缀的函数,因为前缀即为标签
def sep_label(fname):
    filestr = fname.split(".")[0]
    #将后面的.txt去掉,保留前面的数据,因此为[0]
    lable = int(filestr.split("_")[0])
    #同理,保留前面的数据,因此为[0]
    return lable

#建立训练数据
def traindata ():
    labels = []
    train_file = listdir("E:/py_application/shu_ju_fen_xi_yu_wa_jue/testdata")
    #listdir能够加载一个目录下的所有文件的名称

    num = len(train_file)    #求出有多少个文件

    #生成一个二维数组,每一行存储一个arr,即每行存储一个训练数据
    train_arr = zeros((num,1024)) #numpy中的方法,用与生成一个num行1024列的全0的二维数组

    for i in range(0,num):        #有多少个txt就循环多少次
        this_fname = train_file[i]  #取当前第i个元素的文件名
        thislable = sep_label(this_fname)   #从当前的文件名中读取出标签lable
        labels.append(thislable)
        train_arr[i,:] = data_to_array("traindata/"+this_fname)  #把得到的一维数组arr赋到train__arr中
    return train_arr,labels     #返回训练集与标签

def test_knn ():
    train_arr, labels = traindata()     #获取训练集与标签
    test_list = listdir("testdata")     #获取测试集目录下的文件名
    test_num = len(test_list)           #获取文件名总数
    for i in range(0,test_num):         #测试每个测试数据
        this_test_file = test_list[i]   #取第i个元素的文件名
        test_arr = data_to_array("testdata/"+this_test_file)    #将第i个文本数据转成一维数组
        result_knn = knn(3,test_arr,train_arr,labels)   #测试第i个数据
        print(result_knn)   #打印测试结果

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值