詳解樸素貝葉斯的來源,原理以及例項解析

想學習的弱雞小白發表於2020-11-01

出現背景:

在貝葉斯公式出現之前,人們只會解決正向概率問題,即“假如一個袋子裡有5個白球,3個黑球。現從中摸一個球,取得白球的概率。”實際上,這是從上帝視角來看待問題,在實際生活中的用途並不大。
而貝葉斯公式要解決的是逆向概率問題,即“袋子裡白球和黑球兩種顏色的球的個數是未知的,現從中多次摸球,推斷袋中兩種顏色的球各有多少。”這就很符合實際生活中的場景,站在“普通人的角度”一步步解決問題。當然,也可以細心的發現這很符合機器學習的思想,因為很明顯,摸球的次數會決定推斷的準確性,而一次次的摸球實際上就是一個學習的過程。而解決這個逆向概率問題的演算法就是貝葉斯演算法。

相關公式:

條件概率:
在這裡插入圖片描述
貝葉斯公式:
在這裡插入圖片描述

全概率公式:
在這裡插入圖片描述

樸素貝葉斯公式:
在這裡插入圖片描述

原理及大致流程:

貝葉斯定理

之前有一門概率論課程,已經學習過貝葉斯定理,但是當時學習的時候沒有考慮到它的應用,只知道在機器學習中很有用。現在看著這道題目,再回頭重新理解貝葉斯定理。在這之前,首先介紹兩個概念:先驗概率和後驗概率。
先驗概率:指根據以往經驗和分析得到的概率,如全概率公式,它往往作為"由因求果"問題中的"因"出現(公式中的P(B)即為先驗概率)。
後驗概率:指依據得到"結果"資訊所計算出的最有可能是那種事件發生,如貝葉斯公式中的,是"執果尋因"問題中的"因"(公式中的P(B|A)即為後驗概率)。
因此實際上先驗概率就是利用以往的資料通過古典概率模型加以定義的,較為容易計算得到結果。而後驗概率則需要使用貝葉斯公式。
從另一個角度理解的話,就是實際上如果沒有大量資料的話,我們只知道先驗概率P(B),而作為機器學習演算法,貝葉斯演算法可以通過大量的樣本A,通過判斷P(A|B)/P(A)是否大於1,來對P(B)進行修正,即B的條件下A發生的概率大於A本身發生的概率,那麼就認為A的條件下B發生的概率大於B本身的概率,當然,這是根據公式嚴密的推導得到的。
得到貝葉斯演算法後,進一步考慮這個公式,A是結果B發生的一個條件,或者說是樣本的一個特徵,而樣本的特徵往往不是一維的,比如決策一個人是否健康的標準,特徵可能會有“身高,體重,肺活量,血壓…”多維變數,若用Ai表示其中的n個特徵中的每個標籤,則貝葉斯公式分子中的P(A|B)便需要計算結果B發生的條件下這n個標籤同時發生的概率,在這裡假設n=2,則公式為
在這裡插入圖片描述

樸素貝葉斯

當n的值較大時,計算P(A1,A2,…An|Bi)的難度是很大的,此時便需要用到很重要的一個假設:假設這n個標籤是相互獨立的。這樣假設的目的是簡化計算,因為可以化成單標籤概率的乘積。但假設是需要前提的,即不同的標籤是不一定獨立的,甚至大多數時候都是不獨立的。儘管如此,事實上這樣的獨立假設產生的效果是很好的。而這也是樸素貝葉斯中的“樸素”二字的由來。經過這樣的假設以後,得到的式子便是上面的樸素貝葉斯公式

拉普拉斯平滑

但是不能忽視的一點是如果P(Ai|B)或者P(Bi)的值為0該如何,按照公式我們會得到P(Bi|A)=0的結果,即下結論為“這種情況下Bi絕不可能發生”,然而這樣貌似是不準確的,比如實際生活中,假如國足連輸了10場,如果我們用這10場資料應用樸素貝葉斯公式,會發現預測第11場勝利的概率為0,但這個說法未免過於絕對。因此,我們引入了一種方法,叫做拉普拉斯平滑,它在每個標籤的條件概率計算時分子加1,分母加上標籤分量個數。這樣做正確的依據是當資料量很大時,加的值幾乎可以忽略,同時還可以避免分子為0的情況。

結論

最終,貝葉斯演算法要得到的是使得P(Bj|A)最大的j,此時可以負責任的說“Bj”是最有可能發生的。

應用

題目

在這裡插入圖片描述(中文請自行翻譯)

思路

這個題目中,給定了訓練資料集和測試資料集,要求利用訓練資料集的資料來應用到測試資料集中,對孩子是否應該入學進行不同等級的劃分。這裡我們抽象出上面的A和B:最終判斷孩子是否應該入學的5個等級即為B,而其中的特徵向量便是A,每個特徵向量是一個包含8個標籤的Ai,我們要做的就是基於訓練資料,對於測試資料中的每個特徵向量,找到P(Bj|A)(j=1,…,5)中使得概率最大的j,Bj即為最終要做出的判斷。由於此題中的所有資料均是離散的,並不是連續資料,因此不需要考慮概率分佈問題,只需要統計資料即可。我們可以根據資料集很容易的統計出P(Bj)的值,當然,這裡需要加入拉普拉斯平滑;同時也可以得到P(Ai|Bj)的值(根據條件概率的公式得到)。這樣分子就可以通過資料集統計得到,而針對一個特徵向量,需要比較的不同的Bj中,分母的P(A)是完全相同的,因此可以只通過比較分子來判斷即可。

