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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

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

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

1. 引言

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

2. 問(wèn)題描述

本文基于樸素貝葉斯構(gòu)建一個(gè)分類(lèi)垃圾郵件的模型,研究對(duì)象是英文的垃圾郵件,一來(lái)英文垃圾郵件數(shù)據(jù)集比較容易找到比較多,二來(lái)難度較中文的稍小,并且很多人都在用英文郵件,可比性較強(qiáng),適合新手入門(mén)。

3. 算法流程

A. 數(shù)據(jù)準(zhǔn)備

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

B. 理論依據(jù)

a. 貝葉斯定理

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

?

貝葉斯定理

?

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

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

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

極大似然估計(jì)


注:使用對(duì)數(shù)似然的原因是避免連乘造成下溢。
這種參數(shù)化的方法的弊端是結(jié)果的準(zhǔn)確性嚴(yán)重依賴(lài)于所假設(shè)的概率分布形式是否符合潛在的真實(shí)數(shù)據(jù)分布。下面就是貝葉斯的優(yōu)越性了。

?

b2. 樸素貝葉斯分類(lèi)器

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

樸素貝葉斯分類(lèi)器


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

Laplace

?

C. 垃圾郵件實(shí)際問(wèn)題

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

    將測(cè)試結(jié)果與實(shí)際結(jié)果進(jìn)行比較,并記錄下分類(lèi)正確和分類(lèi)錯(cuò)誤的數(shù)目,計(jì)算出TP、FP、FN和TN,最后得到準(zhǔn)確率、精確率和召回率。如果有必要的話,畫(huà)出相應(yīng)的圖進(jìn)行說(shuō)明。
    看到要計(jì)算準(zhǔn)確率、精確率和召回率這里我表示很慚愧,只計(jì)算了準(zhǔn)確率
#測(cè)試 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.結(jié)論

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

手寫(xiě)B(tài)ayes結(jié)果


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

庫(kù)中Bayes結(jié)果

?

庫(kù)中Bayes混淆矩陣

?

注:準(zhǔn)確率相差這么大很大的一個(gè)原因是訓(xùn)練集的大小不同,大的為25000,我自己寫(xiě)的為36.。。不過(guò)還是要怪自己的代碼不精,革命剛剛起步……

?

總結(jié)

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

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。