基于二值概率的朴素贝叶斯分类器在手写数字识别中的应用

基于二值概率的朴素贝叶斯分类器(最小错误率贝叶斯分类器)在手写数字识别中的应用

    • 一、 mnist数据集下载并保存至文件夹
    • 二、算法原理
    • 三、代码

一、 mnist数据集下载并保存至文件夹

  1. 下载数据集,下载下图四个包并解压
    基于二值概率的朴素贝叶斯分类器在手写数字识别中的应用_第1张图片
  2. 对网上下载的数据集进行处理,分别保存到0-9对应的文件夹
# -*- coding: utf-8 -*-
from PIL import Image
import struct


def read_image(filename_img,filename_label):

    f_img = open(filename_img, 'rb')
    index_img = 0
    buf_img = f_img.read()
    f_img.close()

    f_label = open(filename_label, 'rb')
    index_label = 0
    buf_label = f_label.read()
    f_label.close()
    # 开始读取 魔数及标签数目
    magic, labels = struct.unpack_from('>II', buf_label, index_label)
    index_label += struct.calcsize('>II')
    labelArr = [0] * labels

    #开始读取 魔数、图片数目、图片行数、列数
    magic, images, rows, columns = struct.unpack_from('>IIII', buf_img, index_img)
    index_img += struct.calcsize('>IIII')
    for i in range(images):
        # 逐个读取图片,每个图片字节数为 行数X列数
        image = Image.new('L', (columns, rows))
        for x in range(rows):
            for y in range(columns):
                # 读取并填充图片的像素值,每个像素值为一个字节
                image.putpixel((y, x), int(struct.unpack_from('>B', buf_img, index_img)[0]))
                index_img += struct.calcsize('>B')
        # 一个标签一个字节
        labelArr[i] = int(struct.unpack_from('>B', buf_label, index_label)[0])
        index_label += struct.calcsize('>B')
       #print('train'+labelArr[i]+'/'+str(i)+'.png')
        image.save('./data/test/' + str(labelArr[i]) + '/' + str(i) + '.png')


if __name__ == '__main__':
    #read_image('./dataset/train-images.idx3-ubyte','./dataset/train-labels.idx1-ubyte')
    read_image('./dataset/t10k-images.idx3-ubyte','./dataset/t10k-labels.idx1-ubyte')

二、算法原理

  1. 求单张图片特征:将2828的手写数字区域划分成77的大块,每块的特征根据此块内黑色像素点的比例阈值化为0或1;那么就有49个0/1特征,这样就完成了特征表示。
  2. 将训练集和测试集图片遍历得到其特征。
  3. 模型训练:计算类条件概率分布即某一类数字的图像上,这49个特征取0/1 的概率,根据朴素贝叶斯方法,变成49个独立的量的联合概率分布。具体是从特定大小的样本集中统计频数,最终以频数来代替概率。
  4. 模型预测:就是根据上面训练出来的朴素贝叶斯模型,对任一个新的样本 x ,分别计算它是类别 j 的条件下的后验概率,取最大后验概率的类别即可。

三、代码

import numpy as np
import matplotlib.pyplot as plt
import cv2
import os
import math

train_path = './data_2400_600/train/'
test_path = './data_2400_600/test/'

class_num = 10
feature_len = 49
train_label=[0,1,2,3,4,5,6,7,8,9]
test_label=[0,1,2,3,4,5,6,7,8,9]
train_num = 2400  #0-9每类训练集数量
test_num = 600   #0-9每类测试集数量

