Python機器學習筆記:樸素貝葉斯演算法

戰爭熱誠發表於2019-05-18

  樸素貝葉斯是經典的機器學習演算法之一,也是為數不多的基於概率論的分類演算法。對於大多數的分類演算法,在所有的機器學習分類演算法中,樸素貝葉斯和其他絕大多數的分類演算法都不同。比如決策樹,KNN,邏輯迴歸,支援向量機等,他們都是判別方法,也就是直接學習出特徵輸出Y和特徵X之間的關係,要麼是決策函式,要麼是條件分佈。但是樸素貝葉斯卻是生成方法,該演算法原理簡單,也易於實現。

1,基本概念

  樸素貝葉斯:貝葉斯分類時一類分類演算法的總稱,這類演算法均以貝葉斯定理為基礎,故統稱為貝葉斯分類。而樸素貝葉斯分類時貝葉斯分類中最簡單,也是最常見的一種分類方法。

  貝葉斯公式

(X:特徵向量, Y:類別)

  先驗概率P(X):先驗概率是指根據以往經驗和分析得到的概率。

  後驗概率P(Y|X):事情已經發生,要求這件事情發生的原因是由某個因素引起的可能性的大小,後驗分佈P(Y|X)表示事件X已經發生的前提下,事件Y發生的概率,叫做事件X發生下事件Y的條件概率。

  後驗概率P(X|Y):在已知Y發生後X的條件概率,也由於知道Y的取值而被稱為X的後驗概率。

  樸素:樸素貝葉斯演算法是假設各個特徵之間相互獨立,也是樸素這詞的意思那麼貝葉斯公式中的P(X|Y)可寫成:

  樸素貝葉斯公式

 

2,貝葉斯演算法簡介

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

  樸素貝葉斯會單獨考量每一維獨立特徵被分類的條件概率,進而綜合這些概率並對其所在的特徵向量做出分類預測。因此,樸素貝葉斯的基本資料假設是:各個維度上的特徵被分類的條件概率之間是相互獨立的。它經常被用於文字分類中,包括網際網路新聞的分類,垃圾郵件的篩選。

  樸素貝葉斯分類時一種十分簡單的分類演算法,叫他樸素貝葉斯分類時因為這種方法的思想真的很樸素,樸素貝葉斯的思想基礎是這樣的:對於給出的待分類項,求解在此項出現的條件下各個類別出現的概率,哪個最大,即認為此待分類項屬於哪個類別。

3,樸素貝葉斯的推導過程

  貝葉斯學派很古老,但是從誕生到一百年前一直不是主流。主流是頻率學派。頻率學派的權威皮爾遜和費歇爾都對貝葉斯學派不屑一顧,但是貝葉斯學派硬是憑藉著在現代特定領域的出色應用表現為自己贏得了半壁江山。

   貝葉斯學派的思想可以概括為先驗概率 + 資料 = 後驗概率。也就是說我們在實際問題中需要得到的後驗概率,可以通過先驗概率和資料一起綜合得到。資料大家好理解,被頻率學派攻擊的是先驗概率,一般來說先驗概率就是我們對於資料所在領域的歷史經驗,但是這個經驗常常難以量化或者模型化,於是貝葉斯學派大膽的假設先驗分佈的模型,比如正態分佈,beta分佈等。這個假設一般沒有特定的依據,因此一直被頻率學派認為很荒謬。雖然難以從嚴密的數學邏輯推出貝葉斯學派的邏輯,但是在很多實際應用中,貝葉斯理論很好用,比如垃圾郵件分類,文字分類。

  條件概率就是事件X在另外一個事件Y已經發生條件下的概率。條件概率表示為P(X|Y)。

  我們先看看條件獨立公式,如果X和Y相互獨立,則由:

  我們接著看條件概率公式:

  或者說:

  接著看看全概公式:

  從上面的公式很容易得出貝葉斯公式:

3.1 完整的推導過程

  這裡我們從條件概率的定義推匯出貝葉斯定理,其實上面已經推導了,但是這個更簡潔一些,所以使用一個叫聯合概率的概念。

  聯合概率:表示兩件事共同發生(數學概念上的交集)的概念,A和B的聯合概率表示為

 P(AnB)。

  根據條件概率的定義,在事件B發生的條件下事件A發生的概率為:

  同樣地,在事件A發生的條件下事件B發生的概率為:

  結合這兩個方程式,我們可以得到:

  這個引理有時稱為概率乘法規則。上式兩邊同時除以P(A),若P(A)是非零的,我們可以得到貝葉斯定理:

 

   解釋:事件X在事件Y發生的條件下的概率,與事件Y在事件X發生的條件下的概率是不一樣的;然而這兩者是有確定關係的,貝葉斯定理就是這種關係的陳述。

  貝葉斯公式的用途在於通過已知三個概率來推測第四個概率。它的內容是:在 X 出現的前提下, Y 出現的概率等於 Y 出現的前提下 X 出現的概率乘以 Y 出現的概率再除以 X 出現的概率。通過聯絡X和Y,計算從一個事件發生的情況下另一事件發生的概率,即從結果上追溯到源頭。

  通俗地講就是當你不能確定某一個事件發生的概率時,你可以依靠與該事件本質屬性相關的時間發生的概率去推測該事件發生的概率。用數學語言表達就是:支援某項屬性的事件發生的愈多,則該事件發生的可能性就愈大。這個推理過程有時候也叫貝葉斯推理。

 

4,樸素貝葉斯的模型

  從統計學知識回到我們的資料分析。假設我們的分類模型樣本是:

  即我們有 m 個樣本,每個樣本有 n 個特徵,特徵輸出有 K 個類別,定義為

  從樣本我們可以學習到樸素貝葉斯的先驗分佈,接著學習到條件概率分佈,然後我們就可以用貝葉斯公式得到X 和 Y 的聯合分佈 P(X,Y)了。聯合分佈P(X,Y)定義為:

  從上面的式子就可以看出比較容易通過最大似然法求出,得到的就是類別在訓練集裡面出現的頻數。但是很難求出,這是一個超級複雜的有n個維度的條件分佈。樸素貝葉斯模型在這裡做一個大膽的假設,即 X 的n個維度之間相互獨立,這樣就可以得出:

  從上式可以看出,這個很難的條件分佈大大的簡化了,但是這也可能帶來預測的不準確性。你會說我的特徵之間非常不獨立怎麼辦?如果真是非常不獨立的話,那就儘量不要使用樸素貝葉斯模型了,考慮使用其他的分類方法比較好。但是一般情況下,樣本的特徵之間獨立這個條件的確是弱成立的,尤其是資料量非常大的時候。雖然我們犧牲了準確性,但是得到的好處是模型的條件分佈的計算大大簡化了,這就是貝葉斯模型的選擇。

  最後回到我們要解決的問題,我們的問題是給定測試集的一個新樣本特徵,我們如何判斷它屬於哪個型別?

  既然是貝葉斯模型,當然是後驗概率最大化來判斷分類了。我們只要計算出所有的K個條件概率,然後找出最大的條件概率對應的類別,這就是樸素貝葉斯的預測了。

 

5,三種常見的貝葉斯模型

5.1,多項式模型(MultinomialNB)

  多項式樸素貝葉斯常用語文字分類,特徵是單詞,值時單詞出現的次數。

  多項式模型在計算先驗概率P(Yk)和和條件概率P(Xi|Yk)時,會做出一些平滑處理,具體公式為:

  • N:樣本數
  • NYk:類別為Yk的樣本數
  • K:總的類別個數
  • α:平滑值

  • NYk,Xi:類別為Yk,且特徵為X1的樣本數
  • n:特徵X1可以選擇的數量

5.2,高斯模型(GaussianNB)

  當特徵是連續變數的時候,假設特徵分佈為正態分佈,根據樣本算出均值和方差,再求得概率。

  其中Ck為的第K類類別。Y的需要求出μk 和σk2 ,μk 在樣本類別Ck中,所有 Xj 的平均值。σk2 為在樣本類別 Ck 中,所有 Xj 的方差。

  GaussianNB類的主要引數僅有一個,即先驗概率priors,對應Y的各個類別的先驗概率 P(Y=Ck)。這個值預設不給出,如果不給出此時P(Y=Ck) = mk/m。其中m為訓練集樣本總數量,mk為輸出為第k類別的訓練集樣本數。如果給出的話就以priors為準。

  在使用GaussianNB 的 fit方法擬合資料後,我們可以進行預測。此時預測有三種方法,包括predict,predict_log_proba 和 predict_proba。

  predict方法就是我們最常用的預測方法,直接給出測試集的預測類別輸出。

  predict_proba則不同,它會給出測試集樣本在各個類別上預測的概率。容易理解,predict_proba預測出的各個類別概率裡最大值對應的類別,也就是predict方法得到類別。

  predict_log_proba 和 predict_proba類似,它會給出測試集樣本在各個類別上預測的概率的一個對數轉化。轉化後 predict_log_proba 預測出的各個類別對數概率裡的最大值對應的類別,也就是 predict 方法得到類別。

>>> from sklearn import datasets
>>> iris = datasets.load_iris()
>>> from sklearn.naive_bayes import GaussianNB
>>> gnb = GaussianNB()
>>> y_pred = gnb.fit(iris.data, iris.target).predict(iris.data)
>>> print("Number of mislabeled points out of a total %d points : %d"
...       % (iris.data.shape[0],(iris.target != y_pred).sum()))
Number of mislabeled points out of a total 150 points : 6

  

5.3,伯努利模型(BernoulliNB)

  伯努利模型適用於離散特徵的情況,伯努利模型中每個特徵的取值只能是1和0。

   此時 l 只有兩種取值。Xjl只能取值0或者1。

  BernoulliNB一共有四個引數,其中三個引數的名字和意義和MultinomialNB完全相同。唯一增加的一個引數是binarize。這個引數主要是用來幫BernoulliNB處理二項分佈的,可以是數值或者不輸入。如果不輸入,則BernoulliNB認為每個資料特徵已經是二元的。否則的話,小於binarize的會歸為一類,大於 binarize的會歸為另外一類。

  在使用BernoulliNB 的fit 或者 partial_fit 方法擬合資料後,我們可以進行預測,此時預測方法有三種。包括predict,predict_log_proba和predict_proba。由於方法和GaussianNB完全一樣,這裡就不累述了。

6,演算法流程

  我們假設訓練集為m個樣本n個維度,如下:

  共有K個特徵輸出類別,分別為C1,C2,...Ck,每個特徵輸出類別的樣本個數為m1,m2,...mk,在第k 個類別中,如果是離散特徵,則特徵Xj各個類別取值為mjl。其中l取值為1,2,...Sj,Sj為特徵j不同的取值數。

  輸出為例項X(test)的分類。

6.1,準備工作階段

  此階段是為樸素貝葉斯分類做必要的準備,主要工作是根據具體情況確定特徵屬性,並對每個特徵屬性進行適當劃分,然後由人工對一部分待分類項進行分類,形成訓練樣本集合。這一階段的輸入是所有待分類資料,輸出是特徵屬性和訓練樣本。這一階段是整個樸素貝葉斯分類中唯一需要人工完成的階段,其質量對整個過程將有重要影響,分類器的質量很大程度上由特徵屬性,特徵屬性劃分及訓練樣本質量決定。

  1,如果沒有Y的先驗概率,則計算Y的K個先驗概率:,否則為輸入的先驗概率。

  2,分別計算第K個類別的第 j 維特徵的第 l 個取值條件概率:

    a) 如果是離散值:

    λ 可以取值為1,或者其他大於0 的數字。

    b)如果是稀疏二項離散值:

    此時 l 只有兩種取值。

    c)如果是連續值不需要計算各個 l 的取值概率,直接求正態分佈的引數:

  需要求出μk 和σk2 ,μk 在樣本類別Ck中,所有 Xj 的平均值。σk2 為在樣本類別 Ck 中,所有 Xj 的方差。

  3,對於例項 X(test),分別計算:

  4,確定例項 X(test) 的分類Cresult

  從上面的計算可以看出,沒有複雜的求導和矩陣運算,因此效率很高。

6.2,分類器訓練階段

  這個階段的認為就是生成分類器,主要工作是計算每個類別在訓練樣本中的出現頻率及每個特徵屬性劃分對每個類別的條件概率估計,並將結果記錄。其輸入時特徵屬性和訓練樣本,輸出是分類器。這一階段是機械性階段,根據前面討論的公式可以由程式自動計算完成。

6.3,應用階段

  這一階段的任務是使用分類器對待分類項進行分類,其輸入時分類器和待分類項,輸出是待分類項和類別的對映關係。這一階段也是機械性階段,由程式完成。

 

7,樸素貝葉斯演算法優缺點小結

7.1  優點

1,樸素貝葉斯模型發源於古典數學理論,有穩定的分類效率

2,對小規模的資料表現很好,能處理多分類任務,適合增量式訓練,尤其是資料量超出記憶體時,我們可以一批批的去增量訓練

3,對缺失資料不太敏感,演算法也比較簡單,常用於文字分類。

7.2  缺點

 1,理論上,樸素貝葉斯模型與其他分類方法相比具有最小的誤差率。但是實際上並非總是如此,這是因為樸素貝葉斯模型給定輸出類別的情況下,假設屬性之間相互獨立,這個假設在實際應用中往往是不成立的,在屬性個數比較多或者屬性之間相關性較大時,分類效果不好。而在屬性相關性較小的時,樸素貝葉斯效能最為良好。對於這一點,有半樸素貝葉斯之類的演算法通過考慮部分關聯性適度改進。

2,需要知道先驗概率,且先驗概率很多時候取決於假設,假設的模型可以有很多種,因此在某些時候會由於假設的先驗模型的原因導致預測效果不佳。

3,由於我們是通過先驗和資料來決定後驗的概率從而決定分類,所以分類決策存在一定的錯誤率。

4,對輸入資料的表達形式很敏感。

 

 

Sklearn樸素貝葉斯類庫使用小結

  官網地址:請點選我

  樸素貝葉斯是一類比較簡單的演算法,scikit-learn中樸素貝葉斯類庫的使用也比較簡單。相對於決策樹,KNN之類的演算法,樸素貝葉斯需要關注的引數是比較少的,這樣也比較容易掌握。

  在scikit-learn中,提供了三種樸素貝葉斯分類演算法:GaussianNB(高斯分佈的樸素貝葉斯),MultinomailNB(先驗為多項式分佈的樸素貝葉斯),BernoulliNB(先驗為伯努利分佈的樸素貝葉斯)。

  這三個類適用的分類場景各不相同,一般來說,如果樣本特徵的分佈大部分是連續值,適用GaussianNB會比較好。如果樣本特徵的分佈大部分是多元離散值,使用MultinomialNB比較合適。而如果樣本特徵是二元離散值或者很稀疏的多元離散值,應該使用BernoulliNB。

1,高斯樸素貝葉斯

sklearn.naive_bayes.GaussianNB(priors=None)

1.1 利用GaussianNB建立簡單模型

import numpy as np
from sklearn.naive_bayes import GaussianNB
X = np.array([[-1, -1], [-2, -2], [-3, -3], [-4, -4], [1, 1], [2, 2], [3, 3]])
y = np.array([1, 1, 1, 1, 2, 2, 2])
clf = GaussianNB()
re = clf.fit(X, y)
print(re)
# GaussianNB(priors=None, var_smoothing=1e-09)

  

1.2  經過訓練集訓練後,觀察各個屬性值

re1 = clf.priors
# print(re1)  #None

# 設定priors引數值
re2 = clf.set_params(priors=[0.625, 0.375])
# print(re2)
# GaussianNB(priors=[0.625, 0.375], var_smoothing=1e-09)

# 返回各類標記對應先驗概率組成的列表
re3 = clf.priors
# print(re3)
# [0.625, 0.375]

  

1.3  priors屬性:獲取各個類標記對應的先驗概率

re4 = clf.class_prior_
# print(re4)
# [0.57142857 0.42857143]

re5 = type(clf.class_prior_)
# print(re5)
# <class 'numpy.ndarray'>

  

1.4 class_prior_屬性:同priors一樣,都是獲取各個類標記對應的先驗概率,區別在於priors屬性返回列表,class_prior_返回的是陣列

re6 = clf.class_count_
# print(re6)
# [4. 3.]

  

1.5  class_count_屬性:獲取各類標記對應的訓練樣本數

re6 = clf.class_count_
# print(re6)
# [4. 3.]

  

1.6  theta_屬性:獲取各個類標記在各個特徵上的均值

re7 = clf.theta_
# print(re7)
# [[-2.5 -2.5]
#  [ 2.   2. ]]

 

1.7  sigma_屬性:獲取各個類標記在各個特徵上的方差

re8 = clf.sigma_
# print(re8)
# [[1.25000001 1.25000001]
#  [0.66666667 0.66666667]]

  

