2018/12/13

Naive Bayes (天性貝氏)

14 Naive Bayes (貝氏)

天性貝氏分類器是一種簡單的機率式分類器  (Probabilistic classifiers) ,是基於貝氏定理和特徵間彼此獨立的假設。Naive就是指天性單純,也就是強調特地間是彼此獨立的,而Bayes是指貝氏定理,此定理在機率理論及統計理論裡有很廣泛的應用。可將貝氏定理表示成
$$\begin{equation} P(X|Y)=\frac{P(Y|X)P(X)}{P(Y)} \end{equation}$$ 其中$P(Y|X)$表示條件機率,指出在已知$X$的情況下,$Y$ 出現的機率。而$P(X|Y)$是指在已知$Y$的情況下, $X$ 出現的機率。貝氏定理來就是用來互轉這兩個條件機率,以下圖來說明此式子的意義及應用
條件機率圖說
圖中的$X$可以看成輸入,其值是0或1,而$Y$看成輸出,$p(y_1|x=0)$表示當$x=0$時會得$y_1$的機率,相同地,$p(y_1|x=1)$表示當$x=1$時會得$y_1$的機率,這兩機率可一般化寫成$P(Y|X)$ 是一種 A Priori (先驗)機率,意思是說我們還沒實驗前就已知道的機率,而$P(X|Y)$ 是A Posteriori (後驗)機率,亦即要實驗後由觀察到的值來推論,因為看到的$y_1$可能是由$x=0$引起,也可能是由$x=1$來,求$p(x=0|y_1)$就是求 $y_1$ 由 class 0 所引起的機率。貝氏定理可用求解這種後驗機率。

∎單特徵分類
在Naive Bayes的應用中可將$X$看成類別,將$Y$看成特徵,當我們見某一特徵時想推論是什麼類別,所以可看成一種分類的應用。例如我們看見特徵 $y_1$,則可求 $y_1$ 由class 0 引起的機率,  $$\begin{equation} p(x=0|y_1)=\frac{p(y_1|x=0)p(x=0)}{p(y_1|x=0)p(x=0)+p(y_1|x=1)p(x=1)}\end{equation}$$ 同時也求$y_1$由class 1 引起的機率,$p(x=1|y_1)$,
$$\begin{equation} p(x=1|y_1)=\frac{p(y_1|x=1)p(x=1)}{p(y_1|x=0)p(x=0)+p(y_1|x=1)p(x=1)}\end{equation}$$ 因要推論$y_1$是由那一個類別而來的,我們比較(2) 和 (3),但因分母兩式一樣,所以只需比較分子,若 $$p(y_1|x=0)p(x=0)>p(y_1|x=1)p(x=1)$$ 則推定是由class 0而來,否則是由class 1而來。$p(x=i)$是類別 $i$ 的機率是類別 $i$ 的數目和總實例數目的比值,而$p(y_1|x=i)$是類別 $i$ 中具有特徵 $y_1$ 的比率。

我們以一個簡單的例子來說明如何計算機率值。
✋ 假設兩個類別為 0 和 1,類別0有 3個實例,類別1有9個實例,其中類別0中有一個實例具有我們關心的特徵,而類別1 中有2個有此特徵,若觀察中見一實例具有此特徵,則該判斷類別0或是1?

