日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

基于朴素贝叶斯的垃圾邮件分类-着重理解拉普拉斯变换

發布時間:2025/3/19 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于朴素贝叶斯的垃圾邮件分类-着重理解拉普拉斯变换 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1. 引言

在正式學習樸素貝葉斯之前,需要明確的是機器學習所要實現的是基于有限的訓練樣本集盡可能準確地估計出后驗概率P(c|x),即根據特征得到所屬類別的概率,首先引入兩個概念。
判別式模型(discriminative models):給定x,直接建模P(c|x)來預測c,比如決策樹、BP神經網絡、支持向量機等;
生成式模型(generative models):聯合概率分布P(x,c)進行建模,然后由此獲得p(c|x),典型代表就是下面要講的樸素貝葉斯。

2. 問題描述

本文基于樸素貝葉斯構建一個分類垃圾郵件的模型,研究對象是英文的垃圾郵件,一來英文垃圾郵件數據集比較容易找到比較多,二來難度較中文的稍小,并且很多人都在用英文郵件,可比性較強,適合新手入門。

3. 算法流程

A. 數據準備

a. 數據集使用 UCI Machine Learning Repository,已上傳至GitHub,可進行下載。
b. 訓練集中,positive郵件數量為12500,negative郵件數量為12500;測試集中,positive郵件數量和negative郵件數量同為12500。
c. 數據預處理。去除郵件中的特殊符號以及沒有任何意義的詞語,如一些html標簽或者"the"、"a"等詞語。具體方式為使用現成的停用詞表進行操作。

B. 理論依據

a. 貝葉斯定理

貝葉斯定理是該算法的核心思想。

?

貝葉斯定理

?

其中,P(c)是類先驗概率,p(x|c)是條件概率,p(x)是“證據因子”(在同一問題中p(x)全相同);
p(c)=類別c的數目/總數。
因此,求解p(c|x)的問題變成了求解p(x|c)的問題,接下來引出下面兩種解決方法。

b1. 極大似然估計(源自頻率主義學派)

試錯,此路不通。
假設p(x|c)具有確定的形式并且被參數向量θc唯一確定,則要利用訓練集估計θc的值,即p(x|c)-->p(x|θc)。
Frequentist:參數雖然未知,但是客觀存在的固定值。
Bayesian:參數是未觀察到的隨機變量,其本身也有分布。
若樣本Dc滿足獨立同分布,則參數θc對于數據集Dc的似然是

極大似然估計


注:使用對數似然的原因是避免連乘造成下溢。
這種參數化的方法的弊端是結果的準確性嚴重依賴于所假設的概率分布形式是否符合潛在的真實數據分布。下面就是貝葉斯的優越性了。

?

b2. 樸素貝葉斯分類器

樸素貝葉斯分類器(naive Bayes classifier)采用了屬性條件獨立性假設(attribute conditional independence assumption),即對于已知類別,假設所有的屬性都相互獨立(雖然這是不對的,但至少在垃圾郵件分類這里假設所有的屬性獨立取得了還不賴的結果)。換言之,假設所有屬性獨立地對分類結果發生影響。

樸素貝葉斯分類器


另外,為了避免進行計算時c類樣本的數量和在樣本中第i個屬性的取值為0導致p(c)或者p(x|c)為0,這里使用拉普拉斯修正(Laplacian correction),即

Laplace

?

C. 垃圾郵件實際問題

  • a. 建立詞匯表(之后可以創建TF-IDF詞匯表,現在僅僅簡化)
    統計郵件中出現的所有詞匯并記作一維向量的形式,即(abandon,ahead,buy,go,...,zero)。
def word_create(ori_data):#還沒有進行去停用詞的操作nltk.stopwoords的包沒能下載下來 # ori_data.data = [word for word in ori_data.data if(word not in stopwords.words('english'))]print("Vectorzing dataset ...")#建立一個集合列表word_dic = set([])#詞向量的時間vectorTime = time()#詞典的構造for doc in ori_data.data:#doc是byte,這里將byte轉化為stringdoc = str(doc, encoding = "utf-8")#使用正則表達式將特殊符號去除doc = re.sub("[\s+\.\!\/_,$%^*(+\"\'-]+|[+——!,。?、~@#¥%……&*()<>]+", " ", doc)#使用默認的空格方式將email分隔開,然后轉化為小寫字母,與原集合取并集word_dic = word_dic|set(doc.lower().split())#向量化的時間和詞典中詞的數量print("Vectorzing time:{0}\nThe number of word_dictionary:{1}".format(vectorTime,len(word_dic)))return list(word_dic)
  • b. 詞向量表示(之后使用Word2Vec表示詞向量,現在僅僅簡化)
    將每封郵件依據詞匯表以向量的形式表示出來,該詞在郵件中出現記為1,反之記為0,即比如(1,1,0,0,...,1)。
    無疑這會造成維數災難,Word2Vec會好很多,不過現在的計算量不是很大也不涉及其他算法就用one-hot方式表示了。
def doc_represent(wordDic,ori_data):#創建一個文檔數(行)*詞向量(列)長度的二維數組doc_re = numpy.zeros((len(ori_data.data),len(wordDic)),dtype= numpy.int)#計數器count = 0#用來記錄詞向量表示時間representTime = time()for doc in ori_data.data:#同word_create函數,進行同樣的操作doc = str(doc, encoding = "utf-8")doc = re.sub("[\s+\.\!\/_,$%^*(+\"\'-]+|[+——!,。?、~@#¥%……&*()<>]+", " ", doc)for word in doc.lower().split():if word in wordDic:#將對應詞向量位置置1doc_re[count][wordDic.index(word)] = 1count = count+1print("Represent doc time:{0}\nThe number of doc:{1}".format(representTime-time(),len(doc_re)))#返回表示文檔的二維數組return doc_re
  • c. 計算先驗概率p(c)
    p(正常郵件)=D(正常郵件數)+1/D(總郵件數)+2
    p(垃圾郵件)=D(垃圾郵件數)+1/D(總郵件數)+2
def pre_probabilty(ori_data):s_pre_pro = []#正常郵件的先驗概率P_normal = (normal + 1.0)/(len(ori_data.data) + 2.0)s_pre_pro.append(P_normal)#垃圾郵件的先驗概率P_spam = (spam + 1.0)/(len(ori_data.data) + 2.0)s_pre_pro.append(P_spam)#返回先驗概率的列表return s_pre_pro
  • d. 計算每個詞匯的條件概率
    p(abandon=1|正常郵件)=D(正常郵件中有abandon的數目)+1/D(正常郵件數)+2
    p(abandon=1|垃圾郵件)=D(垃圾郵件中有abandon的數目)+1/D(垃圾郵件數)+2
    p(ahead=1|正常郵件)=D(正常郵件中有ahead的數目)+1/D(正常郵件數)+2
    p(ahead=1|垃圾郵件)=D(垃圾郵件中有ahead的數目)+1/D(垃圾郵件數)+2
    ...
    p(zero=1|正常郵件)=D(正常郵件中有zer的數目)+1/D(正常郵件數)+2
    p(zero=1|垃圾郵件)=D(垃圾郵件中有zero的數目)+1/D(垃圾郵件數)+2
#計算每個詞在正常郵件垃圾郵件中的數目 def wordNum_email(email_repre,wordDic):#用二維向量存儲num_word = numpy.zeros((2,len(wordDic)),dtype= numpy.int)for i in range(len(wordDic)):#在正常郵件的數目for j in range(normal):num_word[0][i] += email_repre[j][i]#在垃圾郵件中的數目for j in range(normal, spam+normal):num_word[1][i] += email_repre[j][i]return num_word #條件概率 def con_probabilty(email_repre,wordDic):#得到每個詞匯在正常郵件、垃圾郵件中的數目word_num = wordNum_email(email_repre,wordDic)word_pro = numpy.zeros((2,len(wordDic)),dtype = numpy.double)for i in range(len(wordDic)):word_pro[0][i] = round((word_num[0][i]+1)/(normal + 2),8)word_pro[1][i] = round((word_num[1][i]+1)/(spam + 2 ),8)return word_pro
  • e. 測試
    p(email1=正常郵件)=p(正常郵件)p(zero|正常郵件)p(buy|正常郵件)p(achieve|正常郵件)=...
    p(email1=垃圾郵件)=p(垃圾郵件)p(zero|垃圾郵件)p(buy|垃圾郵件)p(achieve|垃圾郵件)=...
    若p(email1=正常郵件)>p(email1=垃圾郵件),則為正常郵件;
    若p(email1=正常郵件)<p(email1=垃圾郵件),則為垃圾郵件;
    若p(email1=正常郵件)=p(email1=垃圾郵件),則用一個隨機數隨機決定。

    將測試結果與實際結果進行比較,并記錄下分類正確和分類錯誤的數目,計算出TP、FP、FN和TN,最后得到準確率、精確率和召回率。如果有必要的話,畫出相應的圖進行說明。
    看到要計算準確率、精確率和召回率這里我表示很慚愧,只計算了準確率
#測試 def test_spam(test_repre,pre_pro,con_pro):email_pro = numpy.zeros((len(test_repre),2),dtype = numpy.double)email_judge = []normal_num = 0spam_num = 0for i in range(len(test_repre)):email_pro[i][0] = round(pre_pro[0],8)email_pro[i][1] = round(pre_pro[1],8)for j in range(len(test_repre[0])):if test_repre[i][j] != 0:email_pro[i][0] *= con_pro[0][j]email_pro[i][1] *= con_pro[1][j]if email_pro[i][0] > email_pro[i][1] :email_judge.append(0)elif email_pro[i][0] < email_pro[i][1] :email_judge.append(1)else :if random.random() > 0.5:email_judge.append(1)else:email_judge.append(0)for i in range(normal_test):if email_judge[i] == 0:normal_num +=1for i in range(normal_test,len(test_repre)):if email_judge[i] == 1:spam_num +=1print("email_judge\n")print(email_judge)print("normal_num="+str(normal_num)+"\nspam_num="+str(spam_num))return (normal_num + spam_num)/len(test_repre)

4.結論

由于諸多因素(設置閾值去除稀有詞匯,使用TF-IDF表示詞匯向量,使用log防止乘數下溢)沒有考慮,所以訓練大量的數據集時會導致內存不足的現象,故只使用了36個訓練數據進行訓練,使用36個測試數據測試準確率。最終準確率只有55.5%多,只比瞎猜的大了一點,個人覺得還是訓練集太少,再放大一點肯定還是會提升很多的。樸素貝葉斯的基本思想在這,這里我就不多改了,其他的問題之后注意,要進入下一個算法的學習了。在這里附上代碼地址,(樸素貝葉斯-spamClassification)[https://github.com/RuiDream/MachineLearning.git]
自己手寫的Bayes結果展示:

手寫Bayes結果


調包的結果展示(人家的很齊全,還有混淆矩陣,服):

庫中Bayes結果

?

庫中Bayes混淆矩陣

?

注:準確率相差這么大很大的一個原因是訓練集的大小不同,大的為25000,我自己寫的為36.。。不過還是要怪自己的代碼不精,革命剛剛起步……

?

總結

以上是生活随笔為你收集整理的基于朴素贝叶斯的垃圾邮件分类-着重理解拉普拉斯变换的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。