轉自 寒小陽html
1. 引言¶
貝葉斯方法是一個歷史悠久,有着堅實的理論基礎的方法,同時處理不少問題時直接而又高效,不少高級天然語言處理模型也能夠從它演化而來。所以,學習貝葉斯方法,是研究天然語言處理問題的一個很是好的切入口。python
2. 貝葉斯公式¶
貝葉斯公式就一行:web
P(Y|X)=P(X|Y)P(Y)P(X)
而它實際上是由如下的聯合機率公式推導出來:算法
P(Y,X)=P(Y|X)P(X)=P(X|Y)P(Y)
其中
P(Y)
叫作先驗機率,
P(Y|X)
叫作後驗機率,
P(Y,X)
叫作聯合機率。安全
沒了,貝葉斯最核心的公式就這麼些。網絡
3. 用機器學習的視角理解貝葉斯公式¶
在機器學習的視角下,咱們把
X
理解成「具備某特徵」,把
Y
理解成「類別標籤」(通常機器學習爲題中都是X=>特徵
, Y=>結果
對吧)。在最簡單的二分類問題(是
與否
斷定)下,咱們將
Y
理解成「屬於某類」的標籤。因而貝葉斯公式就變造成了下面的樣子:機器學習
P(「屬於某類」|「具有某特徵」)=P(「具有某特徵」|「屬於某類」)P(「屬於某類」)P(「具有某特徵」)
svg
咱們簡化解釋一下上述公式:函數
P(「屬於某類」|「具有某特徵」)=
在已知某樣本「具備某特徵」的條件下,該樣本「屬於某類」的機率。因此叫作『後驗機率』。
P(「具有某特徵」|「屬於某類」)=
在已知某樣本「屬於某類」的條件下,該樣本「具備某特徵」的機率。
P(「屬於某類」)=
(在未知某樣本具備該「具備某特徵」的條件下,)該樣本「屬於某類」的機率。因此叫作『先驗機率』。
P(「具有某特徵」)=
(在未知某樣本「屬於某類」的條件下,)該樣本「具備某特徵」的機率。
工具
而咱們二分類問題的最終目的就是要判斷
P(「屬於某類」|「具有某特徵」)
是否大於1/2就夠了。貝葉斯方法把計算「具備某特徵的條件下屬於某類」的機率轉換成須要計算「屬於某類的條件下具備某特徵」的機率,然後者獲取方法就簡單多了,咱們只須要找到一些包含已知特徵標籤的樣本,便可進行訓練。而樣本的類別標籤都是明確的,因此貝葉斯方法在機器學習裏屬於有監督學習方法。
這裏再補充一下,通常『先驗機率』、『後驗機率』是相對出現的,好比
P(Y)
與
P(Y|X)
是關於
Y
的先驗機率與後驗機率,
P(X)
與
P(X|Y)
是關於
X
的先驗機率與後驗機率。
4. 垃圾郵件識別¶
舉個例子好啦,咱們如今要對郵件進行分類,識別垃圾郵件和普通郵件,若是咱們選擇使用樸素貝葉斯分類器,那目標就是判斷
P(「垃圾郵件」|「具有某特徵」)
是否大於1/2。如今假設咱們有垃圾郵件和正常郵件各1萬封做爲訓練集。須要判斷如下這個郵件是否屬於垃圾郵件:
「我司可辦理正規發票(保真)17%增值稅發票點數優惠!」
也就是判斷機率
P(「垃圾郵件」|「我司可辦理正規發票(保真)17%增值稅發票點數優惠!」)
是否大於1/2。
咳咳,有木有發現,轉換成的這個機率,計算的方法:就是寫個計數器,而後+1 +1 +1統計出全部垃圾郵件和正常郵件中出現這句話的次數啊!!!好,具體點說:
P(「垃圾郵件」|「我司可辦理正規發票(保真)17%增值稅發票點數優惠!」)
=垃圾郵件中出現這句話的次數垃圾郵件中出現這句話的次數+正常郵件中出現這句話的次數
5. 分詞¶
一個很悲哀可是很現實的結論: 訓練集是有限的,而句子的可能性則是無限的。因此覆蓋全部句子可能性的訓練集是不存在的。
因此解決方法是? 句子的可能性無限,可是詞語就那麼些!!漢語經常使用字2500個,經常使用詞語也就56000個(你終於明白小學語文老師的用心良苦了)。按人們的經驗理解,兩句話意思相近並不強求非得每一個字、詞語都同樣。好比「我司可辦理正規發票,17%增值稅發票點數優惠!」,這句話就比以前那句話少了「(保真)」這個詞,可是意思基本同樣。若是把這些狀況也考慮進來,那樣本數量就會增長,這就方便咱們計算了。
因而,咱們能夠不拿句子做爲特徵,而是拿句子裏面的詞語(組合)做爲特徵去考慮。好比「正規發票」能夠做爲一個單獨的詞語,「增值稅」也能夠做爲一個單獨的詞語等等。
句子「我司可辦理正規發票,17%增值稅發票點數優惠!」就能夠變成(「我」,「司」,「可」,「辦理」,「正規發票」,「保真」,「增值稅」,「發票」,「點數」,「優惠」))。
因而你接觸到了中文NLP中,最最最重要的技術之一:分詞!!!也就是把一整句話拆分紅更細粒度的詞語來進行表示。另外,分詞以後去除標點符號、數字甚至無關成分(停用詞)是特徵預處理中的一項技術。
中文分詞是一個專門的技術領域(我不會告訴你某搜索引擎廠碼磚工有專門作分詞的!!!),上過以前課程的同窗都知道python有一個很是方便的分詞工具jieba,假定咱們已經完成分詞工做:
咱們觀察(「我」,「司」,「可」,「辦理」,「正規發票」,「保真」,「增值稅」,「發票」,「點數」,「優惠」),這能夠理解成一個向量:向量的每一維度都表示着該特徵詞在文本中的特定位置存在。這種將特徵拆分紅更小的單元,依據這些更靈活、更細粒度的特徵進行判斷的思惟方式,在天然語言處理與機器學習中都是很是常見又有效的。
所以貝葉斯公式就變成了:
P(「垃圾郵件」|(「我」,「司」,「可」,「辦理」,「正規發票」,「保真」,「增值稅」,「發票」,「點數」,「優惠」))
=P((「我」,「司」,「可」,「辦理」,「正規發票」,「保真」,「增值稅」,「發票」,「點數」,「優惠」)|"垃圾郵件")P(「垃圾郵件」)P((「我」,「司」,「可」,「辦理」,「正規發票」,「保真」,「增值稅」,「發票」,「點數」,「優惠」))
P(「正常郵件」|(「我」,「司」,「可」,「辦理」,「正規發票」,「保真」,「增值稅」,「發票」,「點數」,「優惠」))
=P((「我」,「司」,「可」,「辦理」,「正規發票」,「保真」,「增值稅」,「發票」,「點數」,「優惠」)|"正常郵件")P(「正常郵件」)P((「我」,「司」,「可」,「辦理」,「正規發票」,「保真」,「增值稅」,「發票」,「點數」,「優惠」))
6. 條件獨立假設¶
下面咱們立刻會看到一個很是簡單粗暴的假設。
機率
P((「我」,「司」,「可」,「辦理」,「正規發票」,「保真」,「增值稅」,「發票」,「點數」,「優惠」)|"垃圾郵件")
依舊不夠好求,咱們引進一個很樸素的近似。爲了讓公式顯得更加緊湊,咱們令字母S表示「垃圾郵件」,令字母H表示「正常郵件」。近似公式以下:
P((「我」,「司」,「可」,「辦理」,「正規發票」,「保真」,「增值稅」,「發票」,「點數」,「優惠」)|S)
=P(「我」|S)×P(「司」|S)×P(「可」|S)×P(「辦理」|S)×P(「正規發票」|S)
×P(「保真」|S)×P(「增值稅」|S)×P(「發票」|S)×P(「點數」|S)×P(「優惠」|S)
這就是傳說中的條件獨立假設。基於「正常郵件」的條件獨立假設的式子與上式相似,此處省去。接着,將條件獨立假設代入上面兩個相反事件的貝葉斯公式。
因而咱們就只須要比較如下兩個式子的大小:
C=P(「我」|S)P(「司」|S)P(「可」|S)P(「辦理」|S)P(「正規發票」|S)
×P(「保真」|S)P(「增值稅」|S)P(「發票」|S)P(「點數」|S)P(「優惠」|S)P(「垃圾郵件」)
C¯¯¯¯=P(「我」|H)P(「司」|H)P(「可」|H)P(「辦理」|H)P(「正規發票」|H)
×P(「保真」|H)P(「增值稅」|H)P(「發票」|H)P(「點數」|H)P(「優惠」|H)P(「正常郵件」)
厲(wo)害(cao)!醬紫處理後式子中的每一項都特別好求!只須要分別統計各種郵件中該關鍵詞出現的機率就能夠了!!!好比:
P(「發票」|S)=垃圾郵件中所有「發票」的次數垃圾郵件中所有詞語的次數
統計次數很是方便,並且樣本數量足夠大,算出來的機率比較接近真實。因而垃圾郵件識別的問題就可解了。
7. 樸素貝葉斯(Naive Bayes),「Naive」在何處?¶
加上條件獨立假設的貝葉斯方法就是樸素貝葉斯方法(Naive Bayes)。 Naive的發音是「乃一污」,意思是「樸素的」、「幼稚的」、「蠢蠢的」。咳咳,也就是說,大神們取名說該方法是一種比較萌蠢的方法,爲啥?
將句子(「我」,「司」,「可」,「辦理」,「正規發票」) 中的 (「我」,「司」)與(「正規發票」)調換一下順序,就變成了一個新的句子(「正規發票」,「可」,「辦理」, 「我」, 「司」)。新句子與舊句子的意思徹底不一樣。但因爲乘法交換律,樸素貝葉斯方法中算出來兩者的條件機率徹底同樣!計算過程以下:
P((「我」,「司」,「可」,「辦理」,「正規發票」)|S)
=P(「我」|S)P(「司」|S)P(「可」|S)P(「辦理」|S)P(「正規發票」|S)
=P(「正規發票」|S)P(「可」|S)P(「辦理」|S)P(「我」|S)P(「司」|S)
=P((「正規發票」,「可」,「辦理」,「我」,「司」)|S)
也就是說,在樸素貝葉斯眼裏,「我司可辦理正規發票」與「正規發票可辦理我司」徹底相同。樸素貝葉斯失去了詞語之間的順序信息。這就至關於把全部的詞彙扔進到一個袋子裏隨便攪和,貝葉斯都認爲它們同樣。所以這種狀況也稱做詞袋子模型(bag of words)。
![詞袋子配圖](http://static.javashuo.com/static/loading.gif)
詞袋子模型與人們的平常經驗徹底不一樣。好比,在條件獨立假設的狀況下,「武松打死了老虎」與「老虎打死了武松」被它認做一個意思了。恩,樸素貝葉斯就是這麼單純和直接,對比於其餘分類器,好像是顯得有那麼點萌蠢。
8. 簡單高效,吊絲逆襲¶
雖說樸素貝葉斯方法萌蠢萌蠢的,但實踐證實在垃圾郵件識別的應用還使人詫異地好。Paul Graham先生本身簡單作了一個樸素貝葉斯分類器,「1000封垃圾郵件可以被過濾掉995封,而且沒有一個誤判」。(Paul Graham《黑客與畫家》)
那個…效果爲啥好呢?
「有人對此提出了一個理論解釋,而且創建了何時樸素貝葉斯的效果可以等價於非樸素貝葉斯的充要條件,這個解釋的核心就是:有些獨立假設在各個分類之間的分佈都是均勻的因此對於似然的相對大小不產生影響;即使不是如此,也有很大的可能性各個獨立假設所產生的消極影響或積極影響互相抵消,最終致使結果受到的影響不大。具體的數學公式請參考這篇 paper。」(劉未鵬《:平凡而又神奇的貝葉斯方法》)
恩,這個分類器中最簡單直接看似萌蠢的小盆友『樸素貝葉斯』,實際上倒是簡單、實用、且強大的。
9. 處理重複詞語的三種方式¶
咱們以前的垃圾郵件向量(「我」,「司」,「可」,「辦理」,「正規發票」,「保真」,「增值稅」,「發票」,「點數」,「優惠」),其中每一個詞都不重複。而這在現實中其實不多見。由於若是文本長度增長,或者分詞方法改變,必然會有許多詞重複出現,所以須要對這種狀況進行進一步探討。好比如下這段郵件:
「代開發票。增值稅發票,正規發票。」 分詞後爲向量: (「代開」,「發票」,「增值稅」,「發票」,「正規」,「發票」)
其中「發票」重複了三次。
9.1 多項式模型:¶
若是咱們考慮重複詞語的狀況,也就是說,重複的詞語咱們視爲其出現屢次,直接按條件獨立假設的方式推導,則有
P((「代開」,「發票」,「增值稅」,「發票」,「正規」,「發票」)|S)
=P(「代開」」|S)P(「發票」|S)P(「增值稅」|S)P(「發票」|S)P(「正規」|S)P(「發票」|S)
=P(「代開」」|S)P3(「發票」|S)P(「增值稅」|S)P(「正規」|S)
注意這一項:
P3(「發票」|S)
。
在統計計算P(「發票」|S)時,每一個被統計的垃圾郵件樣本中重複的詞語也統計屢次。
P(「發票」|S)=每封垃圾郵件中出現「發票」的次數的總和每封垃圾郵件中所有詞出現次數(計算重復次數)的總和
你看這個屢次出現的結果,出如今機率的指數/次方上,所以這樣的模型叫做多項式模型。
9.2 伯努利模型¶
另外一種更加簡化的方法是將重複的詞語都視爲其只出現1次,
P((「代開」,「發票」,「增值稅」,「發票」,「正規」,「發票」)|S)
=P(「發票」|S)P(「代開」」|S)P(「增值稅」|S)P(「正規」|S)
統計計算
P(「詞語」|S)
時也是如此。
P(「發票」|S)=出現「發票」的垃圾郵件的封數每封垃圾郵件中所有詞出現次數(出現了只計算一次)的總和
這樣的模型叫做伯努利模型(又稱爲二項獨立模型)。這種方式更加簡化與方便。固然它丟失了詞頻的信息,所以效果可能會差一些。
9.3 混合模型¶
第三種方式是在計算句子機率時,不考慮重複詞語出現的次數,可是在統計計算詞語的機率P(「詞語」|S)時,卻考慮重複詞語的出現次數,這樣的模型能夠叫做混合模型。
咱們經過下圖展現三種模型的關係。
![三種形態](http://static.javashuo.com/static/loading.gif)
具體實踐中採用那種模型,關鍵看具體的業務場景,一個簡單經驗是,對於垃圾郵件識別,混合模型更好些。
10. 去除停用詞與選擇關鍵詞¶
咱們繼續觀察(「我」,「司」,「可」,「辦理」,「正規發票」,「保真」,「增值稅」,「發票」,「點數」,「優惠」) 這句話。其實,像「我」、「可」之類詞其實很是中性,不管其是否出如今垃圾郵件中都沒法幫助判斷的有用信息。因此能夠直接不考慮這些典型的詞。這些無助於咱們分類的詞語叫做「停用詞」(Stop Words)。這樣能夠減小咱們訓練模型、判斷分類的時間。 因而以前的句子就變成了(「司」,「辦理」,「正規發票」,「保真」,「增值稅」,「發票」,「點數」,「優惠」) 。
咱們進一步分析。以人類的經驗,其實「正規發票」、「發票」這類的詞若是出現的話,郵件做爲垃圾郵件的機率很是大,能夠做爲咱們區分垃圾郵件的「關鍵詞」。而像「司」、「辦理」、「優惠」這類的詞則有點雞肋,可能有助於分類,但又不那麼強烈。若是想省事作個簡單的分類器的話,則能夠直接採用「關鍵詞」進行統計與判斷,剩下的詞就能夠先無論了。因而以前的垃圾郵件句子就變成了(「正規發票」,「發票」) 。這樣就更加減小了咱們訓練模型、判斷分類的時間,速度很是快。
「停用詞」和「關鍵詞」通常均可以提早靠人工經驗指定。不一樣的「停用詞」和「關鍵詞」訓練出來的分類器的效果也會有些差別。
11. 淺談平滑技術¶
咱們來講個問題(中文NLP裏問題超級多,哭瞎T_T),好比在計算如下獨立條件假設的機率:
P((「我」,「司」,「可」,「辦理」,「正規發票」)|S)
=P(「我」|S)P(「司」|S)P(「可」|S)P(「辦理」|S)P(「正規發票」|S)
咱們掃描一下訓練集,發現「正規發票」這個詞從出現過!!!*,因而
P(「正規發票」|S)=0
…問題嚴重了,整個機率都變成0了!!!樸素貝葉斯方法面對一堆0,很悽慘地失效了…更殘酷的是這種狀況其實很常見,由於哪怕訓練集再大,也可能有覆蓋不到的詞語。本質上仍是樣本數量太少,不知足大數定律,計算出來的機率失真**。爲了解決這樣的問題,一種分析思路就是直接不考慮這樣的詞語,但這種方法就至關於默認給P(「正規發票」|S)賦值爲1。其實效果不太好,大量的統計信息給浪費掉了。咱們進一步分析,既然能夠默認賦值爲1,爲何不能默認賦值爲一個很小的數?這就是平滑技術的基本思路,依舊保持着一向的做風,樸實/土
可是直接而有效
。
對於伯努利模型,P(「正規發票」|S)的一種平滑算法是:
P(「正規發票」|S)=出現「正規發票」的垃圾郵件的封數+1每封垃圾郵件中所有詞出現次數(出現了只計算一次)的總和+2
對於多項式模型,P(「正規發票」| S)的一種平滑算法是:
P(「發票」|S)=每封垃圾郵件中出現「發票」的次數的總和+1每封垃圾郵件中所有詞出現次數(計算重復次數)的總和+被統計的詞表的詞語數量
提及來,平滑技術的種類其實很是多,有興趣的話回頭咱們專門拉個專題講講好了。這裏只提一點,就是全部的平滑技術都是給未出如今訓練集中的詞語一個估計的機率,而相應地調低其餘已經出現的詞語的機率。
平滑技術是由於數據集過小而產生的現實需求。若是數據集足夠大,平滑技術對結果的影響將會變小。
12. 內容小結¶
咱們找了個最簡單常見的例子:垃圾郵件識別,說明了一下樸素貝葉斯進行文本分類的思路過程。基本思路是先區分好訓練集與測試集,對文本集合進行分詞、去除標點符號等特徵預處理的操做,而後使用條件獨立假設,將原機率轉換成詞機率乘積,再進行後續的處理。
貝葉斯公式 + 條件獨立假設 = 樸素貝葉斯方法
基於對重複詞語在訓練階段與判斷(測試)階段的三種不一樣處理方式,咱們相應的有伯努利模型、多項式模型和混合模型。在訓練階段,若是樣本集合過小致使某些詞語並未出現,咱們能夠採用平滑技術對其機率給一個估計值。並且並非全部的詞語都須要統計,咱們能夠按相應的「停用詞」和「關鍵詞」對模型進行進一步簡化,提升訓練和判斷速度。
13. 爲何不直接匹配關鍵詞來識別垃圾郵件?¶
有同窗可能會問:「何須費這麼大勁算那麼多詞的機率?直接看郵件中有沒有‘代開發票’、‘轉售發票’之類的關鍵詞不就得了?若是關鍵詞比較多就認爲是垃圾郵件唄。」
其實關鍵詞匹配的方法若是有效的話真沒必要用樸素貝葉斯。畢竟這種方法簡單嘛,就是一個字符串匹配。從歷史來看,以前沒有貝葉斯方法的時候主要也是用關鍵詞匹配。可是這種方法準確率過低。咱們在工做項目中也嘗試過用關鍵詞匹配的方法去進行文本分類,發現大量誤報。感受就像扔到垃圾箱的郵件99%都是正常的!這樣的效果不忍直視。而加一個樸素貝葉斯方法就可能把誤報率拉低近一個數量級,體驗好得不要不要的。
另外一個緣由是詞語會隨着時間不斷變化。發垃圾郵件的人也不傻,當他們發現本身的郵件被大量屏蔽以後,也會考慮採用新的方式,如變換文字、詞語、句式、顏色等方式來繞過反垃圾郵件系統。好比對於垃圾郵件「我司可辦理正規發票,17%增值稅發票點數優惠」,他們採用火星文:「涐司岢辦理㊣規髮票,17%增値稅髮票嚸數優蕙」,那麼字符串匹配的方法又要從新找出這些火星文,一個一個找出關鍵詞,從新寫一些匹配規則。更可怕的是,這些規則可能相互之間的耦合關係異常複雜,要把它們梳理清楚又是大一個數量級的工做量。等這些規則失效了又要手動更新新的規則……無窮無盡貓鼠遊戲最終會把貓給累死。
而樸素貝葉斯方法卻顯示出無比的優點。由於它是基於統計方法的,只要訓練樣本中有更新的垃圾郵件的新詞語,哪怕它們是火星文,都能自動地把哪些更敏感的詞語(如「髮」、「㊣」等)給凸顯出來,並根據統計意義上的敏感性給他們分配適當的權重 ,這樣就不須要什麼人工了,很是省事。你只須要時不時地拿一些最新的樣本扔到訓練集中,從新訓練一次便可。
小補充一下,對於火星文、同音字等替代語言,通常的分詞技術可能會分得不許,最終可能只把一個一個字給分出來,成爲「分字」。效果可能不會太好。也能夠用過n-gram之類的語言模型,拿到最多見短語。固然,對於英文等天生自帶空格來間隔單詞的語言,分詞則不是什麼問題,使用樸素貝葉斯方法將會更加順暢。
14.實際工程的tricks¶
應用樸素貝葉斯方法的過程當中,一些tricks能顯著幫助工程解決問題。咱們畢竟經驗有限,沒法將它們全都羅列出來,只能就所知的一點點經驗與你們分享,歡迎批評指正。
14.1 trick1:取對數¶
咱們提到用來識別垃圾郵件的方法是比較如下兩個機率的大小(字母S表示「垃圾郵件」,字母H表示「正常郵件」):
C=P(「我」|S)P(「司」|S)P(「可」|S)P(「辦理」|S)P(「正規發票」|S)
×P(「保真」|S)P(「增值稅」|S)P(「發票」|S)P(「點數」|S)P(「優惠」|S)P(「垃圾郵件」)
C¯¯¯¯=P(「我」|H)P(「司」|H)P(「可」|H)P(「辦理」|H)P(「正規發票」|H)
×P(「保真」|H)P(「增值稅」|H)P(「發票」|H)P(「點數」|H)P(「優惠」|H)P(「正常郵件」)
但這裏進行了不少乘法運算,計算的時間開銷比較大。尤爲是對於篇幅比較長的郵件,幾萬個數相乘起來仍是很是花時間的。若是能把這些乘法變成加法則方便得多。恰好數學中的對數函數log就能夠實現這樣的功能。兩邊同時取對數(本文統一取底數爲2),則上面的公式變爲:
logC=logP(「我」|S)+logP(「司」|S)+logP(「可」|S)+logP(「辦理」|S)+logP(「正規發票」|S)
+logP(「保真」|S)+logP(「增值稅」|S)+logP(「發票」|S)+logP(「點數」|S)+logP(「優惠」|S)+logP(「垃圾郵件」)
logC¯¯¯¯=logP(「我」|H)+logP(「司」|H)+logP(「可」|H)+logP(「辦理」|H)+logP(「正規發票」|H)
+logP(「保真」|H)+logP(「增值稅」|H)+logP(「發票」|H)+logP(「點數」|H)+logP(「優惠」|H)+logP(「正常郵件」)
有同窗可能要叫了:「作對數運算豈不會也很花時間?」的確如此,可是能夠在訓練階段直接計算
logP
,而後把他們存在一張大的hash表裏。在判斷的時候直接提取hash表中已經計算好的對數機率,而後相加便可。這樣使得判斷所須要的計算時間被轉移到了訓練階段,實時運行的時候速度就比以前快得多,這可不止幾個數量級的提高。
14.2 trick2:轉換爲權重¶
對於二分類,咱們還能夠繼續提升判斷的速度。既然要比較
logC
和
logC¯¯¯¯
的大小,那就能夠直接將上下兩式相減,並繼續化簡:
logCC¯¯¯¯=logP(「我」|S)P(「我」|H)+logP(「司」|S)P(「司」|H)+logP(「可」|S)P(「可」|H)+logP(「辦理」|S)P(「辦理」|H)+logP(「正規發票」|S)P(「正規發票」|H)
+logP(「保真」|S)P(「保真」|H)+logP(「增值稅」|S)P(「增值稅」|H)+logP(「發票」|S)P(「發票」|H)+logP(「點數」|S)P(「點數」|H)+logP(「優惠」|S)P(「優惠」|H)+logP(「正常郵件」|S)P(「正常郵件」)
logCC¯¯¯¯
若是大於0則屬於垃圾郵件。咱們能夠把其中每一項做爲其對應詞語的權重,好比
logP(「發票」|S)P(「發票」|H)
就能夠做爲詞語「發票」的權重,權重越大就越說明「發票」更多是與「垃圾郵件」相關的特徵。這樣能夠根據權重的大小來評估和篩選顯著的特徵,好比關鍵詞。而這些權重值能夠直接提早計算好而存在hash表中 。判斷的時候直接將權重求和便可。
關鍵詞hash表的樣子以下,左列是權重,右列是其對應的詞語,權重越高的說明越「關鍵」:
![hash](http://static.javashuo.com/static/loading.gif)
14.3 trick3:選取topk的關鍵詞¶
前文說過能夠經過提早選取關鍵詞來提升判斷的速度。有一種方法能夠省略提早選取關鍵詞的步驟,就是直接選取一段文本中權重最高的K個詞語,將其權重進行加和。好比Paul Graham 在《黑客與畫家》中是選取郵件中權重最高的15個詞語計算的。
經過權重hash表可知,若是是全部詞語的權重,則權重有正有負。若是隻選擇權重最高的K個詞語,則它們的權重基本都是正的。因此就不能像以前那樣判斷
logCC¯¯¯¯
是否大於0來區分郵件了。而這須要依靠經驗選定一個正數的閾值(門檻值) ,依據
logCC¯¯¯¯
與該門檻值的大小來識別垃圾郵件。
以下圖所示,藍色點表明垃圾郵件,綠色點表明正常郵件,橫座標爲計算出來的
logCC¯¯¯¯
值,中間的紅線表明閾值。
![權重](http://static.javashuo.com/static/loading.gif)
14.4 trick4:分割樣本¶
選取topk個詞語的方法對於篇幅變更不大的郵件樣本比較有效。可是對篇幅過大或者太小的郵件則會有判斷偏差。
好比這個垃圾郵件的例子:(「我」,「司」,「可」,「辦理」,「正規發票」,「保真」,「增值稅」,「發票」,「點數」,「優惠」)。分詞出了10個詞語,其中有「正規發票」、「發票」2個關鍵詞。關鍵詞的密度仍是蠻大的,應該算是敏感郵件。但由於採用最高15個詞語的權重求和,而且相應的閾值是基於15個詞的狀況有效,可能算出來的結果還小於以前的閾值,這就形成漏判了。
相似的,若是一封稅務主題的郵件有1000個詞語,其中只有「正規發票」、「發票」、「避稅方法」3個權重比較大的詞語,它們只是在正文表述中順帶提到的內容。關鍵詞的密度被較長的篇幅稀釋了,應該算是正常郵件。可是卻被閾值判斷成敏感郵件,形成誤判了。
這兩種狀況都說明topk關鍵詞的方法須要考慮篇幅的影響。這裏有許多種處理方式,它們的基本思想都是選取詞語的個數及對應的閾值要與篇幅的大小成正比,本文只介紹其中一種方方法:
對於長篇幅郵件,按必定的大小,好比每500字,將其分割成小的文本段落,再對小文本段落採用topk關鍵詞的方法。只要其中有一個小文本段落超過閾值就判斷整封郵件是垃圾郵件。
對於超短篇幅郵件,好比50字,能夠按篇幅與標準比較篇幅的比例來選取topk,以肯定應該匹配關鍵詞語的個數。好比選取
50500×15≈2
個詞語進行匹配,相應的閾值能夠是以前閾值的
215
。以此來判斷則更合理。
14.5 trick5:位置權重¶
到目前爲止,咱們對詞語權重求和的過程都沒有考慮郵件篇章結構的因素。好比「正規發票」若是出如今標題中應該比它出如今正文中對判斷整個郵件的影響更大;而出如今段首句中又比其出如今段落正文中對判斷整個郵件的影響更大。因此能夠根據詞語出現的位置,對其權重再乘以一個放大係數,以擴大其對整封郵件的影響,提升識別準確度。
好比一封郵件其標題是「正規發票」(假設標題的放大係數爲2),段首句是「發票」,「點數」,「優惠」(假設段首的放大係數爲1.5),剩下的句子是(「我」,「司」,「可」,「辦理」,「保真」)。則計算
logCC¯¯¯¯
時的公式就能夠調整爲:
logCC¯¯¯¯=2×logP(「正規發票」|S)P(「正規發票」|H)+1.5×logP(「發票」|S)P(「發票」|H)+1.5×logP(「點數」|S)P(「點數」|H)+1.5×logP(「優惠」|S)P(「優惠」|H)
+logP(「我」|S)P(「我」|H)+logP(「司」|S)P(「司」|H)+logP(「可」|S)P(「可」|H)+logP(「辦理」|S)P(「辦理」|H)+logP(「保真」|S)P(「保真」|H)+logP(「正常郵件」|S)P(「正常郵件」)