1.8 方法

  • get_params(deep=True):返回priors與其引數值組成字典
re9 = clf.get_params(deep=True)
# print(re9)
# {'priors': [0.625, 0.375], 'var_smoothing': 1e-09}

re10 = clf.get_params()
# print(re10)
# {'priors': [0.625, 0.375], 'var_smoothing': 1e-09}
  • set_params(**params):設定估計器priors引數
re11 = clf.set_params(priors=[0.625, 0.375])
# print(re11)
# GaussianNB(priors=[0.625, 0.375], var_smoothing=1e-09)
  • fit(X, sample_weight=None):訓練樣本,X表示特徵向量,y類標記,sample_weight表示各樣本權重陣列  
In [12]: clf.fit(X,y,np.array([0.05,0.05,0.1,0.1,0.1,0.2,0.2,0.2]))#設定樣本不同的權重
Out[12]: GaussianNB(priors=[0.625, 0.375])
 
In [13]: clf.theta_
Out[13]:
array([[-3.375, -3.375],
       [ 2.   ,  2.   ]])
 
In [14]: clf.sigma_
Out[14]:
array([[ 1.73437501,  1.73437501],
       [ 0.66666667,  0.66666667]])
  • partial_fit(X, y, classes=None, sample_weight=None):增量式訓練,當訓練資料集資料量非常大,不能一次性全部載入記憶體時,可以將資料集劃分若干份,重複呼叫partial_fit線上學習模型引數,在第一次呼叫partial_fit函式時,必須指定classes引數,在隨後的的呼叫可以忽略。
In [18]: import numpy as np
    ...: from sklearn.naive_bayes import GaussianNB
    ...: X = np.array([[-1, -1], [-2, -2], [-3, -3],[-4,-4],[-5,-5], [1, 1], [2
    ...: ,  2], [3, 3]])
    ...: y = np.array([1, 1, 1,1,1, 2, 2, 2])
    ...: clf = GaussianNB()#預設priors=None
    ...: clf.partial_fit(X,y,classes=[1,2],sample_weight=np.array([0.05,0.05,0.
    ...: 1,0.1,0.1,0.2,0.2,0.2]))
    ...:
Out[18]: GaussianNB(priors=None)
 
In [19]: clf.class_prior_
Out[19]: array([ 0.4,  0.6])
  • predict(X):直接輸出測試集預測的類標記
In [20]: clf.predict([[-6,-6],[4,5]])
Out[20]: array([1, 2])
  • predict_proba(X):輸出測試樣本在各個類標記預測概率值
In [21]: clf.predict_proba([[-6,-6],[4,5]])
Out[21]:
array([[  1.00000000e+00,   4.21207358e-40],
       [  1.12585521e-12,   1.00000000e+00]])
  • predict_log_proba(X):輸出測試樣本在各個類標記上預測概率值對應對數值
In [22]: clf.predict_log_proba([[-6,-6],[4,5]])
Out[22]:
array([[  0.00000000e+00,  -9.06654487e+01],
       [ -2.75124782e+01,  -1.12621024e-12]])
  • score(X, y, sample_weight=None):返回測試樣本對映到指定類標記上的得分(準確率)
In [23]: clf.score([[-6,-6],[-4,-2],[-3,-4],[4,5]],[1,1,2,2])
Out[23]: 0.75
 
In [24]: clf.score([[-6,-6],[-4,-2],[-3,-4],[4,5]],[1,1,2,2],sample_weight=[0.3
    ...: ,0.2,0.4,0.1])
Out[24]: 0.59999999999999998

  

2,多項式樸素貝葉斯

  主要用於離散特徵分類,例如文字分類單詞統計,以出現的次數作為特徵值

sklearn.naive_bayes.MultinomialNB(alpha=1.0, fit_prior=True, class_prior=None)

  引數說明:

alpha:浮點型,可選項,預設1.0,新增拉普拉修/Lidstone平滑引數

fit_prior:布林型,可選項,預設True,表示是否學習先驗概率,引數為
False表示所有類標記具有相同的先驗概率

class_prior:類似陣列,陣列大小為(n_classes,),預設None,類先驗概率

  

2.1 利用MultinomialNB建立簡單模型

In [2]: import numpy as np
   ...: from sklearn.naive_bayes import MultinomialNB
   ...: X = np.array([[1,2,3,4],[1,3,4,4],[2,4,5,5],[2,5,6,5],[3,4,5,6],[3,5,6,
   ...: 6]])
   ...: y = np.array([1,1,4,2,3,3])
   ...: clf = MultinomialNB(alpha=2.0)
   ...: clf.fit(X,y)
   ...:
Out[2]: MultinomialNB(alpha=2.0, class_prior=None, fit_prior=True)

2.2 經過訓練後,觀察各個屬性值

  • class_log_prior_:各類標記的平滑先驗概率對數值,其取值會受fit_prior和class_prior引數的影響

若指定了class_prior引數,不管fit_prior為True或False,class_log_prior_取值是class_prior轉換成log後的結果

In [4]: import numpy as np
   ...: from sklearn.naive_bayes import MultinomialNB
   ...: X = np.array([[1,2,3,4],[1,3,4,4],[2,4,5,5],[2,5,6,5],[3,4,5,6],[3,5,6,
   ...: 6]])
   ...: y = np.array([1,1,4,2,3,3])
   ...: clf = MultinomialNB(alpha=2.0,fit_prior=True,class_prior=[0.3,0.1,0.3,0
   ...: .2])
   ...: clf.fit(X,y)
   ...: print(clf.class_log_prior_)
   ...: print(np.log(0.3),np.log(0.1),np.log(0.3),np.log(0.2))
   ...: clf1 = MultinomialNB(alpha=2.0,fit_prior=False,class_prior=[0.3,0.1,0.3
   ...: ,0.2])
   ...: clf1.fit(X,y)
   ...: print(clf1.class_log_prior_)
   ...:
