機器學習練習之樸素貝葉斯

     練習來自http://openclassroom.stanford.edu/MainFolder/DocumentPage.php?course=MachineLearning&doc=exercises/ex6/ex6.html

貝葉斯定理

         貝葉斯定理是概率論中非常重要的定理, 數學家Harold Jeffreys曾說"Bayes therom is the theory of probability what pythagoras's therom is to geometry"。

        

       貝葉斯定理是基於條件概率的:

    

        而貝葉斯公式如下:

      (來自http://www2.imm.dtu.dk/courses/02443/slides2014/Bayes_HO.pdf

       貝葉斯定理是教我們從現象中去推斷本質或原因的一種方法。假設我們已經有了歷史數據(x, y),x可以看作是現象或事件,y是本質或原因,然後給出新的x,要推斷出y是什麼。比如貝葉斯可以用於醫療診斷,醫療的歷史數據使我們知道在病人得了某種病後會有哪些症狀、以及病種的分佈情況,當有一個未確診的病人出現時,根據病人發生的症狀我們就可以推測病人患各種病的概率。

      貝葉斯定理涉及到先驗概率、後驗概率。先驗概率是通過歷史數據產生的,對於上面的貝葉斯公式,就是y的分佈,一般而言y是離散的。P(y)是對歷史數據y的似然估計。先驗概率告訴我們,隨便給出一個樣本,y的概率分佈。後驗概率是根據觀察數據x去推斷y的概率分佈。所以PRML書上說,posterior ∝ likelihood × prior。貝葉斯定理融合了先驗概率和極大似然估計,極大似然估計就是likelihood,比如給出訓練數據,likelihood可以得出最可能的模型,但是貝葉斯還考慮了先驗概率,雖然那個似然最大的模型最大概率產生數據,但是如果那個模型很少見,概率很低,這樣綜合考慮起來就可能不是最優的模型。

        如果歷史數據是無窮的,那麼給出x,我們只要找到使得P(x|y)最大的y就行了,這就是頻率論的最大似然估計,在機器學習中,-logP(x|y)就是損失函數,所以最大似然估計就是要最小化損失。貝葉斯定理的一個特點是融合了先驗分佈P(y), 頻率學派認爲這個是爲了數學的方便而不是真實先驗的反映,而且錯誤的先驗選擇可能導致錯誤的結果具有很高的置信度(參考PRML).


樸素貝葉斯


   樸素貝葉斯是基於貝葉斯定理與特徵條件獨立假設的分類方法,對於給定的訓練數據集,首先基於特徵條件獨立假設學習輸入/輸出的聯合概率分佈,然後基於此模型,對給定的輸入x,利用貝葉斯定理求出後驗概率最大的輸出y。樸素貝葉斯法實現簡單,學習與預測的效率都很高,是一種常用的方法。(參見《統計學習方法》樸素貝葉斯法)。

   樸素貝葉斯法是屬於生成模型,什麼是生成模型呢?在監督學習中,我們要學到一個模型,使用這個模型,對於給定的輸入可以預測相應的輸出。模型的一般形式爲決策函數Y=f(X)或條件概率分佈f(Y|X)。生成模型的特點是要生成或可以還原聯合概率分佈p(x,y),比如這裏的貝葉斯法是能夠學習到p(x,y)的,而判別模型則不能,像logistic regression就是判別模型,模型可以得到p(y|x)的概率,像感知機模型,只要算出w*x+b就能知道屬於那個類別,這也是判別模型。

       好了, 回到本文的練習,這個練習是要用樸素貝葉斯法對郵件進行分類(垃圾郵件、非垃圾郵件)。
對於這個問題,樸素貝葉斯法的模型爲:
 

        給定了郵件訓練數據,可以求出垃圾郵件和非垃圾郵件的先驗分佈,也可以分別求出垃圾郵件和非垃圾郵件中每個詞出現的概率。樸素貝葉斯的”樸素“就是認爲每個詞出現是獨立的,與其它詞的出現沒有關係。垃圾郵件和非垃圾郵件對整個詞庫有不一樣的分佈情況,對於(非)垃圾郵件,全部詞出現的概率加起來是等於1的,這又像是多項式分佈了。在計算詞在每個類別的概率時,用到了拉普拉斯平滑,這是爲了防止在給新郵件進行計算它屬於(非)垃圾郵件的概率,遇到了沒有在訓練數據見過的單詞時,概率爲0,這樣乘起來結果就是0,所以預定給每個單詞出現次數加1,這樣爲了概率和爲1,分母中加了總詞數。上圖中的前兩個公式是對於詞庫中的每個詞在垃圾郵件和非垃圾郵件出現的全部詞中的概率。由於每個單詞出現的概率可能很低,爲了防止下溢,使用自然對數進行計算。

    

     


郵件分類程序


%% Exercise 6: Naive Bayes
% 樸素貝葉斯練習:垃圾郵件分類
% Multinomial Naive Bayes model

numTrainDocs = 700;  % 文檔數量
numTokens = 2500;  % 詞庫

 %讀取訓練集特徵文件,每行有3個元素,表示文檔id、詞id和詞頻
 %dlmread讀取以ascii碼分割的文件中的數字
M = dlmread('train-features.txt', ''); 

%根據訓練集特徵構建稀疏矩陣,矩陣大小爲numTrainDocs*numTokens
%S = sparse(i,j,s,m,n), i,j爲向量,S(i(k),j(k))=s(k),S大小爲m*n
%表示形式爲:(i(k) j(k)) s(k)
spmatrix = sparse(M(:,1), M(:,2), M(:,3), numTrainDocs, numTokens); 

% 根據稀疏矩陣還原完整矩陣
train_matrix = full(spmatrix);

%讀取文檔類別
train_labels = dlmread('train-labels.txt');

% 訓練過程
spam_index = find(train_labels);   %記錄垃圾郵件索引
nonspam_index = find(train_labels==0);  %記錄非垃圾郵件索引

proc_spam = length(spam_index)/numTrainDocs; % 計算垃圾郵件概率
% 分別計算垃圾和非垃圾郵件中每個單詞出現的次數
% train_matrix(spam_index,:)找出屬於垃圾郵件的文檔向量
% sum(train_matrix(spam_index, :))對每一列的所有行累加起來,即統計該詞在垃圾郵件中出現的總次數
wc_spam = sum(train_matrix(spam_index, :));
wc_nonspam = sum(train_matrix(nonspam_index, :));
% 分別計算tokens在垃圾郵件和非垃圾郵件中出現的概率
prob_tokens_spam = (wc_spam + 1) ./ (sum(wc_spam) + numTokens);
prob_tokens_nonspam = (wc_nonspam + 1) ./ (sum(wc_nonspam) + numTokens);

% 測試
test_labels = dlmread('test-labels.txt');

M = dlmread('test-features.txt', '');
% 構建稀疏矩陣,這麼貌似有個問題,如果測試文檔中不含有第2500個詞的話,構建出的稀疏矩陣列數不是numTokens
% 下面的test_matrix乘於訓練出來的(log(spam_wc_proc))'就肯定會出錯
spmatrix = sparse(M(:,1), M(:,2), M(:,3));

test_matrix = full(spmatrix);

% 分別計算test_matrix的每一行即每篇文檔屬於垃圾郵件和非垃圾郵件的概率
% logp(x|y=1) + logp(y=1)
test_spam_proc = test_matrix * (log(prob_tokens_spam))' + log(proc_spam);
% logp(x|y=0) + logp(y=0)
test_nonspam_proc = test_matrix * (log(prob_tokens_nonspam))' + log(1-proc_spam);
% 預測
test_spam = test_spam_proc > test_nonspam_proc;
% 計算分類準確率
accuracy = sum(test_spam==test_labels) / length(test_labels);
fprintf('Accuracy:%f\n', accuracy);




實驗有3個訓練集,分別包括50、100和400封郵件的,實驗結果表明使用越多的訓練集,在同一測試集上的結果的準確率越高。


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