<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)