[-1.2039728  -2.30258509 -1.2039728  -1.60943791]
-1.20397280433 -2.30258509299 -1.20397280433 -1.60943791243
[-1.2039728  -2.30258509 -1.2039728  -1.60943791]

  

若fit_prior引數為False,class_prior=None,則各類標記的先驗概率相同等於類標記總個數N分之一

In [5]: import numpy as np
   ...: from sklearn.naive_bayes import MultinomialNB
   ...: X = np.array([[1,2,3,4],[1,3,4,4],[2,4,5,5],[2,5,6,5],[3,4,5,6],[3,5,6,
   ...: 6]])
   ...: y = np.array([1,1,4,2,3,3])
   ...: clf = MultinomialNB(alpha=2.0,fit_prior=False)
   ...: clf.fit(X,y)
   ...: print(clf.class_log_prior_)
   ...: print(np.log(1/4))
   ...:
[-1.38629436 -1.38629436 -1.38629436 -1.38629436]
-1.38629436112

  

若fit_prior引數為True,class_prior=None,則各類標記的先驗概率相同等於各類標記個數處以各類標記個數之和

In [6]: import numpy as np
   ...: from sklearn.naive_bayes import MultinomialNB
   ...: X = np.array([[1,2,3,4],[1,3,4,4],[2,4,5,5],[2,5,6,5],[3,4,5,6],[3,5,6,
   ...: 6]])
   ...: y = np.array([1,1,4,2,3,3])
   ...: clf = MultinomialNB(alpha=2.0,fit_prior=True)
   ...: clf.fit(X,y)
   ...: print(clf.class_log_prior_)#按類標記1、2、3、4的順序輸出
   ...: print(np.log(2/6),np.log(1/6),np.log(2/6),np.log(1/6))
   ...:
[-1.09861229 -1.79175947 -1.09861229 -1.79175947]
-1.09861228867 -1.79175946923 -1.09861228867 -1.79175946923

  

  • intercept_:將多項式樸素貝葉斯解釋的class_log_prior_對映為線性模型,其值和class_log_propr相同
In [7]: clf.class_log_prior_
Out[7]: array([-1.09861229, -1.79175947, -1.09861229, -1.79175947])
 
In [8]: clf.intercept_
Out[8]: array([-1.09861229, -1.79175947, -1.09861229, -1.79175947])

  

  • feature_log_prob_:指定類的各特徵概率(條件概率)對數值,返回形狀為(n_classes, n_features)陣列
In [9]: clf.feature_log_prob_
Out[9]:
array([[-2.01490302, -1.45528723, -1.2039728 , -1.09861229],
       [-1.87180218, -1.31218639, -1.178655  , -1.31218639],
       [-1.74919985, -1.43074612, -1.26369204, -1.18958407],
       [-1.79175947, -1.38629436, -1.23214368, -1.23214368]])

  

特徵條件概率計算過程,以類為1各個特徵對應的條件概率為例

In [9]: clf.feature_log_prob_
Out[9]:
array([[-2.01490302, -1.45528723, -1.2039728 , -1.09861229],
       [-1.87180218, -1.31218639, -1.178655  , -1.31218639],
       [-1.74919985, -1.43074612, -1.26369204, -1.18958407],
       [-1.79175947, -1.38629436, -1.23214368, -1.23214368]])
 
In [10]: print(np.log((1+1+2)/(1+2+3+4+1+3+4+4+4*2)),np.log((2+3+2)/(1+2+3+4+1+
    ...: 3+4+4+4*2)),np.log((3+4+2)/(1+2+3+4+1+3+4+4+4*2)),np.log((4+4+2)/(1+2+
    ...: 3+4+1+3+4+4+4*2)))
-2.01490302054 -1.45528723261 -1.20397280433 -1.09861228867

  

特徵的條件概率=(指定類下指定特徵出現的次數+alpha)/(指定類下所有特徵出現次數之和+類的可能取值個數*alpha)

  • coef_:將多項式樸素貝葉斯解釋feature_log_prob_對映成線性模型,其值和feature_log_prob相同
In [11]: clf.coef_
Out[11]:
array([[-2.01490302, -1.45528723, -1.2039728 , -1.09861229],
       [-1.87180218, -1.31218639, -1.178655  , -1.31218639],
       [-1.74919985, -1.43074612, -1.26369204, -1.18958407],
       [-1.79175947, -1.38629436, -1.23214368, -1.23214368]])
  • class_count_:訓練樣本中各類別對應的樣本數,按類的順序排序輸出
In [12]: clf.class_count_
Out[12]: array([ 2.,  1.,  2.,  1.])
  • feature_count_:各類別各個特徵出現的次數,返回形狀為(n_classes, n_features)陣列
In [13]: clf.feature_count_
Out[13]:
array([[  2.,   5.,   7.,   8.],
       [  2.,   5.,   6.,   5.],
       [  6.,   9.,  11.,  12.],
       [  2.,   4.,   5.,   5.]])
 
 
In [14]: print([(1+1),(2+3),(3+4),(4+4)])#以類別1為例
[2, 5, 7, 8]

  

2.3 方法

  • fit(X, y, sample_weight=None):根據X、y訓練模型
In [15]: import numpy as np
    ...: from sklearn.naive_bayes import MultinomialNB
    ...: X = np.array([[1,2,3,4],[1,3,4,4],[2,4,5,5],[2,5,6,5],[3,4,5,6],[3,5,6
    ...: ,6]])
    ...: y = np.array([1,1,4,2,3,3])
    ...: clf = MultinomialNB(alpha=2.0,fit_prior=True)
    ...: clf.fit(X,y)
    ...:
Out[15]: MultinomialNB(alpha=2.0, class_prior=None, fit_prior=True)

  

  • get_params(deep=True):獲取分類器的引數,以各引數字典形式返回
In [16]: clf.get_params(True)
Out[16]: {'alpha': 2.0, 'class_prior': None, 'fit_prior': True}

  

  • partial_fit(X, y, classes=None, sample_weight=None):對於資料量大時,提供增量式訓練,線上學習模型引數,引數X可以是類似陣列或稀疏矩陣,在第一次呼叫函式,必須制定classes引數,隨後呼叫時可以忽略
In [17]: import numpy as np
    ...: from sklearn.naive_bayes import MultinomialNB
    ...: X = np.array([[1,2,3,4],[1,3,4,4],[2,4,5,5],[2,5,6,5],[3,4,5,6],[3,5,6
    ...: ,6]])
    ...: y = np.array([1,1,4,2,3,3])
    ...: clf = MultinomialNB(alpha=2.0,fit_prior=True)
    ...: clf.partial_fit(X,y)
    ...: clf.partial_fit(X,y,classes=[1,2])
    ...:
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-17-b512d165c9a0> in <module>()
      4 y = np.array([1,1,4,2,3,3])
      5 clf = MultinomialNB(alpha=2.0,fit_prior=True)
----> 6 clf.partial_fit(X,y)
      7 clf.partial_fit(X,y,classes=[1,2])
 
ValueError: classes must be passed on the first call to partial_fit.
 
In [18]: import numpy as np
    ...: from sklearn.naive_bayes import MultinomialNB
    ...: X = np.array([[1,2,3,4],[1,3,4,4],[2,4,5,5],[2,5,6,5],[3,4,5,6],[3,5,6
    ...: ,6]])
    ...: y = np.array([1,1,4,2,3,3])
    ...: clf = MultinomialNB(alpha=2.0,fit_prior=True)
    ...: clf.partial_fit(X,y,classes=[1,2])
    ...: clf.partial_fit(X,y)
    ...:
    ...:
Out[18]: MultinomialNB(alpha=2.0, class_prior=None, fit_prior=True)

  

  • predict(X):在測試集X上預測,輸出X對應目標值
In [19]: clf.predict([[1,3,5,6],[3,4,5,4]])
Out[19]: array([1, 1])

  

  • predict_log_proba(X):測試樣本劃分到各個類的概率對數值
In [22]: import numpy as np
    ...: from sklearn.naive_bayes import MultinomialNB
    ...: X = np.array([[1,2,3,4],[1,3,4,4],[2,4,5,5],[2,5,6,5],[3,4,5,6],[3,5,6
    ...: ,6]])
    ...: y = np.array([1,1,4,2,3,3])
    ...: clf = MultinomialNB(alpha=2.0,fit_prior=True)
    ...: clf.fit(X,y)
    ...:
Out[22]: MultinomialNB(alpha=2.0, class_prior=None, fit_prior=True)
 
In [23]: clf.predict_log_proba([[3,4,5,4],[1,3,5,6]])
Out[23]:
array([[-1.27396027, -1.69310891, -1.04116963, -1.69668527],
       [-0.78041614, -2.05601551, -1.28551649, -1.98548389]])

  

  • predict_proba(X):輸出測試樣本劃分到各個類別的概率值
In [1]: import numpy as np
   ...: from sklearn.naive_bayes import MultinomialNB
   ...: X = np.array([[1,2,3,4],[1,3,4,4],[2,4,5,5],[2,5,6,5],[3,4,5,6],[3,5,6,
   ...: 6]])
   ...: y = np.array([1,1,4,2,3,3])
   ...: clf = MultinomialNB(alpha=2.0,fit_prior=True)
   ...: clf.fit(X,y)
   ...:
Out[1]: MultinomialNB(alpha=2.0, class_prior=None, fit_prior=True)
 
In [2]: clf.predict_proba([[3,4,5,4],[1,3,5,6]])
Out[2]:
array([[ 0.27972165,  0.18394676,  0.35304151,  0.18329008],

  

  • score(X, y, sample_weight=None):輸出對測試樣本的預測準確率的平均值
In [3]: clf.score([[3,4,5,4],[1,3,5,6]],[1,1])
Out[3]: 0.5

  

  • set_params(**params):設定估計器的引數
In [4]: clf.set_params(alpha=1.0)
Out[4]: MultinomialNB(alpha=1.0, class_prior=None, fit_prior=True)

  

3,伯努利樸素貝葉斯

  類似於多項式樸素貝葉斯,也主要用於離散特徵分類,和MultinomialNB的區別是:MultinomialNB以出現的次數為特徵值,BernnoulliNB為二進位制或者布林值特徵

sklearn.naive_bayes.BernoulliNB(alpha=1.0, binarize=0.0, fit_prior=True,class_prior=None)

  引數說明:

binarize:將資料特徵二值化的閾值

  

3.1  利用BernoulliNB建立簡單模型

In [5]: import numpy as np
   ...: from sklearn.naive_bayes import BernoulliNB
   ...: X = np.array([[1,2,3,4],[1,3,4,4],[2,4,5,5]])
   ...: y = np.array([1,1,2])
   ...: clf = BernoulliNB(alpha=2.0,binarize = 3.0,fit_prior=True)
   ...: clf.fit(X,y)
   ...:
Out[5]: BernoulliNB(alpha=2.0, binarize=3.0, class_prior=None, fit_prior=True)

  經過binarize=0.3二值化處理,相當於輸入的X陣列為:

In [7]: X = np.array([[0,0,0,1],[0,0,1,1],[0,1,1,1]])
 
In [8]: X
Out[8]:
array([[0, 0, 0, 1],
       [0, 0, 1, 1],
       [0, 1, 1, 1]])

  

3.2  訓練後檢視個屬性值

  • class_log_prior_:類先驗概率對數值,類先驗概率等於各類的個數/類的總個數
In [9]: clf.class_log_prior_
Out[9]: array([-0.40546511, -1.09861229])

  

  • feature_log_prob_ :指定類的各特徵概率(條件概率)對數值,返回形狀為(n_classes, n_features)陣列
Out[10]:
array([[-1.09861229, -1.09861229, -0.69314718, -0.40546511],
       [-0.91629073, -0.51082562, -0.51082562, -0.51082562]])

  

上述結果計算過程:
假設X對應的四個特徵為A1、A2、A3、A4,類別為y1,y2,類別為y1時,特徵A1的概率為:P(A1|y=y1) = P(A1=0|y=y1)*A1+P(A1=1|y=y1)*A1
In [11]: import numpy as np
    ...: from sklearn.naive_bayes import BernoulliNB
    ...: X = np.array([[1,2,3,4],[1,3,4,4],[2,4,5,5]])
    ...: y = np.array([1,1,2])
    ...: clf = BernoulliNB(alpha=2.0,binarize = 3.0,fit_prior=True)
    ...: clf.fit(X,y)
    ...: print(clf.feature_log_prob_)
    ...: print([np.log((2+2)/(2+2*2))*0+np.log((0+2)/(2+2*2))*1,np.log((2+2)/(2
    ...: +2*2))*0+np.log((0+2)/(2+2*2))*1,np.log((1+2)/(2+2*2))*0+np.log((1+2)/
    ...: (2+2*2))*1,np.log((0+2)/(2+2*2))*0+np.log((2+2)/(2+2*2))*1])
    ...:
[[-1.09861229 -1.09861229 -0.69314718 -0.40546511]
 [-0.91629073 -0.51082562 -0.51082562 -0.51082562]]
[-1.0986122886681098, -1.0986122886681098, -0.69314718055994529, -0.405465108108
16444]

  

  • class_count_:按類別順序輸出其對應的個數
In [12]: clf.class_count_
Out[12]: array([ 2.,  1.])

 

  • feature_count_:各類別各特徵值之和,按類的順序輸出,返回形狀為[n_classes, n_features] 的陣列
In [13]: clf.feature_count_
Out[13]:
array([[ 0.,  0.,  1.,  2.],
       [ 0.,  1.,  1.,  1.]])

  

3.3 方法

  類似於MultinomialNB的方法類似

 

Sklearn實戰一(多項式樸素貝葉斯)

  樸素貝葉斯模型被廣泛應用於海量網際網路文字分類任務。由於其較強的特徵條件獨立假設,使得模型預測所需要顧及的引數規模從冪指數數量級向線性量級減少,極大的節約了記憶體消耗和計算時間。但是,也正是受這種強假設的限制,模型訓練時無法將各個特徵之間的聯絡考量在內,使得該模型在其他資料特徵關聯性較強的分類任務上效能表現不佳。

 程式碼:

#_*_coding:utf-8_*_
# 從sklearn.datasets中匯入新聞資料抓取器
from sklearn.datasets import fetch_20newsgroups
from sklearn.model_selection import train_test_split
# 從sklearn.feature_extraction.text裡匯入文字特徵向量化模板
from sklearn.feature_extraction.text import CountVectorizer
# 從sklearn.naive_bayes裡匯入樸素貝葉斯模型
from sklearn.naive_bayes import MultinomialNB
from sklearn.metrics import classification_report

# 資料獲取
news = fetch_20newsgroups(subset='all')
# 輸出資料的條數  18846
print(len(news.data))

# 資料預處理:訓練集和測試集分割,文字特徵向量化
# 隨機取樣25%的資料樣本作為測試集
X_train, X_test, y_train, y_test = train_test_split(
    news.data, news.target, test_size=0.25, random_state=33
)
# # 檢視訓練樣本
# print(X_train[0])
# # 檢視標籤
# print(y_train[0:100])

# 文字特徵向量化
vec = CountVectorizer()
X_train = vec.fit_transform(X_train)
X_test = vec.transform(X_test)

# 使用樸素貝葉斯進行訓練
# 使用預設配置初始化樸素貝葉斯
mnb = MultinomialNB()
# 利用訓練資料對模型引數進行估計
mnb.fit(X_train, y_train)
# 對引數進行預測
y_predict = mnb.predict(X_test)

# 獲取結果報告
score = mnb.score(X_test, y_test)
print('The accuracy of Naive bayes Classifier is %s' %score)

res = classification_report(y_test, y_predict, target_names=news.target_names)
print(res)

  結果如下:

 

The accuracy of Naive bayes Classifier is 0.8397707979626485

  

 

 

 Sklearn實戰二(多項式樸素貝葉斯)

程式碼:

#_*_coding:utf-8_*_

import pandas as pd
import numpy as np
import cv2
import time

from sklearn.model_selection import train_test_split
from sklearn.metrics  import accuracy_score

# 獲取資料
def load_data():
    # 讀取csv資料
    raw_data = pd.read_csv('train.csv', header=0)
    data = raw_data.values
    features = data[::, 1::]
    labels = data[::, 0]
    # 避免過擬合,採用交叉驗證,隨機選取33%資料作為測試集,剩餘為訓練集
    train_X, test_X, train_y, test_y = train_test_split(features, labels, test_size=0.33, random_state=0)
    return train_X, test_X, train_y, test_y

# 二值化處理
def binaryzation(img):
    # 型別轉化成Numpy中的uint8型
    cv_img = img.astype(np.uint8)
    # 大於50的值賦值為0,不然賦值為1
    cv2.threshold(cv_img, 50, 1, cv2.THRESH_BINARY_INV, cv_img)
    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)):
        # 圖片二值化,讓每一個特徵都只有0, 1 兩種取值
        img = binaryzation(trainset[i])
        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][i][0]
            pix_1 = conditional_probability[i][j][1]
            # 計算0, 1畫素點對應的條件概率
            probability_0 = (float(pix_0)/float(pix_0 + pix_1))*10000 + 1
            probability_1 = (float(pix_1)/float(pix_0 + pix_1))*10000 + 1

            conditional_probability[i][j][0] = probability_0
            conditional_probability[i][j][1] = probability_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)


