1. 程式人生 > 其它 >python機器學習——樸素貝葉斯演算法

python機器學習——樸素貝葉斯演算法

背景與原理:

樸素貝葉斯演算法是機器學習領域最經典的演算法之一,仍然是用來解決分類問題的。

那麼對於分類問題,我們的模型始終是:用$m$組資料,每條資料形如$(x_{1},...,x_{n},y)$,表示資料共有$n$個特徵維度,而$y$表示該資料所屬的類別,不妨設有$k$個取值$C_{1},...,C_{k}$

我們想一想,當我們談論分類問題的時候,我們究竟在談論什麼?

從一個角度來理解,我們實際上是在研究:當給定了$X=x$的條件下,求概率$P(y=C_{i})$,而我們對分類的預測實際上就是使得$P(y=C_{i})$最大的$C_{i}$!

那麼我們實際想求出的是$P(y=C_{i}|X=x)$這樣的一個條件概率。

我們需要一些數學原理:

貝葉斯公式:$P(X|Y)=\dfrac{P(Y|X)P(X)}{P(Y)}$

這個公式的邏輯是很簡單的:$P(X\cap Y)=P(X|Y)P(Y)=P(Y|X)P(X)$,即兩個事件同時發生的概率始終等於一個事件在另一個事件發生條件下的概率乘以另一個事件發生的概率。

而基於這個邏輯,我們有:

$P(y=C_{i}|X=x)=\dfrac{P(X=x|y=C_{i})P(y=C_{i})}{P(X=x)}$

而我們再要求$X$的各個特徵是彼此獨立的,那麼我們有:

$P(X=x|y=C_{i})=\prod_{j=1}^{n}P(X_{j}=x_{j}|y=C_{i})$

於是我們有最終的表示式:

$P(y=C_{i}|X=x)=\dfrac{\prod_{j=1}^{n}P(X_{j}=x_{j}|y=C_{i}) P(y=C_{i})}{P(X=x)}$

而我們想要的是:

$argmax_{C_{i}}\dfrac{\prod_{j=1}^{n}P(X_{j}=x_{j}|y=C_{i}) P(y=C_{i})}{P(X=x)}$

可以看到,對不同的$C_{i}$,上式的分母是相同的,那麼我們將其省略,就得到了:

$argmax_{C_{i}}P(y=C_{i})\prod_{j=1}^{n}P(X_{j}=x_{j}|y=C_{i}) $

這就是我們真正想求的東西

那麼$P(y=C_{i})$是多少呢?它是一個無關條件的先驗概率,那麼我們可以估計其為資料集中類別為$C_{i}$的資料出現的頻率,即出現次數與資料集大小之比。那麼我們設資料集中類別為$C_{i}$的資料有$c_{i}$條,那麼我們有:

$P(y=C_{i})=\dfrac{c_{i}}{m}$(其中$m$為資料集大小)

但是如果我們資料集選取的很不好,某一個類別雖然我們的先驗知識告訴我們有,但資料集中卻沒有這一個分類,這隻能說明這個類別出現概率可能比較小,但並不意味著一定不會出現,所以我們需要給一個補償項,我們選取一個常數$\lambda$,有:

$P(y=C_{i})=\dfrac{c_{i}+\lambda}{m+k\lambda}$(其中$k$為類別數,相當於對每一類我們都人工添加了$\lambda$個屬於這一類的資料)

這樣兜兜轉轉,我們發現不太好求出的實際上是$P(X_{j}=x_{j}|y=C_{i})$

那麼怎麼求呢?如果$X_{j}$是一個離散的量,那麼我們只需再次引入貝葉斯公式:

$P(X_{j}=x_{j}|y=C_{i})=\dfrac{P(X_{j}=x_{j},y=C_{i})}{P(y=C_{i})}$

這樣我們只需統計在原資料集中$X_{j}=x_{j}$且$y=C_{i}$的資料集出現的頻率近似為概率再除以$y=C_{i}$出現的概率就好了。

當然,和上面的情況一樣,我們同樣可能會遇到倒黴的情況,即這種資料沒有出現在資料集中,那我們當然也不能直接認為這種概率是零,那麼和上述處理類似地引入拉普拉斯平滑,選取一個常數$\lambda$(通常為1),此時有:

$P(X_{j}=x_{j}|y=C_{i})=\dfrac{\sum_{p=1}^{m}[X_{j}=x_{j},y=C_{i}]+\lambda}{\sum_{p=1}^{m}[y=C_{i}]+O_{j}\lambda}$

這裡的記號$[...]$表示如果中括號裡內容為真取值為1,否則取值為0,而$O_{j}$是特徵$j$的取值個數

但是...如果特徵是連續的呢?

那麼我們會認為這樣的分佈服從正態分佈,即這個條件概率為:

$P(X_{j}=x_{j}|y=C_{i})=\dfrac{1}{\sqrt{2\pi \sigma_{i}^{2}}}e^{-\frac{(x_{j}-\mu_{i})^{2}}{2\sigma_{i}^{2}}}$

即我們認為在$y=C_{i}$的條件下,所有的$X_{j}$的分佈服從均值為$\mu_{i}$,方差為$\sigma_{i}^{2}$的正態分佈,而這個均值與方差可以通過極大似然估計求得。

這樣我們就解決了所有的問題。

程式碼實現:

import numpy as np
from sklearn import datasets
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import LinearSVC
import matplotlib.pyplot as plt
import pylab as plt
from sklearn.naive_bayes import GaussianNB
from sklearn.model_selection import train_test_split


X,y=datasets.make_classification(n_samples=10000,n_features=20,n_informative=2,n_redundant=2)
X_train,X_test,Y_train,Y_test=train_test_split(X,y,test_size=0.25)

lr=LogisticRegression()
svc=LinearSVC(C=1.0)
rfc=RandomForestClassifier(n_estimators=100)#森林中樹的個數

lr=lr.fit(X_train,Y_train)
score1=lr.score(X_test,Y_test)
print(score1)

svc=svc.fit(X_train,Y_train)
score2=svc.score(X_test,Y_test)
print(score2)

rfc=rfc.fit(X_train,Y_train)
score3=rfc.score(X_test,Y_test)
print(score3)

gnb=GaussianNB()
gnb=gnb.fit(X_train,Y_train)
score4=gnb.score(X_test,Y_test)
print(score4)

y_pred=gnb.predict_proba(X_test)
print(y_pred[:10])

這是在上一篇部落格基礎上對四種分類器的對比,在sklearn中樸素貝葉斯分類器主要有三種:高斯樸素貝葉斯GaussianNB,多項式樸素貝葉斯MultinomialNB和伯努利樸素貝葉斯BernoulliNB,高斯樸素貝葉斯用於處理特徵是連續值的情況,而多項式樸素貝葉斯用於處理特徵是離散值的情況,而伯努利樸素貝葉斯則用於處理特徵只有0/1的情況。

這裡我們使用sklearn自帶的高斯樸素貝葉斯對與前文類似生成的資料集進行分類並對比分類效果,可以看到由於樸素貝葉斯對特徵的分佈有嚴格的要求(獨立、正態等),因此分類效果相較別的分類器相對較差,但是樸素貝葉斯的訓練效率比較高,而且可解釋性也比較好,這是樸素貝葉斯的優點所在。

小結與優化:

樸素貝葉斯由於基礎要求太高,導致很多情況下分類效果並不好,那麼為了解決這個問題,人們作出了一些優化。比如針對要求各個維度相互獨立的要求,一種方法是在樸素貝葉斯基礎上增加屬性間可能存在的依賴關係,另一種則是重新構建資料集,通過變換等手段將原來相關的屬性變為獨立的屬性。最著名的優化方法是TAN演算法,通過發現屬性間的依賴關係來降低獨立性假設。