1. 程式人生 > >資料探勘領域十大經典演算法之—樸素貝葉斯演算法(超詳細附程式碼)

資料探勘領域十大經典演算法之—樸素貝葉斯演算法(超詳細附程式碼)

簡介 NaïveBayes演算法,又叫樸素貝葉斯演算法,樸素:特徵條件獨立;貝葉斯:基於貝葉斯定理。屬於監督學習的生成模型,實現簡單,沒有迭代,並有堅實的數學理論(即貝葉斯定理)作為支撐。在大量樣本下會有較好的表現,不適用於輸入向量的特徵條件有關聯的場景。

基本思想 (1)病人分類的例子 某個醫院早上收了六個門診病人,如下表:

症狀  職業   疾病  ——————————————————  打噴嚏 護士   感冒  打噴嚏 農夫   過敏  頭痛  建築工人 腦震盪  頭痛  建築工人 感冒  打噴嚏 教師   感冒  頭痛  教師   腦震盪

現在又來了第七個病人,是一個打噴嚏的建築工人。請問他患上感冒的概率有多大?  根據貝葉斯定理:

P(A|B) = P(B|A) P(A) / P(B) 可得

P(感冒|打噴嚏x建築工人)  = P(打噴嚏x建築工人|感冒) x P(感冒) / P(打噴嚏x建築工人)

假定”打噴嚏”和”建築工人”這兩個特徵是獨立的,因此,上面的等式就變成了

P(感冒|打噴嚏x建築工人)  = P(打噴嚏|感冒) x P(建築工人|感冒) x P(感冒) / P(打噴嚏) x P(建築工人) 這是可以計算的。

P(感冒|打噴嚏x建築工人)  = 0.66 x 0.33 x 0.5 / 0.5 x 0.33  = 0.66 因此,這個打噴嚏的建築工人,有66%的概率是得了感冒。同理,可以計算這個病人患上過敏或腦震盪的概率。比較這幾個概率,就可以知道他最可能得什麼病。

這就是貝葉斯分類器的基本方法:在統計資料的基礎上,依據某些特徵,計算各個類別的概率,從而實現分類。

(2)樸素貝葉斯分類器的公式 假設某個體有n項特徵(Feature),分別為F1、F2、…、Fn。現有m個類別(Category),分別為C1、C2、…、Cm。貝葉斯分類器就是計算出概率最大的那個分類,也就是求下面這個算式的最大值:

P(C|F1F2...Fn) = P(F1F2...Fn|C)P(C) / P(F1F2...Fn) 由於 P(F1F2…Fn) 對於所有的類別都是相同的,可以省略,問題就變成了求

P(F1F2...Fn|C)P(C) 的最大值。  樸素貝葉斯分類器則是更進一步,假設所有特徵都彼此獨立,因此

P(F1F2...Fn|C)P(C) = P(F1|C)P(F2|C) ... P(Fn|C)P(C) 上式等號右邊的每一項,都可以從統計資料中得到,由此就可以計算出每個類別對應的概率,從而找出最大概率的那個類。  雖然”所有特徵彼此獨立”這個假設,在現實中不太可能成立,但是它可以大大簡化計算,而且有研究表明對分類結果的準確性影響不大。

(3)拉普拉斯平滑(Laplace smoothing) 也就是引數為1時的貝葉斯估計,當某個分量在總樣本某個分類中(觀察樣本庫/訓練集)從沒出現過,會導致整個例項的計算結果為0。為了解決這個問題,使用拉普拉斯平滑/加1平滑進行處理。  它的思想非常簡單,就是對先驗概率的分子(劃分的計數)加1,分母加上類別數;對條件概率分子加1,分母加上對應特徵的可能取值數量。這樣在解決零概率問題的同時,也保證了概率和依然為1。

eg:假設在文字分類中,有3個類,C1、C2、C3,在指定的訓練樣本中,某個詞語F1,在各個類中觀測計數分別為=0,990,10,即概率為P(F1/C1)=0,P(F1/C2)=0.99,P(F1/C3)=0.01,對這三個量使用拉普拉斯平滑的計算方法如下:  1/1003 = 0.001,991/1003=0.988,11/1003=0.011

實際應用場景 文字分類 垃圾郵件過濾 病人分類 拼寫檢查 樸素貝葉斯模型 樸素貝葉斯常用的三個模型有:

高斯模型:處理特徵是連續型變數的情況 多項式模型:最常見,要求特徵是離散資料 伯努利模型:要求特徵是離散的,且為布林型別,即true和false,或者1和0 程式碼實現 基於多項式模型的樸素貝葉斯演算法(在github獲取)

# encoding=utf-8

import pandas as pd import numpy as np import cv2 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)  # 型別轉化成Numpy中的uint8型     cv2.threshold(cv_img, 50, 1, cv2.THRESH_BINARY_INV, cv_img)  # 大於50的值賦值為0,不然賦值為1     return cv_img

# 訓練,計算出先驗概率和條件概率 def Train(trainset, train_labels):     prior_probability = np.zeros(class_num)                         # 先驗概率     conditional_probability = np.zeros((class_num, feature_len, 2))   # 條件概率

    #  計算     for i in range(len(train_labels)):         img = binaryzation(trainset[i])     # 圖片二值化,讓每一個特徵都只有0,1兩種取值         label = train_labels[i]

        prior_probability[label] += 1

        for j in range(feature_len):             conditional_probability[label][j][img[j]] += 1

    # 將條件概率歸到[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))*10000 + 1             probalility_1 = (float(pix_1)/float(pix_0+pix_1))*10000 + 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 j in range(feature_len):         probability *= int(conditional_probability[label][j][img[j]])

    return probability

# 預測 def Predict(testset, prior_probability, conditional_probability):     predict = []

    # 對每個輸入的x,將後驗概率最大的類作為x的類輸出     for img in testset:

        img = binaryzation(img)  # 影象二值化

        max_label = 0         max_probability = calculate_probability(img, 0)

        for j in range(1, class_num):             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  # MINST資料集有10種labels,分別是“0,1,2,3,4,5,6,7,8,9” feature_len = 784  # MINST資料集每個image有28*28=784個特徵(pixels)

if __name__ == '__main__':

    print("Start read data")     time_1 = time.time()

    raw_data = pd.read_csv('../data/train.csv', header=0)  # 讀取csv資料     data = raw_data.values

    features = data[::, 1::]     labels = data[::, 0]

    # 避免過擬合,採用交叉驗證,隨機選取33%資料作為測試集,剩餘為訓練集     train_features, test_features, train_labels, test_labels = train_test_split(features, labels, test_size=0.33, random_state=0)

    time_2 = time.time()     print('read data cost %f seconds' % (time_2 - time_1))

    print('Start training')     prior_probability, conditional_probability = Train(train_features, train_labels)     time_3 = time.time()     print('training cost %f seconds' % (time_3 - time_2))

    print('Start predicting')     test_predict = Predict(test_features, prior_probability, conditional_probability)     time_4 = time.time()     print('predicting cost %f seconds' % (time_4 - time_3))

    score = accuracy_score(test_labels, test_predict)     print("The accruacy score is %f" % score) 測試資料集為MNIST資料集,獲取地址train.csv

執行結果

è¿éåå¾çæè¿°