機器學習_樸素貝葉斯算法識別手寫數字

樸素貝葉斯算法是基於條件概率的一種分類算法,通過概率大小來進行分類,經常用於分類文檔。本文用python實現樸素貝葉斯算法,並用kaggle識別手寫數字的數據集來訓練,得到81%的準確率。雖然準確率可能比不上其它如SVM、神經網絡等算法,但是樸素貝葉斯算法相對來說簡單,計算速度也較快。

樸素貝葉斯理論說明

樸素貝葉斯的基本公式:
P(c1|w)>P(c0|w) ,則w樣本屬於c1 類別;
P(c1|w)<P(c0|w) ,則w樣本屬於c0 類別。
同樣在多分類問題中,P(ci|w) 最大時表示樣本w 屬於ci 分類。其中P(ci|w) 表示挑選出來的樣本w 屬於ci 的概率。

  • 通常P(ci|w) 難以直接求得,可用條件概率間接求,公式如下:
    P(ci|w)=P(w|ci)P(ci)P(w)
    其中P(w|ci) 表示從ci 類中取出樣本w 的概率,P(ci) 表示類別ci 的概率,以上公式的由來相信學過概率論的同學應該都比較清楚這是條件概率。

  • 主要過程

    1. 計算條件概率P(w|ci)P(ci) ,假設各特徵相互獨立,則P(w|ci)=P(w0|ci)P(w1|ci)....P(wn|ci)
    2. 對於一個數據集,取出每一個樣本概率 P(w) 值是一樣的,因此只需要比較P(ci|w) 的值,最大值條件下的ci 即分類結果
    3. 爲防止概率數值過小(接近於0)而出現下溢,因而採用logP(w|ci)P(ci) 來表示概率。

python實現

通過Kaggle識別手寫數字來實現樸素貝葉斯算法。

  • 訓練數據集
import numpy as np
def trainMethod(dataSet, classesLabel):
    m,n = dataSet.shape
    labelSet = set(classesLabel)
    numLabel = len(labelSet)
    numFeat = np.ones((numLabel,n))
    piLabel = np.zeros(numLabel)
    piDenom = np.ones(numLabel)+1
    for label in labelSet:
        for i in range(m):
            if classesLabel[i] == label:
                numFeat[label] += dataSet[i]
                piDenom[label] += sum(dataSet[i])
                piLabel[label] +=1
    for j in labelSet:
        numFeat[j] = np.log(numFeat[j]/piDenom[j])
    piLabel = piLabel/m
    return numFeat, piLabel
  • 測試算法
import numpy as np
import pandas as pd
import csv
#預測函數
def predict(testVec, piFeat, piLabel):
    maxPi = sum(testVec * piFeat[0]) + np.log(piLabel[0])  # 初始化
    maxIndex = 0
    for i in range(len(piLabel)):
        currentPi = sum(testVec * piFeat[i]) + np.log(piLabel[i])
        if currentPi > maxPi:
            maxPi = currentPi
            maxIndex = i
    return maxIndex

#圖片二像素化,即把圖片變爲黑白,沒有灰度
def normalizing(array):
    m,n = array.shape
    for i in range(m):
        for j in range(n):
            if array[i, j]!=0:
                array[i, j]=1  #非零全部轉化爲1
    return array

# 定義數據集加載函數
def loadTrainData():
    csv_data = np.array(pd.read_csv('kaggle_dataset/digit_recognize/train.csv'))
    label = csv_data[:,0]  #取值label
    data = csv_data[:,1:]  #取像素質值
    return label, normalizing(data)
# 加載測試數據,測試數據中沒有label
def loadTestData():
    csv_test = np.array(pd.read_csv('kaggle_dataset/digit_recognize/test.csv'))
    return csv_test
# 將數據寫入到csv中,python3讀寫
def saveResultCsv(result, csvName):
    with open(csvName, 'w', newline='') as myFile:
        writer = csv.writer(myFile)
        heads = ['ImageId', 'Label']
        writer.writerow(heads)
        j = 1
        for i in result:
            temp = [j, i]
            writer.writerow(temp)
            j += 1


label,dataSet= loadTrainData()
dataTest = loadTestData()
piFeat, piLabel = trainMethod(dataSet, label)
result = []
for i in range(len(dataTest)):
    result.append(predict(dataTest[i], piFeat, piLabel))
saveResultCsv(result, 'kaggle_dataset/digit_recognize/result_NB.csv')
  • 提交結果,準確率爲81%

樸素貝葉斯分類結果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章