#二值化及特征提取函数
def initArr(path):
    feature=[]
    pos = 0
    folders=os.listdir(path)
    for folder in folders:
        files=os.listdir(path+folder)
        for file in files:
            img=cv2.imread(path+folder+'/'+file)
            h,w=img.shape[0],img.shape[1]
            ret, img= cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)#二值化
            #np.array将img转化为类型为float64的数组
            img= np.array(img,dtype='float64')/255 #归一化
            x=0
            for m in range(4,w+4-1,4):# m可以取7,14,21,28
                y=0
                for n in range(4,h+4-1,4):# n可以取7,14,21,28
                    k=0
                    for i in range(x,m):# i第一次循环取0、1、2、3、4、5、6   i第二次循环取7、8、9、10、11、12  ......
                        for j in range(y,n):# j第一次循环取0、1、2、3、4、5、6   j第二次循环取7、8、9、10、11、12  ......
                            if(img[i][j] == 1).all():# 统计黑色像素值为1的个数
                                k=k+1
                    p=k/16    #计算小块中的黑色像素的概率值
                    #将每个小方块中概率大于0.1的置为1
                    if(p>0.1):
                        feature.append(1) 
                    else:
                        feature.append(0)
                    y+=4
                x+=4
    return feature   #得出的是黑色像素概率向量

#按16一组划分特征向量
def devide(train_feature,test_feature):
    train_data=[]
    test_data=[]
    for i in range(0, len(train_feature), 49):
        train_data.append(train_feature[i:i+49])
    for i in range(0, len(test_feature), 49):
        test_data.append(test_feature[i:i+49])
    return train_data,test_data

def train(train_data):
    print('start training...')
    # 先验概率
    prior_probability = np.zeros(class_num)   
    # 条件概率                      
    conditional_probability = np.zeros((class_num,feature_len,2))   
    s=0
    # 计算先验概率及条件概率
    for i in range(len(train_label)):
        for k in range(train_num):
            img=train_data[s+k]
            label = train_label[i]
            prior_probability[label] += 1
            for j in range(feature_len):
                #求出每张图片0,1的总数
                conditional_probability[label][j][img[j]] += 1
        s += train_num
    
    # 将概率归到[1.10001]
    for i in range(class_num):
        for j in range(feature_len):
            # 经过二值化后图像只有0,1两种取值
            pix_0 = conditional_probability[i][j][0]
            pix_1 = conditional_probability[i][j][1]

            # 计算0,1像素点对应的条件概率
            probalility_0 = (float(pix_0)/float(pix_0+pix_1))*1000000 + 1
            probalility_1 = (float(pix_1)/float(pix_0+pix_1))*1000000 + 1

            conditional_probability[i][j][0] = probalility_0
            conditional_probability[i][j][1] = probalility_1

    return prior_probability,conditional_probability

# 计算概率
def calculate_probability(img,label):
    probability = int(prior_probability[label])

    for i in range(len(img)):
        probability *= int(conditional_probability[label][i][img[i]])

    return probability

def predict(test_data,prior_probability,conditional_probability):
    print('start predicting...')
    predict = []
    for img in test_data:
        #存放预测值
        max_label = 0
        #存放预测概率
        max_probability = calculate_probability(img,0)

        for j in range(1,10):
            probability = calculate_probability(img,j)
            if max_probability < probability:
                max_label = j
                max_probability = probability
        predict.append(max_label)
    return np.array(predict)

def accuracy_score(test_predict):
    acc = 0
    for i in range(0,len(test_label)):
        label = test_label[i]
        for j in range(0,test_num):
            if(label == test_predict[i*test_num+j]):
                acc += 1
            print('real num is:',label,' predict num is:',test_predict[i*test_num+j])
    print('Test accuracy is: %f' % (acc/(class_num*test_num)))

if __name__ == '__main__':
    print('start extracting feature...')
    #生成特征向量
    train_feature=initArr(train_path)
    test_feature=initArr(test_path)
    #按16一组划分特征向量
    train_data,test_data=devide(train_feature,test_feature)

    prior_probability,conditional_probability = train(train_data)
    test_predict = predict(test_data,prior_probability,conditional_probability)
    accuracy_score(test_predict)



你可能感兴趣的:(机器学习,计算机视觉,分类,深度学习)