👉 由給定的問題知 $(p(x=0)=1/4$, $p(x=1)=3/4$, 而$p(y|x=0)=1/3$, $p(y|x=1)=2/9$,因只需求分子,所以可計算$p(y|x=0)p(x=0)=(1/4)\times (1/3)=1/12$,$p(y|x=1)p(x=1)=(2/9)\times (3/4)=1/6$,因此判定為來自 class 1。此題的另一個思考是共有12個實例,其中有三個具有考慮的特徵,有一個來自class 0,兩個來自class 1。當已知抽取出的實例有此特徵表示當抽到不具特徵的都不考慮,直至抽到有此特徵為止,這相當於從三個有此特徵的實例中隨機抽取,因class 1有兩個實例, class 0有一個實例,所以抽到class 1的機率是抽到class 0兩倍,因而判斷為class 1。

∎多特徵分類
在分類應用中當然會有很多特徵,所以我們必需單特徵的情形推展到多特徵分類,如下圖所示,
多特徵
圖中表示有$y_1,\cdots,y_K$個特徵。假設我們在一實例中見到$y_1,\cdots,y_j$等特徵,要推論是屬於那個class,則計算 $$\begin{equation} p(x_i|y_1,\cdots,y_j)=\frac{p(y_1,\cdots,y_j|x_i)p(x_i)}{p(y_1,\cdots,y_j)},\: i=0,1\end{equation}$$ 因分母相同,我們只判斷分子 $$\begin{equation} p(y_1,\cdots,y_j|x_i)p(x_i)=p(x_i)\prod _{k=1}^jp(y_k|x_i)\end{equation}$$ 因此,判斷的準則可寫成 $$ p(x_0)\prod _{k=1}^jp(y_k|x_0) \begin{align*} &\mbox{ 0}\\[-5pt] &\gtrless \\[-5pt] &\mbox{ 1} \end{align*} \: \: p(x_1)\prod _{k=1}^jp(y_k|x_1) $$ 上面的推論都是假設給定一個類別後,該類別的特徵間彼此獨立,才能將合機率分佈成連乘,但這假設並不合理,因在同一個類別下特徵並不一定是獨立的,例如在性別判斷中,若給定女生 ,則身高體重有一定的關聯性,並非獨立。但若要考慮關聯性,特徵的聯合機率分佈會很複雜,使得問題難以處理。

∎ sklearn Naive Bayes (NB)
sklearn 內建多種Naive Bayes 的class
  • Multinomial Naïve bayes: MultiNB 假設特徵是多項式分佈,適合分類形特徵
  • Gaussian NB: MultiNB 假設特徵是高斯分佈,適合連續形特徵
  • Bernoulli NB:適合二元值的特徵,每項都是一個Bernoulli分佈。
scikit-learn 中有一內建的資料集 'The Breast Cancer Wisconsin dataset' ,是個有關乳房腫塊的資集,其每一實例含有 30個描述核細胞的實數值特徵,共有212個惡性 (Malignant)和357個良性(Benign)的標籤。
from sklearn.datasets import load_breast_cancer
breast = load_breast_cancer()
print(breast.target_names)
print(breast.feature_names)
print(len(breast.data))
print(sum(breast.target))
['malignant' 'benign']
['mean radius' 'mean texture' 'mean perimeter' 'mean area'
 'mean smoothness' 'mean compactness' 'mean concavity'
 'mean concave points' 'mean symmetry' 'mean fractal dimension'
 'radius error' 'texture error' 'perimeter error' 'area error'
 'smoothness error' 'compactness error' 'concavity error'
 'concave points error' 'symmetry error' 'fractal dimension error'
 'worst radius' 'worst texture' 'worst perimeter' 'worst area'
 'worst smoothness' 'worst compactness' 'worst concavity'
 'worst concave points' 'worst symmetry' 'worst fractal dimension']
569
357
第二行 load_breast_cancer()若有加上參數 "return_X_y=True" 則會傳回特徵及標籤分離的資料,預設是fault,會傳回一整串Dictionary-like object, 用傳回的資料可檢查資料集的屬性,如target的名稱是 ['malignant' 'benign'] ,特徵的名稱,也可查驗總共有569個實例,其有357個良性,因其二元編碼是1,所以sum()可以統計總數。

在參考文獻裡的應用是使用此資料集於比較NB 和邏輯回歸的性能,程式如下
from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import LogisticRegression
from sklearn.naive_bayes import GaussianNB
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
%matplotlib inline
X,y = load_breast_cancer(return_X_y=True)
X_train, X_test,y_train,y_test = train_test_split(X, y,stratify=y,random_state=11)
lr = LogisticRegression()
nb = GaussianNB()

lr_scores = []
nb_scores = []
train_sizes = range(10, len(X_train), 10)
for size in train_sizes:
    X_slice, _, y_slice, _ = train_test_split(
          X_train, y_train, train_size=size, test_size=len(X_train)-size, 
          stratify=y_train, random_state=11)
    nb.fit(X_slice, y_slice)
    nb_scores.append(nb.score(X_test, y_test))
    lr.fit(X_slice, y_slice)
    lr_scores.append(lr.score(X_test, y_test))
    
plt.plot(train_sizes, nb_scores, label='Naive Bayes')
plt.plot(train_sizes, lr_scores, linestyle='--', label='Logistic Regression')
plt.title("Naive Bayes and Logistic Regression Accuracies")
plt.xlabel("Number of training instances")
plt.ylabel("Test set accuracy")
plt.legend()
性能比較
程式第7行設"return_X_y=True" ,第8行的 stratify=y是指當分層放資料時,訓練集和測試集要有相同比率的正負實例,以免標籤不平衡。第15-18行表示每次增加10個實例到訓練集進行訓練,所以可以得上面的比較圖,其中若沒有加上 test_size=len(X_train)-size,,因只有指定訓練 集大小,沒有指定測試集大小執亍時會有警告,加上這個參數就不會有警告。執行結果顯示當訓集實例較少時 NB的性能較好,但當訓練集實例增加時反而是邏輯回歸的性能較好。

參考文獻
Gavin Hackeling, Mastering Machine Learning with scikit-learn, 2nd, Packt Publishing, 2017

沒有留言:

張貼留言