贝叶斯决策分类器 MNIST手写数据集 分类 python实现
转载: (1) https://zhuanlan.zhihu.com/p/51200626
(2) 菊安酱的机器学习第三期
(3) 代码来自:https://github.com/WenDesi/lihang_book_algorithm
(4) https://blog.csdn.net/taiji1985/article/details/73657994
贝叶斯:
首先,贝叶斯分类算法是统计学中的一种概率分类方法,朴素贝叶斯分类是贝叶斯分类中的一种,其分类原理就是利用贝叶斯公式根据某特征的先验概率计算出后验概率,然后选择最大后验概率的类作为该特征所属的类。
在生活中常常用贝叶斯做决策,先看一下公式:
光看公式不知道咋用,举个例子说明一下:
这个例子是女生根据男生的三个特征来确定是不是嫁给他。
朴素贝叶斯:
分子上的式子为什么能连乘?
概率老师不是说过只有相互独立才能直接拆吗?是的,朴素贝叶斯分类器对条件概率分布做出了条件独立性的假设。为啥?因为这样能算,就这么简单,如果条件都不独立,后面咋整?(读者:那你这不严谨啊)。emmm….事实上是这样,向量的特征之间大概率是不独立地,如果我们假设独立了,会无法避免地抛弃一些前后连贯的信息(比方说我说“好事成_”,后面大概率就是个”双“,这个双明显依赖于前面的三个字)。在建立模型时如果这些都考虑进去,会让模型变得很复杂。后来前人说那我们试试不管它们,强行独立。诶发现效果还不错诶,那就这么用吧。这就是计算机科学家和数学家的分歧所在。
上图中P(X=x|Y=Ck)转换成能求的式子了以后,那么就是比较Y为不同Ck的情况下哪个概率最大,那就表示属于哪个类的可能性最大。所以前头式子前头加上一个argmax,表示求让后式值最大的Ck。
然后由于下图中圈出来这一项是在Y为不同Ck情况下的连乘,所以不管k为多少,所有Ck连乘结果肯定是一致的,在比较谁的值最大时,式子里面的常数无法对结果的大小造成影响,可以去掉。
变成了这样:
使用朴素贝叶斯分类MNIST手写数据集:
在数据集中,每个图片作为一个样本,它的分类结果共有10类,分别为0,1,2,3,…9 。 数据集中每张图片的的每个像素采用灰度值,我们为了方便下面处理将它变成二值图像。即将非0的点置为1。这样处理后,我们可以认为一个像素是否为1变成一个0-1分布。
我们计算这样一个概率值:
![](https://img2018.cnblogs.com/blog/1408690/201905/1408690-20190508161832273-1025299375.png)
![](https://img2018.cnblogs.com/blog/1408690/201905/1408690-20190508162011025-1310834088.png)
代码实现:
import pandas as pd import numpy as np import cv2 import random import time from sklearn.cross_validation import train_test_split from sklearn.metrics import accuracy_score # 二值化 def binaryzation(img): cv_img = img.astype(np.uint8) cv2.threshold(cv_img,50,1,cv2.THRESH_BINARY_INV,cv_img) return cv_img def Train(trainset,train_labels): prior_probability = np.zeros(class_num) # 预设先验概率 p(y = j) conditional_probability = np.zeros((class_num,feature_len,2)) # 预设条件概率 p(xk | y) # 计算先验概率及条件概率 for i in range(len(train_labels)): #训练集标签的数量 img = binaryzation(trainset[i]) # 图片二值化 对每一个图片进行二值化 label = train_labels[i] #对每一张图片赋予标签 prior_probability[label] += 1 #先验概率,总要计算出训练集中同一种标签的数量,比如说是数字1的图片有多少张 for j in range(feature_len):#对每一张图片的每一个像素进行操作,统计同一种标签下的图像中各像素取值的数量 conditional_probability[label][j][img[j]] += 1 #属于第i类的图像中像素j为0和1的数量 prior_probability =np.log((prior_probability + 1) / (len(trainset))) #先验概率平滑 # 将概率归到[1,10000] for i in range(class_num): for j in range(feature_len): # 经过二值化后图像只有0,1两种取值 pix_0 = conditional_probability[i][j][0]# 得到属于第i类的图像中第j个像素像素值为0的数量 pix_1 = conditional_probability[i][j][1]# 得到属于第i类的图像中第j个像素像素值为1的数量 # 计算0,1像素点对应的条件概率 后验概率平滑 probalility_0 = (float(pix_0)+1)/(float(pix_0+pix_1)+2)*1000000 # 拉普拉斯平滑 probalility_1 = (float(pix_1)+1)/(float(pix_0+pix_1)+2)*1000000 conditional_probability[i][j][0] = np.log(probalility_0) # 得到 P(Xk|y) conditional_probability[i][j][1] = np.log(probalility_1) return prior_probability,conditional_probability # 计算概率 def calculate_probability(img,label): probability = prior_probability[label] #先验概率 sum = 0 for i in range(len(img)): # 取log变为相加 sum += int(conditional_probability[label][i][img[i]]) probability = probability + sum return probability def Predict(testset,prior_probability,conditional_probability): predict = [] for img in testset: # 图像二值化 img = binaryzation(img) 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) class_num = 10 feature_len = 784 if __name__ == '__main__': print('Start read data') time_1 = time.time() raw_data = pd.read_csv('mnist_train.csv',header=0) data = raw_data.values imgs = data[0::,1::] #取出像素值 labels = data[::,0] #取出标签值 time_2 = time.time() print('read data cost ',time_2 - time_1,' second','\n') print('Start training') prior_probability,conditional_probability = Train(imgs,labels) time_3 = time.time() print('training cost ',time_3 - time_2,' second','\n') test_data = pd.read_csv('mnist_test.csv',header=0) test_data = test_data.values test_imgs = test_data[0::,1::] #取出测试集像素值 test_labels = test_data[::,0] #取出测试集标签值 print('Start predicting') test_predict = Predict(test_imgs,prior_probability,conditional_probability) time_4 = time.time() print('predicting cost ',time_4 - time_3,' second','\n') score = accuracy_score(test_labels,test_predict) print("The accruacy socre is ", score)
测试结果: