貝葉斯分類器



核心思想

貝葉斯決策理論的核心思想,即選擇具有最高概率的決策。

背景:假定p1(x,y)表示點(x,y)屬於類別1的概率,p2(x,y)表示點(x,y)
屬於類別2的概率,那么對於一個新數據點(x,y),可以采用下面的規則來判斷它的類別:

  • 若p1(x,y)>p2(x,y),那么類別為1;
  • 若p1(x,y)<p2(x,y),那么類別為2.

理論基礎

“屬性條件獨立性假設”:對於已知類別,假定所有屬性相互獨立,換言之,假設
每個屬性獨立地對分類結果發生影響。這也是‘朴素’的來源。
另一層意思是:每個屬性同等重要。

基於屬性條件獨立性假設,貝葉斯公式可以改寫為:

\[{\rm{P}}(c|{\bf{x}}) = \frac{{P(c)P({\bf{x}}|c)}}{{p({\bf{x}})}} = \frac{{p(c)}}{{p({\bf{x}})}}\prod\limits_{i = 1}^d {P({x_i}|c)} \]

其中d為屬性數目,\(x_i\)為x在第i個屬性上的取值。

由於對所有類別來說P(x)相同,因此基於貝葉斯准則有

\[{h_{NB}}({\bf{x}}) = \mathop {\arg \max }\limits_{c \in \gamma } P(c)\prod\limits_{i = 1}^d {P({x_i}|c)} \]

朴素貝葉斯分類器的訓練過程就是基於訓練集D來估計類先驗概率p(c),並為每個屬性估計條件概率\(P(x_i|c)\).

  • 離散屬性:條件概率計算:\(p({x_i}|c) = \frac{{\left| {{D_{c,{x_i}}}} \right|}}{{|{D_c}|}}\).
    \(D_{c,x_i}\)表示\(D_c\)中在第\(i\)個屬性上取值為\(x_i\)的樣本組成的集合。

  • 連續屬性:考慮概率密度函數,假定\(p({x_i}|c) \sim {\rm N}({\mu _{c,i}},\sigma _{c,i}^2)\),其中\(\mu _{c,i},\sigma _{c,i}^2\)分別是c類樣本在第\(i\)個屬性上取值的均值和標准差,則有

\[p({x_i}|c) = \frac{1}{{\sqrt {2\pi } {\sigma _{c,i}}}}\exp ( - \frac{{{{({x_i} - {\mu _{c,i}})}^2}}}{{2\sigma _{c,i}^2}}) \]

當某個屬性值在訓練集中沒有與某個類同時出現過,將使得\(P(x_i|c)=0\),使得后續的判別出現問題。所以為了避免其它屬性攜帶的信息被訓練集中未出現的屬性值'抹去',在估計概率值時通常要進行'平滑'。

針對P(x_i|c)計算的不同,朴素貝葉斯分類器出現了不同的變體


1. 自己動手算

以決策樹中的'貸款數據表為例',對下列樣本進行預測:

Age 	Work 	House 	Loan 	Class
中年 	否 	是 	一般 	?

import pandas as pd
DATA=pd.read_excel(r'F:\Python_processing\Python_Jupyter腳本集\機器學習\loan.xlsx')
#1.首先待預測樣本不再已知樣本中,年齡是‘中年’
DATA[DATA['Age']=='中年']
#2. 計算P(c):即分別計算class為是和否的概率
Age Work House Loan Class
5 中年 一般
6 中年
7 中年
8 中年 非常好
9 中年 非常好
def getResults(dataframe):
    p_c_dict=dataframe.value_counts()
    p_c=dict([ (c_i,round(c_value/p_c_dict.values.sum(),3)) for c_i,c_value in zip(p_c_dict.index,p_c_dict.values)])
    return p_c 
#特征

columns=[i for i in DATA.columns[:-1]]
data1=DATA[DATA['Class']=='是'][columns]
data2=DATA[DATA['Class']=='否'][columns]
print('class # 是')
for i in columns:
    #划分數據
    temp_data=data1[i]
    #開始統計結果
    print(i,getResults(temp_data))
    
