1.樸素貝葉斯算法介紹
算法本質的是貝葉斯公式 ,計算在已知數據的條件下,求各個分類的後驗概率,數據的分類結果是概率最大的那個分類。
樸素一詞的來源是假設各特徵之間相互獨立。因此
2.MNIST數據集介紹
數據集地址:http://yann.lecun.com/exdb/mnist/
2.1基本介紹
MNIST數據集是一個手寫數字0~9的圖片數據集,訓練集60000,測試集10000,每張圖28*28.
2.2如何用Python讀取
開始下載了數據集,解壓後本以爲是圖片,結果是二進制文件,然後就不知道怎麼讀取了。查閱之後發現文件的格式是idx3-utype和idx1-utype,在數據集的網站上有介紹,如下圖:
如何讀取這種文件呢?要先讀數據頭,以idx3爲例,前8個數據是數據頭,第一個數是magic number(魔數),暫且不管;第二個數是圖片的數量(60000);第三和四個是圖片的行列像素值(28*28).然後讀取之後的數據,之後的都是像素值(8byte)。
具體程序如下:
def deconde_idx1_ubyte(filename):
# 讀取二進制數據
bin_data = open(filename, 'rb').read()
# 解析文件頭信息,依次爲魔數和標籤數
offset = 0
fmt_header = '>ii'
magic_number, num_images = struct.unpack_from(fmt_header, bin_data, offset)
# print('魔數:%d, 圖片數量: %d張' % (magic_number, num_images))
# 解析數據集
offset += struct.calcsize(fmt_header)
fmt_image = '>B'
labels = np.empty(num_images)
for i in range(num_images):
# if (i + 1) % 10000 == 0:
# print ('已解析 %d' % (i + 1) + '張')
labels[i] = struct.unpack_from(fmt_image, bin_data, offset)[0]
offset += struct.calcsize(fmt_image)
return labels
def decode_idx3_ubyte(filename):
bin_data = open(filename, 'rb').read()
# 解析文件頭信息,依次爲魔數、圖片數量、每張圖片高、每張圖片寬
offset = 0
fmt_header = '>iiii' #因爲數據結構中前4行的數據類型都是32位整型,所以採用i格式,但我們需要讀取前4行數據,所以需要4個i。我們後面會看到標籤集中,只使用2個ii。
magic_number, num_images, num_rows, num_cols = struct.unpack_from(fmt_header, bin_data, offset)
# print('魔數:%d, 圖片數量: %d張, 圖片大小: %d*%d' % (magic_number, num_images, num_rows, num_cols))
# 解析數據集
image_size = num_rows * num_cols
offset += struct.calcsize(fmt_header) #獲得數據在緩存中的指針位置,從前面介紹的數據結構可以看出,讀取了前4行之後,指針位置(即偏移位置offset)指向0016。
# print(offset)
fmt_image = '>' + str(image_size) + 'B' #圖像數據像素值的類型爲unsigned char型,對應的format格式爲B。這裏還有加上圖像大小784,是爲了讀取784個B格式數據,如果沒有則只會讀取一個值(即一副圖像中的一個像素值)
# print(fmt_image,offset,struct.calcsize(fmt_image))
images = np.empty((num_images, num_rows, num_cols))
for i in range(num_images):
# if (i + 1) % 10000 == 0:
# print('已解析 %d' % (i + 1) + '張')
# print(offset)
images[i] = np.array(struct.unpack_from(fmt_image, bin_data, offset)).reshape((num_rows, num_cols))
offset += struct.calcsize(fmt_image)
# images = np.reshape(images, (num_images, image_size))
return images
3.基本步驟
- 讀取數據集
- 訓練模型
2.1. 求先驗概率,p(c1), p(c2)…
2.2. 求條件概率, p(x|c1),p(x|c2)… - 對測試集進行預測,求準確率
4.程序
from PIL import Image
import numpy as np
import struct
import math
import matplotlib.pyplot as plt
from collections import Counter
#將28*28的圖片變化成5*5的圖片
def imageResize(images):
#images.shape = (60000, 28, 28)
nx, ny, nz = images.shape
dataSetResize = np.empty((nx, 25))
for i in range(nx):
tempdata = np.array(Image.fromarray(images[i]).resize((5, 5)))
dataSetResize[i] = np.resize(tempdata, 25)
return dataSetResize
#二值化
def Binarization(images):
for i in range(images.shape[0]):
imageMean = images[i].mean()
images[i] = np.array([0 if x < imageMean else 1 for x in images[i]])
return images
#模型訓練
def Bayes_train(train_x, train_y):
#先驗概率P(0), P(1)....
totalNum = train_x.shape[0]
classNum = Counter(train_y)
prioriP = np.array([classNum[i]/totalNum for i in range(10)])
#後驗概率
posteriorNum = np.empty((10, train_x.shape[1]))
posteriorP = np.empty((10, train_x.shape[1]))
for i in range(10):
posteriorNum[i] = train_x[np.where(train_y == i)].sum(axis = 0)
#拉普拉斯平滑
posteriorP[i] = (posteriorNum[i] + 1) / (classNum[i] + 2)
return prioriP, posteriorP
#模型預測
def Bayes_pret(test_x, test_y, prioriP, posteriorP):
pret = np.empty(test_x.shape[0])
for i in range(test_x.shape[0]):
prob = np.empty(10)
for j in range(10):
temp = sum([math.log(1-posteriorP[j][x]) if test_x[i][x] == 0 else math.log(posteriorP[j][x]) for x in range(test_x.shape[1])])
prob[j] = np.array(math.log(prioriP[j]) + temp)
pret[i] = np.argmax(prob)
return pret, (pret == test_y).sum()/ test_y.shape[0]
def main():
train_x_data = decode_idx3_ubyte('./data/train_images')
# train_x = imageResize(train_x)
train_y = deconde_idx1_ubyte('./data/train_labels')
train_x = np.resize(train_x_data, (train_x_data.shape[0], train_x_data.shape[1]*train_x_data.shape[2]))
train_x = Binarization(train_x)
test_x_data = decode_idx3_ubyte('./data/test_images')
# test_x = imageResize(test_x)
test_y = deconde_idx1_ubyte('./data/test_labels')
test_x = np.resize(test_x_data, (test_x_data.shape[0], test_x_data.shape[1]*test_x_data.shape[2]))
test_x = Binarization(test_x)
prioriP, posteriorP = Bayes_train(train_x, train_y)
accuracy = Bayes_pret(test_x, test_y, prioriP, posteriorP)
print(accuracy)
if __name__ == "__main__":
main()
準確率:
#5*5
0.5856
#28*28
0.8474