# MNIST資料集有10種labels,分別為“0,1,2,3,4,5,6,7,8,9
class_num = 10
feature_len = 784

if __name__ == '__main__':
    time_1 = time.time()
    train_X, test_X, train_y, test_y = load_data()
    prior_probability, conditional_probability = Train(train_X, train_y)
    test_predict = Predict(test_X, prior_probability, conditional_probability)
    score = accuracy_score(test_y, test_predict)
    print(score)

  資料需要的@我,放在這裡,太大了。

Sklearn實戰三(高斯樸素貝葉斯)

   程式碼:

from sklearn import metrics
from sklearn.naive_bayes import GaussianNB
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler

# 讀取資料
X = []
Y = []
fr = open("datingTestSet.txt", encoding='utf-8')
print(fr)
index = 0
for line in fr.readlines():
    # print(line)
    line = line.strip()
    line = line.split('\t')
    X.append(line[:3])
    Y.append(line[-1])

# 歸一化
scaler = MinMaxScaler()
# print(X)
X = scaler.fit_transform(X)
# print(X)

# 交叉分類
train_X, test_X, train_y, test_y = train_test_split(X, Y, test_size=0.2)

#高斯貝葉斯模型
model = GaussianNB()
model.fit(train_X, train_y)

# 預測測試集資料
predicted = model.predict(test_X)
# 輸出分類資訊
res = metrics.classification_report(test_y, predicted)
# print(res)
# 去重複,得到標籤類別
label = list(set(Y))
# print(label)
# 輸出混淆矩陣資訊
matrix_info = metrics.confusion_matrix(test_y, predicted, labels=label)
# print(matrix_info)

  資料需要的@我,放在這裡,太大了。

 

 補充:文字特徵向量化

  樸素貝葉斯模型去給文字資料分類,就必須對文字資料進行處理。

1,處理的流程如下:

  • 1,對文字分詞(作為特徵)
  • 2,統計各詞在句子中是否出現(詞集模型)
  • 3,統計各詞在句子中出現次數(詞袋模型)
  • 4,統計各詞在這個文件的TFIDF值(詞袋模型+ IDF值)

2,文字特徵向量化方法:

  • 1,詞集模型:One-Hot編碼向量化文字
  • 2,詞袋模型+ IDF:TFIDF向量化文字
  • 3,雜湊向量化文字

具體原理如下:

  1,One-Hot表示法先將文字資料集中不重複的單詞提取出來,得到一個大小為V的詞彙表。然後用一個V維的向量來表示一個文章,向量中的第的d個維度上的1 表示詞彙表中的第 d個單詞出現在這篇文章中。

  如果文字資料集太大,那麼得到的詞彙表中可能存在幾千個單詞,這樣文字的維度會太大,不僅會導致計算時間增加,而且帶來了稀疏問題(One-Hot矩陣中大多數元素都是0)。因此,我們通常會在計算詞彙表的時候,會排除那些出現次數太少的單詞,從而降低文字維度。

  2,TF-IDF(term frequency-inverse document frequency),不僅考慮了單詞在文章中的出現次數,還考慮了其在整個文字資料集中的出現次數。TF-IDF的主要思想是:如果某個詞或短語在一篇文章中出現的頻率TF高,並且在其他文章中很少出現,則認為此詞或者短語具有很好的類別區分能力。

  3,TFidfVectorizer在執行時,需要先將詞袋矩陣放入記憶體,再計算個位置單詞的TFIDF值,如果詞袋維度大,將佔用過多記憶體,效率低,此時可以使用雜湊向量化。雜湊向量化可以緩解TFidfVectorizer在處理高維文字時記憶體消耗過大的問題。

 

問題:自然語言處理裡和貝葉斯模型裡出現的laplace光滑什麼意思?有什麼用?

  拉普拉斯光滑是用來對分類變數的出現頻率進行光滑修正的一個手段。

  比如一句話“我愛機器學習”,一共七個字。

  “我”出現了一次,頻率為:

  “學”出現了兩次,頻率為:

  拉普拉斯光滑的公式為:

  其中nx是單詞x出現的次數,l是句子的長度,c是句子中不同詞彙的個數,a是拉普拉斯光滑的光滑係數,這個是自行設定的。

  上面的句子一共七個字,五個不同的字,假設我們選定a=1:

  假設我們選定 a=2:

  a越大,得到的結果越接近於均勻分佈。

  拉普拉斯光滑解決了一些0概率的問題,即一個樣本雖然不出現,但是我們不能認為它的概率就一定是0,在貝葉斯模型中,拉普拉斯光滑很常見。

  此外,拉普拉斯光滑不只是在自然語言處理的文字,詞彙資料,它使用所有的多元categorical的資料。

 

 

參考文獻:https://www.cnblogs.com/pinard/p/6069267.html

 https://www.cnblogs.com/youngsea/p/9327972.html

https://blog.csdn.net/qq_35044025/article/details/79322169

 

相關文章