解題步驟(這裡使用matlab實現)

  1. 匯入訓練資料和測試資料集。
  2. 藉助拉普拉斯平滑計算P(Bj)。
for i=1:5
  p_y(i)=(length(find(train_data(:,9)==i-1))+1)/(length(train_data)+5);%應用拉普拉斯平滑
  1. 計算測試集中每一行的特徵向量A對應的P(A|Bj),並找出其中最大的概率,記錄此時的概率之和Bj。
for i=1:1:length(test_data)
  max=zeros(1,2);%儲存
  for y=0:1:4
    a=1;
    for t=1:8
      b=length(find(train_data(:,t)==test_data(i,t) & train_data(:,9)==y));
      c=length(find(train_data(:,9)==y));
      if t==1
        a*=(b+1)/(c+3);
      elseif t==2
        a*=(b+1)/(c+5);
      elseif t==3
        a*=(b+1)/(c+4);
      elseif t==4
        a*=(b+1)/(c+4);
      elseif t==5
        a*=(b+1)/(c+3);
      elseif t==6
        a*=(b+1)/(c+2);
      elseif t==7
        a*=(b+1)/(c+3);
      elseif t==8
        a*=(b+1)/(c+3);
      end
    endfor
    p=a*p_y(y+1);
    if p>max(1,1)%利用極大似然思想進行比較,選擇概率最大的情況
      max(1,1)=p;%儲存概率
      max(1,2)=y;%儲存最可能的y值
    endif
  endfor
  1. 將測試資料集中得到的所有Bj和實際結果做對比,判斷最終的預測準確率。
sum = length(find(ans(:,1)==test_data(:,9)));%記錄預測的資料個數
rate=sum/length(test_data);%準確概率
  1. 縮小訓練的資料集,從原來的訓練資料中選擇其中的一部分,生成smaller_training_data。
train_data = load('training_data.txt');
data_num=length(train_data);
smaller_num = 8000;%可變
training_num=smaller_num;
smaller_data_index = randperm(data_num, training_num);%在所有的訓練集中,隨機選擇一部分
training_data = zeros(training_num, 9);%訓練集
training_it = 0;%訓練集行索引
%分選取更小的訓練集
for i=1:1:data_num
    flag = 0;%標記為訓練資料
    for j=1:1:training_num
        if(smaller_data_index(j)==i)
            flag = 1;%標記為小資料
        end
    end
    if(flag==1)
        training_it = training_it+1;
        training_data(training_it,:) = train_data(i,:);
    end
end
%將小訓練集輸出到新檔案中
fid = fopen('training_data2.txt','wt');
for i=1:1:training_num
    fprintf(fid,'%d %d %d %d %d %d %d %d %d\n',training_data(i,1), training_data(i,2), training_data(i,3), training_data(i,4), training_data(i,5), training_data(i,6), training_data(i,7), training_data(i,8), training_data(i,9));
end
fclose(fid);
  1. 觀察並對比不同的訓練資料集下測試資料的準確率。
訓練資料集大小測試資料集準確率
20000.90642
40000.90541
60000.90777
80000.91149
100000.90980

完整程式碼

### Naive_Bayes:
train_data = load('training_data.txt');
data_num=length(train_data);

smaller_num = 8000;%可變
training_num=smaller_num;

smaller_data_index = randperm(data_num, training_num);%在所有的訓練集中,隨機選擇一部分

training_data = zeros(training_num, 9);%訓練集

training_it = 0;%訓練集行索引


%分選取更小的訓練集
for i=1:1:data_num
    flag = 0;%標記為訓練資料
    for j=1:1:training_num
        if(smaller_data_index(j)==i)
            flag = 1;%標記為小資料
        end
    end
    if(flag==1)
        training_it = training_it+1;
        training_data(training_it,:) = train_data(i,:);
    end
end


%將小訓練集輸出到新檔案中
fid = fopen('training_data2.txt','wt');
for i=1:1:training_num
    fprintf(fid,'%d %d %d %d %d %d %d %d %d\n',training_data(i,1), training_data(i,2), training_data(i,3), training_data(i,4), training_data(i,5), training_data(i,6), training_data(i,7), training_data(i,8), training_data(i,9));
end
fclose(fid);

### Smaller_size:
train_data = load('training_data.txt');
data_num=length(train_data);

smaller_num = 8000;%可變
training_num=smaller_num;

smaller_data_index = randperm(data_num, training_num);%在所有的訓練集中,隨機選擇一部分

training_data = zeros(training_num, 9);%訓練集

training_it = 0;%訓練集行索引


%分選取更小的訓練集
for i=1:1:data_num
    flag = 0;%標記為訓練資料
    for j=1:1:training_num
        if(smaller_data_index(j)==i)
            flag = 1;%標記為小資料
        end
    end
    if(flag==1)
        training_it = training_it+1;
        training_data(training_it,:) = train_data(i,:);
    end
end


%將小訓練集輸出到新檔案中
fid = fopen('training_data2.txt','wt');
for i=1:1:training_num
    fprintf(fid,'%d %d %d %d %d %d %d %d %d\n',training_data(i,1), training_data(i,2), training_data(i,3), training_data(i,4), training_data(i,5), training_data(i,6), training_data(i,7), training_data(i,8), training_data(i,9));
end
fclose(fid);

相關文章