贝叶斯分类器实现minst手写数字识别

链接: 数据集下载地址.
链接中的数据集共有四个,
train-images-idx3-ubyte:存放的是训练用的图片信息
t10k-images-idx3-ubyte:存放的是测试用的图片信息
train-labels-idx1-ubyte:训练用的图片的实际数字
t10k-labels-idx1-ubyte:测试用的实际数字

第一步,数据集的读取

先读取说明性信息,再读取真正的数据集内容
对于imgs,最终读取为60000 X 28 X 28的矩阵

def loadImageSet(which=0):
	print('load image set')
    	binfile=None
    	if which==0:
        binfile = open(r"train-images-idx3-ubyte", 'rb')
    else:
        binfile=  open(r"t10k-images-idx3-ubyte", 'rb')
        
    	head = struct.unpack_from('>IIII' , buffers ,0) #打包四个,是说明信息
    	print("head,",head)
    	offset=struct.calcsize('>IIII')  #偏移量
   	imgNum=head[1]   #共有多少个
    	width=head[2]    #图片长和宽
    	height=head[3]
        #[60000]*28*28
    	bits=imgNum*width*height  #剩下的数据总长度
    	bitsString='>'+str(bits)+'B' #like '>47040000B'
    	
        imgs=struct.unpack_from(bitsString,buffers,offset)  #读取剩下的信息
        binfile.close()
    	imgs=np.reshape(imgs,[imgNum,width,height])   #变成矩阵形式
    	print('load imgs finished')
    	return imgs

读取label数据集,也是先读取说明性信息

def loadLabelSet(which=0):
    print ('load label set')
    binfile=None
    if which==0:
        binfile=open(r"train-labels-idx1-ubyte", 'rb')
    else:
        binfile=open(r"t10k-labels-idx1-ubyte", 'rb')
    buffers = binfile.read()
    
    head = struct.unpack_from('>II' , buffers ,0)   #大端的字节顺序打包两个4字节无符号整型数据
    print("head,",head)
    imgNum=head[1]
    
    offset = struct.calcsize('>II')  #偏移量
    numString='>'+str(imgNum)+"B"
    labels= struct.unpack_from(numString , buffers , offset)
    binfile.close()
    labels=np.reshape(labels,[imgNum,1])
    print ('load label finished')
    return labels

第二部,训练模型

首先,我们将图片分为7 X 7个4 X 4的图片,实现降维
然后统计4 X 4的图片中,像素值大于0的点数,如果大于一半(8个点),就认为其特征值为1,否则为0

这样,对于每一个样本,我们得到了7*7个特征值

对7*7个特征值进行编号,0,1,2,…,48

首先我们要获得先验概率P(wi):
先验概率
以及条件概率:
在这里插入图片描述
可以看出,在求每个先验概率与条件概率时 i 是不变的,也就是说我们在进行计算时,要从6w个样本中提取出属于 i 的样本

假设我们已经提取出了属于数字0的所有样本,假设共有6000个,即我们得到了6000 X 28 X 28 的图片,按照上述说的,要进行降维。
也就是我们会有 7 X 7个 6000 X 4 X4个图片,然后我们将 6000 X 4 X4降维成6000个0/1数据的一维数组;也就是49个一维数组
按照条件概率公式,我们最终要将6000个求和的,也就是最后变成了一个49个元素的一维数组

实现起来非常简单:

P=np.zeros([10,49])  #条件概率
Pw=np.zeros(10)     #先验概率
def train(label): 
    Pw[label]=np.argwhere(labels == label)[:,0].shape[0]/labels.shape[0]    #统计P(wi)
    
    for i in [0,4,8,12,16,20,24]:
        for j in [0,4,8,12,16,20,24]:
            imgs_0=imgs[np.argwhere(labels == label)[:,0],j:j+4,i:i+4];
            P[label][i//4*7+j//4]=(count(imgs_0)+1)/(imgs_0.shape[0]+2)   #获得Pj(wi)
            
def count(img):           #统计累计xkj
    img=img>0             #统计大于0的点,
    img=img.sum(axis=2)
    img=img.sum(axis=1)   #两次求和得到每个面的和
    tem=img>=8            #大于一半
    return tem.sum()

函数count(img),作用是统计:
在这里插入图片描述
将 6000 X 4 X4降维成6000个0/1数据的一维数组,其实就是将平面求和,通过两次sum就可以实现
最后一次sum是将6000个0/1求和
对于一个数字 i 来说,该函数应该被调用7 X 7次(因为被分成了这么多份)

而train(label)的作用是统计数字为label的所有条件概率,顺便求一下先验概率
如上述所说,会调用7*7次count
而这个函数应该被调用10次(因为有10个数字)
因此在主函数中,会有

#计算全部的Pj(wi),得到训练结果
for label in range(0,10):
    train(label)
'''     训练完成            '''

至此,训练完成,最终得到了两个概率矩阵

第三步,进行测试

首先还是要读取其数据集

#读入测试集
new_imgs=loadImageSet(1)
new_labels=loadLabelSet(1)

之后,逐个样本的去判断,并统计正确个数

#逐个进行识别
count=0
for k in range(0,new_imgs.shape[0]):
    test_k=test_condition(new_imgs[k,:,:])
    if test_k==new_labels[k]:
        count=count+1

关键是要计算类条件概率:
在这里插入图片描述
在这里插入图片描述
因此对于我们每一张图片,还是要降维,然后判断是1还是0,是1就返回P[label][i],是0就返回1-P[label][i],

def count_test(img,label,i):
    img=img>0   #传入的img是4*4的
    flag=img.sum()>=8  #降维
    if flag:
        return P[label][i]
    else:
        return 1-P[label][i]

因此,对于一个测试样本,上面函数要被调用10 X 7 X 7次(共有10个数,每个数进行49次)

def test_condition(img):
    condition_P=[]
    after_P=[]   #储存P(wi|X)
    
    #计算条件概率
    for label in range(0,10):
        condition_P.append(1)
        after_P.append(0)
        for i in [0,4,8,12,16,20,24]:
            for j in [0,4,8,12,16,20,24]:
                img_=img[j:j+4,i:i+4]
                condition_P[label]=condition_P[label]*count_test(img_,label,i//4*7+j//4)
    #计算后验概率
    for label in range(0,10):
        after_P[label]=Pw[label]*condition_P[label]
        
    return after_P.index(max(after_P))   #选取最大的对应的位置,就是判断的数字

完整主函数为:

#读取训练集
imgs=loadImageSet()
labels=loadLabelSet()

#计算全部的Pj(wi),得到训练结果
for label in range(0,10):
    train(label)
'''     训练完成            '''

#读入测试集
new_imgs=loadImageSet(1)
new_labels=loadLabelSet(1)

#逐个进行识别
count=0
for k in range(0,new_imgs.shape[0]):
    test_k=test_condition(new_imgs[k,:,:])
    if test_k==new_labels[k]:
        count=count+1
        
print("正确个数:",count)
print("\n正确率:",count/new_labels.shape[0])

总共代码为120行左右,正确率在0.74左右

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值