高斯朴素貝葉斯(Gaussian Naive Bayes)原理與實現——垃圾郵件識別實戰


朴素貝葉斯(Naive Bayes):

根據貝葉斯定理和朴素假設提出的朴素貝葉斯模型。

貝葉斯定理:

 朴素假設(特征條件獨立性假設):

代入可知朴素貝葉斯模型計算公式:

 

因為朴素貝葉斯是用來分類任務,因此:

 

化簡可知:

 

 

朴素貝葉斯模型除了上式所描述的以外,有三種常用的模型:

1、高斯朴素貝葉斯

2、多項式朴素貝葉斯

3、伯努利朴素貝葉斯

本篇主要是實現高斯朴素貝葉斯,因為它是最常用的一種模型。

高斯朴素貝葉斯:

適用於連續變量,其假定各個特征 𝑥_𝑖 在各個類別𝑦下是服從正態分布的,算法內部使用正態分布的概率密度函數來計算概率。

 

 𝜇_𝑦:在類別為𝑦的樣本中,特征𝑥_𝑖的均值

𝜎_𝑦:在類別為𝑦的樣本中,特征𝑥_𝑖的標准差

高斯朴素貝葉斯代碼實現:

注釋:

1、var_smoothing和epsilon的目的是防止一些特征的方差為0的情況(比如在垃圾郵件識別的時候,使用詞袋模型很容易出現方差為0)

2、計算聯合概率時並不使用連乘,對概率取自然對數,乘法變加法,降低計算復雜度,使模型更穩定。

 1 import numpy as np
 2 import collections
 3 import math
 4 class GaussianNB(object):
 5     def __init__(self):
 6         self.mp = {} #把y值映射到0-n之間的整數
 7         self.n_class = None #類別數
 8         self.class_prior= None #先驗概率P(Y)
 9         self.means = None #均值
10         self.vars = None  #方差
11         self.var_smoothing =1e-9 #平滑因子
12         self.epsilon = None #平滑值
13     def _get_class_prior(self,y):
14         cnt = collections.Counter(y)
15         self.n_class = 0
16         for k,v in cnt.items():
17             self.mp[k] = self.n_class
18             self.n_class+=1
19         self.class_prior = np.array([ v/len(y) for k,v in cnt.items()])
20         pass
21     def _get_means(self,xx,y):
22         new_y =np.array([self.mp[i] for i in y])
23         self.means = np.array([ xx[new_y==id].mean(axis=0) for id in range(self.n_class)])
24         # self.means shape: n_class * dims
25         pass
26     def _get_vars(self,xx,y):
27         new_y = np.array([self.mp[i] for i in y])
28         self.vars = np.array([xx[new_y == id].var(axis=0) for id in range(self.n_class)])
29         # self.vars shape: n_class * dims
30         pass
31     def fit(self,X,Y):
32         # X 必須是numpy的array; Y為list,對於X中每個樣本的類別
33         self._get_class_prior(Y)
34         self._get_means(X,Y)
35         self._get_vars(X,Y)
36         self.epsilon = self.var_smoothing * self.vars.max() #選取特征中最大的方差作為平滑
37         self.vars = self.vars + self.epsilon #給所有方差加上平滑的值
38         pass
39     def _get_gaussian(self,x,u,var):
40         #計算在類別y下x的條件概率P(xj|y)的對數
41         #return math.log(1 / math.sqrt(2 * math.pi * var) * math.exp(-(x - u) ** 2 / (2 * var)))
42         return -(x - u) ** 2 / (2 * var) - math.log(math.sqrt(2 * math.pi * var))
43     def predict(self,x):
44         dims = len(x)
45         likelihoods = []
46         for id in range(self.n_class): #遍歷每類yi,把每個特征的條件概率P(xj|yi)累加
47             likelihoods.append(np.sum([self._get_gaussian(x[j], self.means[id][j], self.vars[id][j]) for j in range(dims)]))
48         # 對先驗概率取對數
49         log_class_prior = np.log(self.class_prior)
50         all_pros = log_class_prior + likelihoods
51         #all_pros = self.standardization(all_pros)
52         max_id = all_pros.argmax() #取概率最大的類別的下標
53         for k,v in self.mp.items(): #轉換為可讀的y值
54             if v== max_id:
55                 return k
56         pass
57     def standardization(self,x):
58         mu = np.mean(x)
59         sigma = np.std(x)
60         return (x - mu) / sigma
61 
62 # nb = GaussianNB()
63 # xx = np.array([[1,2,3],[11,12,1],[2,1,4],[15,16,1],[8,6,6],[19,13,0]])
64 # y = ['min','max','min','max','min','max']
65 # nb.fit(xx,y)
66 # print(nb.predict(np.array([0,0,0])))
View Code

垃圾郵件識別實戰:

數據集:Trec06C數據集

 

筆者獲取的數據集是處理過的

處理方式:隨機選取:5000封垃圾郵件和5000封正常郵件;

預處理提取郵件正文,去掉換行符、多余空格等UTF-8文本格式,每封郵件正文在文件中保存為一行文本其中前5000 條為垃圾郵件,后5000 條為正常郵件。

 

特征提取:使用詞袋模型進行特征提取(特征維度33453)

模型訓練:模型訓練和驗證將數據集隨機切分為訓練集和測試集(40%);使用GaussianNB高斯貝葉斯進行訓練。

實驗結果:在測試集上准確率達到了97.95%,效果還是不錯的

 

 實驗代碼:

注釋:代碼跑起來比較慢,主要是因為預測的函數並不是將所有的句子一起預測,而是一句一句預測了。最近沒啥空改這個,等下次需要的時候再更新吧。

 1 import numpy as np  2 import jieba  3 from sklearn.feature_extraction.text import CountVectorizer  4 from sklearn import model_selection, metrics  5 from GaussianNB import GaussianNB  6 file_path = 'email.txt'
 7 file = open(file_path,encoding='utf-8')  8 data = file.readlines()  9 y = ['Spam']*5000+['Normal mail']*5000
10 split_data = [] 11 for line in data: 12     split_data.append(' '.join(jieba.lcut(line))) 13 print(split_data[-1]) 14 #僅保留長度至少為2個漢字的詞
15 cv = CountVectorizer(token_pattern=r"(?u)\b\w\w+\b") 16 xx = cv.fit_transform(split_data).toarray() 17 print(xx.shape) 18 
19 x_train, x_test, y_train, y_test =  model_selection.train_test_split(xx,y,test_size=0.4) 20 gnb = GaussianNB() 21 gnb.fit(x_train,y_train) 22 y_pre  =[] 23 for x in x_test: 24  y_pre.append(gnb.predict(x)) 25 print(metrics.accuracy_score(y_test,y_pre)) 26 print (metrics.confusion_matrix(y_test, y_pre))
View Code

 

參考資料:

1、《統計學習方法(第二版)》——李航

2、https://zhuanlan.zhihu.com/p/64498790

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM