一、貝葉斯定理
B事件發(fā)生后,A事件發(fā)生的概率可以如下表示:
p ( A ∣ B ) = p ( A ∩ B ) P ( B ) (1) p(A|B)=\frac{p(A\cap B)}{P(B)}\tag{1} p(A∣B)=P(B)p(A∩B)?(1)
A事件發(fā)生后,B事件發(fā)生的概率可以如下表示:
p ( B ∣ A ) = p ( A ∩ B ) P ( A ) (2) p(B|A)=\frac{p(A\cap B)}{P(A)}\tag{2} p(B∣A)=P(A)p(A∩B)?(2)
二者做比:
P ( A ∣ B ) P ( B ∣ A ) = P ( A ) P ( B ) (3) \frac{P(A|B)}{P(B|A)}=\frac{P(A)}{P(B)}\tag{3} P(B∣A)P(A∣B)?=P(B)P(A)?(3)
把 P ( B ∣ A ) P(B|A) P(B∣A) 乘到等式右邊后,我們就叨叨了如下貝葉斯定理:
P ( A ∣ B ) = P ( B ∣ A ) P ( A ) P ( B ) (4) P(A|B)=\frac{P(B|A)P(A)}{P(B)}\tag{4} P(A∣B)=P(B)P(B∣A)P(A)?(4)
二、貝葉斯分類
將貝葉斯定理的變量名稱稍作變換,我們就得到了貝葉斯公式:
P ( c ∣ x ) = P ( x ∣ c ) P ( c ) P ( x ) (5) P(c|\bm{x})=\frac{P(\bm{x}|c)P(c)}{P(\bm{x})}\tag{5} P(c∣x)=P(x)P(x∣c)P(c)?(5)
其中, P ( c ) P(c) P(c) 表示數(shù)據(jù)集中 l a b e l label label 為 c c c 類樣本的概率, x \bm{x} x 是輸入屬性, P ( x ) P(\bm{x}) P(x) 表示輸入 x \bm{x} x 發(fā)生的概率, P ( x ∣ c ) P(\bm{x}|c) P(x∣c) 是 c c c 發(fā)生條件下 x \bm{x} x 發(fā)生的概率。
我們通過公式5,來表示我們把輸入 x \bm{x} x 分為 c c c 類的概率,這就是貝葉斯分類。
進(jìn)一步理解, P ( c ) P(c) P(c)叫做先驗(yàn)概率, P ( x ∣ c ) P(x|c) P(x∣c)叫做似然概率,二者相乘,最終的結(jié)果就可以很好的表征樣本為某個(gè)類別的可能性大小。
三、樸素貝葉斯
從上面的式5可以看出,我們?nèi)绻胍A(yù)測一個(gè)輸入 x \bm{x} x的類別,我們只需要得到訓(xùn)練數(shù)據(jù)集中的 P ( c ) P(c) P(c) 和 P ( x ∣ c ) P(\bm{x}|c) P(x∣c) 就可以了, P ( x ) P(x) P(x)不需要。
因?yàn)槲覀兊念A(yù)測過程是,給出一個(gè)樣本輸入 x x x,假設(shè)這個(gè)樣本可能的類別為 C = { c ∣ c 0 , c 1 , . . . , c n } C=\{c|c_0,c_1,...,c_n\} C={c∣c0?,c1?,...,cn?};
我們根據(jù)貝葉斯公式,計(jì)算 P ( c 0 ) P(c_0) P(c0?), P ( c 1 ) P(c_1) P(c1?),……, P ( c n ) P(c_n) P(cn?) ;
最后,我們選擇一個(gè)最大的 P ( c ) P(c) P(c)作為我們最終的預(yù)測類別 c ′ c' c′,模型預(yù)測結(jié)束。
而在這個(gè)過程中,我們的輸入 x x x 是相同的,因此 P ( x ) P(\bm{x}) P(x) 也是相同的,所以我們不需要管它,就選擇分子最大的就可以了。
3.1 計(jì)算 P ( c ) P(c) P(c)
這個(gè)很好計(jì)算,我們直接統(tǒng)計(jì)一下,數(shù)據(jù)集中不同類別的數(shù)據(jù)的頻率就可以了,大數(shù)定律告訴我們,當(dāng)數(shù)據(jù)集足夠大的時(shí)候,我們可以使用頻率來逼近概率。
3.2 計(jì)算 P ( x ∣ c ) P(\bm{x}|c) P(x∣c)
這個(gè)思路也很簡單,同樣是統(tǒng)計(jì),統(tǒng)計(jì)數(shù)據(jù)集中,label屬于 c c c 的,同時(shí)輸入屬性為 x \bm{x} x 的數(shù)據(jù)的頻率,在數(shù)據(jù)量比較大的情況下,同樣使用頻率逼近概率。
但是,這里的
x
\bm{x}
x 是由不同的輸入屬性組合到一起最終合成的,它具有非常多種的情況,是組合問題,這種問題統(tǒng)計(jì)起來是會出現(xiàn)復(fù)雜度爆炸的情況的,無法在多項(xiàng)式的時(shí)間內(nèi)完成程序的運(yùn)算,換言之為一種 NP
難問題。
3.3 屬性獨(dú)立假設(shè)
為了解決這種 NP
難問題,我們采用了屬性條件獨(dú)立假設(shè),進(jìn)而就誕生了樸素貝葉斯。
樸素貝葉斯分類通過屬性獨(dú)立假設(shè),近似求解了 P ( x ∣ c ) P(\bm{x}|c) P(x∣c)這個(gè)NP難問題,而且近似的效果非常好,可以取得很棒的分類效果。
假設(shè)所有屬性為獨(dú)立分布的,我們可以得到如下式子:
P ( x ∣ c ) = ∏ i = 0 d P ( x i ∣ c ) (6) P(\bm{x}|c)=\prod_{i=0}^dP(x_i|c)\tag{6} P(x∣c)=i=0∏d?P(xi?∣c)(6)
其中d為屬性數(shù)目, x i x_i xi? 為 x \bm{x} x 在第 i i i 個(gè)屬性上的取值。
將式(6)帶入式(5)可以得到如下結(jié)果:
P ( c ∣ x ) = P ( x ∣ c ) P ( c ) P ( x ) = P ( c ) P ( x ) ∏ i = 0 d P ( x i ∣ c ) (7) P(c|\bm{x})=\frac{P(\bm{x}|c)P(c)}{P(\bm{x})}=\frac{P(c)}{P(\bm{x})}\prod_{i=0}^dP(x_i|c)\tag{7} P(c∣x)=P(x)P(x∣c)P(c)?=P(x)P(c)?i=0∏d?P(xi?∣c)(7)
這里面的 P ( x i ∣ c ) P(x_i|c) P(xi?∣c) 是很有限的,它的數(shù)量可以表示為 ∑ i = 1 n n u m A t t r i b u t e s V a l u e s ( i ) × n u m C l a s s V a l u e s \sum_{i=1}^n numAttributesValues(i)\times numClassValues ∑i=1n?numAttributesValues(i)×numClassValues。在程序設(shè)計(jì)中我們可以采用一個(gè)二維的List數(shù)組、三維double數(shù)組或者二維數(shù)組表示三維數(shù)組等多種方法來存儲這個(gè)變量。(具體可以看下面代碼,為了代碼的可讀性和簡潔性,我是采用二維List來進(jìn)行表示的)
其中
n
n
n表示輸入
x
\bm{x}
x的屬性數(shù)量,
n
u
m
A
t
t
r
i
b
u
t
e
s
V
a
l
u
e
s
(
i
)
numAttributesValues(i)
numAttributesValues(i) 表示第i個(gè)屬性的可能取值的數(shù)量,
n
u
m
C
l
a
s
s
V
a
l
u
e
s
numClassValues
numClassValues 表示 label
有多少個(gè)類別。文章來源:http://www.zghlxwxcb.cn/news/detail-543978.html
從上面也可以看出,貝葉斯分類器天然是用來處理名詞性屬性的,如果我們遇到了數(shù)值型屬性,就需要進(jìn)行一下數(shù)據(jù)離散化處理,才能采用貝葉斯進(jìn)行分類。數(shù)據(jù)離散化處理方法有很多,比如:等高分箱、等寬分享,以及基于概率分布的劃分等。文章來源地址http://www.zghlxwxcb.cn/news/detail-543978.html
四、基于weka的代碼實(shí)現(xiàn)
package weka.classifiers.myf;
import weka.classifiers.Classifier;
import weka.core.*;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
/**
* @author YFMan
* @Description 樸素貝葉斯 分類器
* @Date 2023/5/14 18:48
*/
public class myNaiveBayes extends Classifier {
// 用于存儲 樸素貝葉斯 屬性參數(shù)
protected List<Integer>[][] m_Distributions;
// 用于存儲 樸素貝葉斯 類別參數(shù)
protected List<Integer> m_ClassDistribution;
// 類別參數(shù) 的 種類數(shù)量
protected int m_NumClasses;
// 存儲訓(xùn)練數(shù)據(jù)
protected Instances m_Instances;
/*
* @Author YFMan
* @Description 訓(xùn)練分類器,初始化 屬性參數(shù) 和 類別參數(shù)
* @Date 2023/5/14 21:42
* @Param [instances 訓(xùn)練數(shù)據(jù)]
* @return void
**/
public void buildClassifier(Instances instances) throws Exception {
// 初始化訓(xùn)練數(shù)據(jù)
m_Instances = instances;
// 初始化類別參數(shù) 的 種類數(shù)量
m_NumClasses = instances.numClasses();
// 初始化 屬性參數(shù)
m_Distributions = new List[instances.numAttributes() - 1][m_NumClasses];
for(int i=0;i<instances.numAttributes() - 1;i++){
for(int j=0;j<m_NumClasses;j++){
m_Distributions[i][j] = new ArrayList<>();
}
}
// 初始化 類別參數(shù)
m_ClassDistribution = new ArrayList<>();
for(int i=0;i<m_NumClasses;i++){
m_ClassDistribution.add(0);
}
// 獲取屬性參數(shù)的枚舉類型
Enumeration attributeEnumeration = instances.enumerateAttributes();
// 遍歷屬性參數(shù)
while (attributeEnumeration.hasMoreElements()) {
// 獲取屬性參數(shù)
Attribute attribute = (Attribute) attributeEnumeration.nextElement();
// 獲取屬性參數(shù)的索引
int attributeIndex = attribute.index();
// 獲取屬性參數(shù)的值的枚舉類型
Enumeration attributeValueEnumeration = attribute.enumerateValues();
// 遍歷屬性參數(shù)的值
while (attributeValueEnumeration.hasMoreElements()) {
// 獲取屬性參數(shù)的值
String attributeValue = (String) attributeValueEnumeration.nextElement();
// 遍歷類別參數(shù)
for (int classIndex = 0; classIndex < m_NumClasses; classIndex++) {
// 初始化 屬性參數(shù) 的 某個(gè)值 的 某個(gè)類別參數(shù) 的 計(jì)數(shù)
m_Distributions[attributeIndex][classIndex].add(0);
}
}
}
// 遍歷訓(xùn)練數(shù)據(jù)
for (int instanceIndex = 0; instanceIndex < instances.numInstances(); instanceIndex++) {
// 獲取訓(xùn)練數(shù)據(jù)的實(shí)例
Instance instance = instances.instance(instanceIndex);
// 獲取訓(xùn)練數(shù)據(jù)的類別參數(shù)的值
int classValue = (int) instance.classValue();
// 遍歷屬性參數(shù)
for (int attributeIndex = 0; attributeIndex < instances.numAttributes() - 1; attributeIndex++) {
// 獲取訓(xùn)練數(shù)據(jù)的屬性參數(shù)的值
int attributeValue = (int) instance.value(attributeIndex);
// 計(jì)數(shù)
m_Distributions[attributeIndex][classValue].set(attributeValue,
m_Distributions[attributeIndex][classValue].get(attributeValue) + 1);
}
// 計(jì)數(shù)
m_ClassDistribution.set(classValue, m_ClassDistribution.get(classValue) + 1);
}
}
/*
* @Author YFMan
* @Description 根據(jù)給定的實(shí)例,預(yù)測其類別
* @Date 2023/5/14 21:43
* @Param [instance 給定的實(shí)例]
* @return double[]
**/
public double[] distributionForInstance(Instance instance)
throws Exception {
// 初始化預(yù)測概率數(shù)組
double[] predictionProbability = new double[m_NumClasses];
// 遍歷類別參數(shù)
for (int classIndex = 0; classIndex < m_NumClasses; classIndex++) {
// 初始化預(yù)測概率
double prediction = 1;
// 遍歷屬性參數(shù)
for (int attributeIndex = 0; attributeIndex < m_Instances.numAttributes() - 1; attributeIndex++) {
// 獲取屬性參數(shù)的值
int attributeValue = (int) instance.value(attributeIndex);
// 獲取 當(dāng)前屬性 可能的取值數(shù)
int attributeValueCount = m_Distributions[attributeIndex][classIndex].size();
// 計(jì)算條件概率P(x|c) (當(dāng)前屬性值在當(dāng)前類別下占的比例) (拉普拉斯平滑)
double p_x_c = (double) (m_Distributions[attributeIndex][classIndex].get(attributeValue) + 1) /
(m_ClassDistribution.get(classIndex) + attributeValueCount);
// 計(jì)算預(yù)測概率
prediction *= p_x_c;
}
// 計(jì)算先驗(yàn)概率P(c) (當(dāng)前類別占總類別的比例) (拉普拉斯平滑)
double p_c = (double) (m_ClassDistribution.get(classIndex) + 1) /
(m_Instances.numInstances() + m_NumClasses);
// 計(jì)算預(yù)測概率
predictionProbability[classIndex] = prediction * p_c;
}
// 歸一化
Utils.normalize(predictionProbability);
// 返回預(yù)測概率數(shù)組
return predictionProbability;
}
/*
* @Author YFMan
* @Description 主函數(shù)
* @Date 2023/5/14 21:54
* @Param [argv 命令行參數(shù)]
* @return void
**/
public static void main(String[] argv) {
runClassifier(new myNaiveBayes(), argv);
}
}
到了這里,關(guān)于基于weka平臺手工實(shí)現(xiàn)樸素貝葉斯分類的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!