print(''.center(50,"="))
    
print('class # 否')
for i in columns:
    #划分數據
    temp_data=data2[i]
    #開始統計結果
    print(i,getResults(temp_data))

        

輸出結果:
class # 是
Age {'老年': 0.444, '中年': 0.333, '青年': 0.222}
Work {'是': 0.556, '否': 0.444}
House {'是': 0.667, '否': 0.333}
Loan {'好': 0.444, '非常好': 0.444, '一般': 0.111}
==================================================
class # 否
Age {'青年': 0.5, '中年': 0.333, '老年': 0.167}
Work {'否': 1.0}
House {'否': 1.0}
Loan {'一般': 0.667, '好': 0.333}

p_c=getResults(DATA['Class'])
p_c

{'是': 0.6, '否': 0.4}

  • class:是

\[p(class=是)*p(中年|class=是)*p(Work=否|class=是)*p(House=是|class=是)*p(loan=一般|class=是) =0.6 * 0.333* 0.444*0.667*0.111=0.006567911114400001\]

  • class:否

\[p(class=否)*p(中年|class=否)*p(Work=否|class=否)*p(House=是|class=否)*p(loan=一般|class=否) =0.4 * 0.333* 1.0*0*0.667=0\]

所以預測該person的貸款類型為 “是”.

(該樣本是基於person 9修改loan后得到,根據決策樹節的分支可知,loan在眾多屬性特征重要性中屬於最后,所以上述預測結果可以接受!!)

關於連續變量的案例,見周志華《機器學習》。


2. 調用Sklearn庫

Sklearn.naive_bayes官方幫助文檔

高斯朴素貝葉斯

假設\(p(x_i|c)或p(x_i|y)\)服從高斯分布。

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import GaussianNB

X,y=load_iris(return_X_y=True)
X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.5,random_state=0)
gnb=GaussianNB().fit(X_train,y_train)
y_pred=gnb.predict(X_test)
print("Number of mislabeled points out of a total %d points:%d"
     %(X_test.shape[0],(y_test!=y_pred).sum()))

Number of mislabeled points out of a total 75 points:4

from sklearn.metrics import confusion_matrix

confusion_matrix(y_test,y_pred)

array([[21, 0, 0],
[ 0, 30, 0],
[ 0, 4, 20]], dtype=int64)

多項式朴素貝葉斯

MultinomialNB實現了對多個分布數據的朴素貝葉斯算法,是文本分類中使用的兩個經典朴素Bayes變體之一(其中數據通常表示為字向量計數,盡管TF-ID向量在實踐中也很好地工作)。

\(p(x_i|c)或p(x_i|y)\)采用平滑處理:$$p({x_i}|c) = \frac{{|{D_{ci}}| + \alpha }}{{|{D_c}| + \alpha *n}}$$

\(n\)表示特征數量;\(\alpha>=0\);。

from sklearn.naive_bayes import MultinomialNB
import numpy as np
rng = np.random.RandomState(1)
X = rng.randint(5, size=(6, 100))
y = np.array([1, 2, 3, 4, 5, 6])
from sklearn.naive_bayes import MultinomialNB
clf = MultinomialNB()
clf.fit(X, y)
print(clf.predict(X[2:3]))

[3]

補碼朴素貝葉斯

補碼朴素貝葉斯(ComplementNB,cNB)是標准多項式朴素貝葉斯(MNB)算法的一種自適應算法,特別適用於不平衡的數據集。
具體內容見論文:Tackling the Poor Assumptions of Naive Bayes Text Classifiers

論文提出(多項式)朴素貝葉斯自身的系統錯誤以及在文本分類上的缺陷:

  • 在有偏數據集上,權重的決策邊界偏向樣本數較多的類。
  • 朴素貝葉斯對不符合獨立性假設的(特征所在的)類影響較大。

多項式朴素貝葉斯
假定有固定的類\(c \in \{ 1,2,...,m\}\),每一個對應預定的多項式參數集合,類\(c\)對應的參數為:
\({{\bf{\theta }}_c} = \{ {\theta _{c1}},{\theta _{c2}},...,{\theta _{cn}}\}\),其中\(n\)代表詞袋大小,
\(\sum\nolimits_i {{\theta _{ci}} = 1,} {\theta _{ci}}\)表示單詞\(i\)在類\(c\)中出現的概率。文本分類中文檔的似然函數可以
表示為$$p(d|{{\bf{\theta }}_c}) = \frac{{(\sum\nolimits_i {{f_i}} )!}}{{\prod\limits_i {{f_i}} }}\prod\limits_i {{{({\theta _{ci}})}^{{f_i}}}} $$
\(f_i\)表示文檔\(d\)中單詞\(i\)出現的次數。
多項式朴素貝葉斯分布的目標優化函數為:

\[\begin{array}{c} l(d) = \mathop {\arg \max }\limits_c [\log p({{\bf{\theta }}_c}) + \sum\limits_i {{f_i}\log {\theta _{ci}}} ] \\ = \mathop {\arg \max }\limits_c [{b_c} + \sum\limits_i {{f_i}{w_{ci}}} ] \\ \end{array}\]

\(b_c\)是閾值項(中括號里面第一項是個常數),\(w_{ci}\)是單詞\(i\)在類\(c\)中的權重。
這些值是決策邊界的自然參數。 對於二進制分類,這尤其容易看到,其中通過將正類參數和負類參數之間的差設置為零來定義邊界,

\[({b_ + } - {b_ - }) + \sum\limits_i {{f_i}({w_{ + i}} - {w_{ - i}}) = 0} \]

基於多項式分布於狄利克雷分布共軛,可以估計出參數\(\theta_{ci}\),

\[{\mathop \theta^\^_{ci}} = \frac{{{N_{ci}} + {\alpha _i}}}{{{N_c} + \alpha }} \]

從而可以得到多項式NB的優化條件:

\[{l_{MNB}}(d) = \mathop {\arg \max }\limits_c [\log \mathop {p({\theta _c})}\limits^\^ + \sum\limits_i {{f_i}\log (\frac{{{N_{ci}} + {\alpha _i}}}{{{N_c} + \alpha }})} ] \]

\(\alpha = \sum\limits_i {{\alpha _i}} ,\alpha_i\)表示一種先驗
為了簡單,使用均勻分布作為先驗,多項式NB的決策邊界轉為為對下列式子的估計:

\[\mathop {{w_{ci}}}\limits^\^ = \log \mathop {{\theta _{ci}}}\limits^\^ \]

Complement NB
針對在有偏數據集上,權重的決策邊界偏向樣本數較多的類的問題。論文
提出了Complement Naive Bayes(CNB),與MNB不同的是,CNB的估計為:

\[\mathop {{\theta _{^ \~ ci}}}\limits^\^ = \frac{{{N_{_{^ \~ ci}}} + {\alpha _i}}}{{{N_{^ \~ c}} + \alpha }} \]

CNB的優化目標為:

\[{l_{CNB}}(d) = \mathop {\arg \max }\limits_c [\log p({{\bf{\theta }}_c}) - \sum\limits_i {{f_i}\frac{{{N_{^ \~ ci}} + {\alpha _i}}}{{{N_{^ \~ c}} + \alpha }}} ] \]

\({N_{^ \~ c}}\)表示除過\(c\)以外的類出現的次數。

注:
負號表示我們要分配給與complement參數估計值不匹配的c類文檔的事實。

這個主要應用在文本分類上,論文提出了具體的處理方案:

伯努利朴素貝葉斯

BernoulliNB實現了根據多元Bernoulli分布分布的數據的朴素貝葉斯訓練和分類算法,即可能有多個特征,但每一個特征都被假定為一個二元值(Bernoulli,boole)變量。因此,這個類需要將樣本表示為二進制值的特征向量;如果傳遞任何其他類型的數據,則BernoulliNB實例可以對其輸入進行二進制化(取決於binarize參數)。

Bernoulli朴素貝葉斯的決策規則是基於

\[p({x_i}|y) = p(i|y){x_i} + (1 - p(i|y))(1 - {x_i}) \]

關於\(p(i|y)\)的理解:
它不同於多項式NB的規則,因為它明確地懲罰一個特征i的不出現,它是y類的指示,其中多項變量會簡單地忽略一個未發生的特征。

它與多項NB規則不同之處在於它明確地懲罰了一個特征的不出現。這是班級的指標,其中多項式變體會忽略一個未發生的特性。

在文本分類的情況下,可以使用單詞出現向量(而不是字數向量)來訓練和使用該分類器。BernoulliNB在某些數據集上,特別是那些文檔較短的數據集中,性能可能會更好。如果時間允許,最好對這兩種模式進行評估。

Categorical Naive Bayes(類朴素貝葉斯)

CategoricalNB對分類分布的數據實施分類朴素貝葉斯算法。 它假定由索引描述的每個特征都有其自己的分類分布。

對於訓練集中的每個特征 \(X\),CategoricalNB估計以類y為條件的X的每個特征i的分類分布。 樣本的索引集定義為\(J={1,...,m}\)\(m\)作為樣本數。

給定c類的特征i中t類(屬性值)的概率估計為:$$p({x_i}{\rm{ = }}t|y = c;\alpha ) = \frac{{{N_{tic}} + \alpha }}{{{N_c} + \alpha {n_i}}}$$

\(N_{tic} = |\{j \in J \mid x_{ij} = t, y_j = c\}|\)是屬性值\(t\)出現特征\(x_i\),樣本,屬於屬於'c'的次數;

\(N_{c} = |\{ j \in J\mid y_j = c\}|\) 屬於類c的樣本數,\(n_i\)是可用的特征數。

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import CategoricalNB

X,y=load_iris(return_X_y=True)
X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.5,random_state=0)
cat=CategoricalNB().fit(X_train,y_train)
y_pred=cat.predict(X_test)
print("Number of mislabeled points out of a total %d points:%d"
     %(X_test.shape[0],(y_test!=y_pred).sum()))

Number of mislabeled points out of a total 75 points:7

#列名
column=DATA.columns
##House后面有空格
DATA.columns=[i.strip() for i in column]
column=DATA.columns
column

Index(['Age', 'Work', 'House', 'Loan', 'Class'], dtype='object')

from sklearn.preprocessing import OrdinalEncoder
ord_encoder=OrdinalEncoder().fit(DATA[column[:-1]])
ord_encoder2=OrdinalEncoder().fit(DATA[['Class']])
ord_encoder.categories_

[array(['中年', '老年', '青年'], dtype=object),
array(['否', '是'], dtype=object),
array(['否', '是'], dtype=object),
array(['一般', '好', '非常好'], dtype=object)]

X=pd.DataFrame(ord_encoder.transform(DATA[column[:-1]]),columns=column[:-1])
y=pd.DataFrame(ord_encoder2.transform(DATA[['Class']]),columns=["Class"])
X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.5,random_state=0)
cat2=CategoricalNB().fit(X_train,y_train)
y_pred=cat2.predict(X_test)
y_pred

array([0., 0., 1., 1., 0., 0., 1., 1.])

mat=confusion_matrix(y_test,y_pred)
mat

array([[4, 0],
[0, 4]], dtype=int64)

print("准確率:%3.2f"%(
    (np.eye(2)*mat).sum()/mat.sum()*100))

准確率:100.00

#對上面動手算的結果進行驗證
raw_test=['中年','否','是','一般']
test=ord_encoder.transform([raw_test])
cat2.predict(test)

array([1.])

#對上面的預測結果進行還原
a=ord_encoder2.inverse_transform([cat2.predict(test)])
print("該樣本%s的class #%s"%(raw_test,a.flatten().tolist()[0]))

該樣本['中年', '否', '是', '一般']的class #是


參考文獻:

  1. 周志華《機器學習》
  2. 李航《統計學習方法》
  3. 《機器學習實戰》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM