<center>
<img src = "https://i.imgur.com/5nBHi93.jpg">
</center>
## Prerequisite
單純貝氏分類器 (Naive Bayes) 是以貝氏定理來解決機器學習上的分類問題。
不免俗在機器學習上,如何估計模型參數是一大重點,而這裡是透過最大概似估計 (Maximum likelihood estimation) 來解決這個問題。
### Maximum likelihood estimation (MLE)
最大概似估計是一個估計機率模型中母數的方法。
這裡先定義一個已知的機率分佈 $D$,其機率函數為 $f_D$,而分佈母數為 $\theta$。
> :bulb: 如何求出 likelihood function ?
> 我們從機率分佈 $D$ 中,抽出 $n$ 個值,$X_1, X_2, \dots, X_n$,並透過 $f_D$ 來計算:
> $$
> L(\theta \mid x_1, \dots, x_n) = f_\theta (x_1, \dots, x_n)
> $$
不論 $D$ 為離散分佈或是連續分佈,最大概似估計會尋找關於 $\theta$ 的最可能的值,而這個值會使得概似函數取到最大值。
其中,$\hat{\theta}$ 即是 $\theta$ 的最大概似估計。但也要注意,最大概似估計不一定存在,也不一定唯一。
### Bayesian probability
貝氏機率 (Bayesian probability) 是透過機率來解釋貝氏定理。
> :bulb: 貝氏定理
> 在已知一些條件下,某一事件的發生機率。例如在事件$B$發生事件$A$的機率。
> 這裡先定義隨機事件 $A$ 和 $B$
> $$
> P(A \mid B) = \frac{P(A)P(B \mid A)}{P(B)}
> $$
> 其中,$P(A \mid B)$ 為 $A$ 的後驗機率,$P(A)$ 是 $A$ 的先驗機率。
## Goal
Naive Bayes 是一種建分類器的方法,主要透過特徵之間強獨立下,運用貝氏定理來分類各式類別。
## Background
如先前提及,貝式定理是描述某已知條件下,另一個事件發生的機率。
透過此定理而進行分類任務的模型可以被定義為
$$
p(C \mid F_1, \dots, F_n)
$$
而此可以依照貝式定理等價於
$$
p(C \mid F_1, \dots, F_n) = \frac{p(C)p(F_1, \dots, F_n \mid C)}{p(F_1, \dots, F_n)}
$$
即是
$$
\text{posterior} = \frac{\text{prior} \times \text{likelihood}}{\text{evidence}}
$$
其中分子的部份可以等價於聯合分佈模型 $p(C, F_1, \dots, F_n)$
接著使用連鎖律
$$
\left.\frac{d g[f(x)]}{d x}\right|_{x=a}=\left.\left.\frac{d g(y)}{d y}\right|_{y=f(a)} \cdot \frac{d f}{d x}\right|_{x=a}
$$
便可以將此寫成條件機率
$$
\begin{align}
p(C, F_1, & \dots, F_n) \\
& \propto p(C) * p(F_1, \dots, F_n \mid C) \\
& \propto p(C) * p(F_1 \mid C) * p(F_2, \dots, F_n \mid C, F_1) \\
& \propto p(C) * p(F_1 \mid C) * p(F_2 \mid C, F_1) * p(F_3, \dots, F_n \mid C, F_1, F_2) \\
& \propto p(C) * p(F_1 \mid C) * p(F_2 \mid C, F_1) * p(F_3 \mid C, F_1, F_2) \dots p(F_n \mid C, F_1, F_2, \dots, F_{n-1}) \\
\end{align}
$$
由於可能計算的特徵數量過多,為了計算後驗機率上的方便,這裡必須先假設特徵之間獨立,但也讓分類準確率下降一些,變得像是一種估計機率後分類的概念。
如此一來,有特徵相互獨立的條件後,可以將此模型表示為
$$
\begin{align}
p(C \mid F_1, \dots, F_n) & \propto p(C, F_1, \dots, F_n) \\
& \propto p(C) p(F_1 \mid C) p(F_2 \mid C) p(F_3 \mid C) \dots \\
& \propto p(C) \prod \limits_{i=1}^n p(F_i \mid C)
\end{align}
$$
而類別變數$C$條件分佈可以寫成
$$
p(C \mid F_1, \dots F_n) = \frac{1}{Z} p(C) \prod \limits_{i=1}^n p(F_i \mid C)
$$
這裡的 $Z$ 是會依據 $F_1, \dots, F_n$ 改變的常數。
**依據機率模型來建造分類器**
藉由上述獨立分佈的特徵模型,我們可以將此視為 Naive Bayes 的模型,並透過**最大事後機率(MAP)決策準則**,來建構分類器,如下
$$
\text{classify}(f_1, \dots, f_n) = \arg \max_c p(C = c) \prod \limits_{i=1}^n p(F_i = f_i \mid C = c)
$$
## Implementation
目前 `sklearn` 有提供以下種類的 Naive Bayes 套件:
- **Multinomial Naive Bayes**
預設特徵的先驗分佈為多項式分佈,此 Multinomial Naive Bayes 適用於具有離散特徵的分類
- **Gaussian Naive Bayes**
藉由假設先驗機率為高斯分佈,計算訓練資料的後驗機率
- **BernouliNB Naive Bayes**
與 Multinomial Naive Bayes 相同,可以用於離散型資料,但 BernouliNB Naive Bayes 是專為 Binary classification 設計
### Prepare data
這裡使用的是 [Spam email Dataset](https://www.kaggle.com/datasets/jackksoncsie/spam-email-dataset)
### Preprocessing
這裡會使用 [CountVectorizer](https://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.CountVectorizer.html) 將文本轉換為標記計數矩陣。
```python
from sklearn.feature_extraction.text import CountVectorizer
vectorizer=CountVectorizer()
spamham_countVectorizer=vectorizer.fit_transform(spam_dataframe['text'])
```
### Using Naive Bayes Classifier
由於是屬於離散型分類,這裡是用的是 `MultinomialNB`
```python
from sklearn.naive_bayes import MultinomialNB
NB_classifier=MultinomialNB()
NB_classifier.fit(X_train,y_train)
```
```python
y_predict_test=NB_classifier.predict(X_test)
y_predict_test
```
### Evaluation
透過 `classification_report` 我們可以計算出分類預測的準確率
```python
from sklearn.metrics import classification_report
print(classification_report(y_test,y_predict_test))
```
## From Scratch
在 From Scratch 的部分僅使用 `numpy`
由於預處理的結果是標記計數矩陣和詞彙列表,所以我們必須實做以下函式。
### preprocess_text
該函數用於對文本進行預處理。 它將刪除標點符號、停用詞,並將文本轉換為小寫。
```python
def preprocess_text(text):
text = text.lower()
text = re.sub(r'[^\w\s]', '', text)
tokens = text.split()
return ' '.join(tokens)
```
### build_vocabulary
該函數用於從文本中構建詞彙。 它將返回詞彙詞典。
```python
def build_vocabulary(texts):
vocabulary = set()
for text in texts:
tokens = text.split()
vocabulary.update(tokens)
return list(vocabulary)
```
### convert_text_to_vector
該函數用於將文本轉換為向量。 它將返回一個文本向量。
```python
def create_bow(texts, vocabulary):
bow_matrix = []
for text in texts:
tokens = text.split()
bow_vector = [tokens.count(word) for word in vocabulary]
bow_matrix.append(bow_vector)
return bow_matrix
```
### MultinomialNB
```python
class CustomMultinomialNB:
def __init__(self, alpha=1):
self.alpha = alpha
def fit(self, X, y):
self.X = X
self.y = y
self.classes = np.unique(y)
self.parameters = {}
for i, c in enumerate(self.classes):
X_c = X[np.where(y == c)]
self.parameters["phi_" + str(c)] = len(X_c) / len(X)
self.parameters["theta_" + str(c)] = (X_c.sum(axis=0) + self.alpha) / (np.sum(X_c.sum(axis=0) + self.alpha))
def predict(self, X):
predictions = []
for x in X:
phi_list = []
for i, c in enumerate(self.classes):
phi = np.log(self.parameters["phi_" + str(c)])
theta = np.sum(np.log(self.parameters["theta_" + str(c)]) * x)
phi_list.append(phi + theta)
predictions.append(self.classes[np.argmax(phi_list)])
return predictions
```
## More example
[Digit Recognizer](https://www.kaggle.com/competitions/digit-recognizer/overview)
## Reference
歡迎更仔細閱讀以下相關內容以了解本篇知識
- [【Python機器學習】110:簡單貝氏分類器介紹及其應用](https://medium.com/%E5%B1%95%E9%96%8B%E6%95%B8%E6%93%9A%E4%BA%BA%E7%94%9F/python%E6%A9%9F%E5%99%A8%E5%AD%B8%E7%BF%92-110-%E5%96%AE%E7%B4%94%E8%B2%9D%E6%B0%8F%E5%88%86%E9%A1%9E%E5%99%A8-50cdd9ce16f7)
- [[機器學習首部曲] 貝氏分類器 Bayesian Classifier](https://pyecontech.com/2020/02/27/bayesian_classifier/)
- [單純貝氏分類器](https://zh.wikipedia.org/zh-tw/%E6%9C%B4%E7%B4%A0%E8%B4%9D%E5%8F%B6%E6%96%AF%E5%88%86%E7%B1%BB%E5%99%A8)
- [一文详解朴素贝叶斯(Naive Bayes)原理](https://zhuanlan.zhihu.com/p/37575364)
- [Multinomial Naive Bayes / Gaussian Naive Bayes / BernouliNB Naive Bayes](https://blog.csdn.net/weixin_46649052/article/details/112508799)