天天看點

手把手教你用 python 和 scikit-learn 實作垃圾郵件過濾

文本挖掘(text mining,從文字中擷取資訊)是一個比較寬泛的概念,這一技術在如今每天都有海量文本資料生成的時代越來越受到關注。目前,在機器學習模型的幫助下,包括情緒分析,檔案分類,話題分類,文本總結,機器翻譯等在内的諸多文本挖掘應用都已經實作了自動化。

在這些應用中,垃圾郵件過濾算是初學者實踐檔案分類的一個很不錯的開始,例如 gmail 賬戶裡的“垃圾郵箱”就是一個垃圾郵件過濾的現實應用。下面我們将基于一份公開的郵件資料集 ling-spam,編寫一個垃圾郵件的過濾器。ling-spam 資料集的下載下傳位址如下:

<a href="http://t.cn/rkqbl9c" target="_blank">http://t.cn/rkqbl9c</a>

這裡我們已經從 ling-spam 中提取了相同數量的垃圾郵件和非垃圾郵件,具體下載下傳位址如下:

<a href="http://t.cn/rkqbkru" target="_blank">http://t.cn/rkqbkru</a>

下面我們将通過以下幾個步驟,編寫一個現實可用的垃圾郵件過濾器。

1. 準備文本資料; 2. 建立詞典(word dictionary); 3. 特征提取; 4. 訓練分類器。

最後,我們會通過一個測試資料集對過濾器進行驗證。

這裡我們将資料集分成了訓練集(702封郵件)和測試集(260封郵件)兩部分,其中垃圾和非垃圾郵件各占 50%。這裡因為每個垃圾郵件的資料集都以 spmsg 命名,是以很容易區分。

在大部分的文本挖掘問題中,文本清理都是第一步,即首先要清理掉那些與我們的目标資訊無關的詞句,本例中也一樣。通常郵件裡一般都會包含很多無用的字元,比如标點符号,停用詞,數字等等,這些字元對檢測垃圾郵件沒什麼幫助,是以我們需要将它們清理掉。這裡 ling-spam 資料集裡的郵件已經經過了以下幾個步驟的處理:

a) 清除停用詞 --- 像 "and", "the", "of" 等這些停用詞在英語語句中非常常見。然而,這些停用詞對于判定郵件的真實身份并沒有什麼卵用,是以這些詞已經從郵件中被移除。

b) 詞形還原 --- 這是一種把同一個詞的不同形式組合在一起,以便被當做一個單獨項目來分析的過程。舉個栗子,"include", "includes" 和 "included" 就可以全部用 "include" 來代表。與此同時,語句的上下文含義也會通過詞形還原的方法保留下來,這一點不同于詞幹提取 (stemming) 的方法(注:詞幹提取是另一種文本挖掘的方法,此法不考慮語句的含義)。

此外,我們還需要移除一些非文字類的符号(non-words),比如标點符号或者特殊字元之類的。要實作這一步有很多方法,這裡,我們将首先建立一個詞典(creating a dictionary),之後再移除這些非文字類的符号。需要指出的是,這種做法其實非常友善,因為當你手上有了一個詞典之後,對于每一種非文字類符号,隻需要移除一次就 ok 了。

一個資料集裡的樣本郵件一般長這樣:

你會發現郵件的第一行是标題,從第三行開始才是正文。這裡我們隻在郵件正文内容的基礎上做文本分析,來判定該郵件是否為垃圾郵件。第一步,我們需要建立一個文字的詞典和文字出現的頻率。為了建立這樣一個“詞典”,這裡我們利用了訓練集裡的 700 封郵件。具體實作詳見下面這個 python 函數:

詞典建立好之後,我們隻要在上面函數的基礎上再加幾行代碼,就可以移除之前提到的那些非文字類符号了。這裡我還順手删掉了一些與垃圾郵件的判定無關的單字元,具體參見如下的代碼,注意這些代碼要附在 def make_dictionary(train_dir) 函數的末尾。

這裡通過輸入 print dictionary 指令就可以輸出詞典。需要注意的是,你在列印輸出的詞典裡可能會看到許多無關緊要的詞,這一點無需擔心,因為我們在後續的步驟中總是有機會對其進行調整的。另外,如果你是嚴格按照上文提到的資料集操作的話,那麼你的詞典裡應該會有以下這些高頻詞(本例中我們選取了頻率最高的 3000 個詞):

[('order', 1414), ('address', 1293), ('report', 1216), ('mail', 1127), ('send', 1079), ('language', 1072), ('email', 1051), ('program', 1001), ('our', 987), ('list', 935), ('one', 917), ('name', 878), ('receive', 826), ('money', 788), ('free', 762)

詞典準備好之後,我們就可以對訓練集裡的每一封郵件提取次元是 3000 的詞數向量 word count vector(這個向量就是我們的特征),每一個詞數向量都包含之前標明的 3000 個高頻詞具體的出現頻率。當然,你可能猜到了,大部分出現的頻率應該會是 0。舉個栗子:比如我們字典裡有 500 個詞,每個詞數向量包含了訓練集裡這 500 個詞的出現頻率。假設訓練集有一組文本:“get the work done, work done”。那麼,這句話對應的詞數向量應該是這樣的:[0,0,0,0,0,…….0,0,2,0,0,0,……,0,0,1,0,0,…0,0,1,0,0,……2,0,0,0,0,0]。在這裡,句中的每個詞出現的頻率都能顯示出來:這些詞分别對應長度為 500 的詞數向量中的第 296,359,415 和 495 的位置,其他位置顯示為 0。

下面這個 python 函數會幫助我們生成一個特征向量矩陣,該矩陣有 700 行 3000 列。其中每一行代表訓練集中 700 封郵件的的每一封郵件,每一列代表詞典中的 3000 個關鍵詞。在 “ij” 位置上的值代表了詞典中第 j 個詞在該郵件(第 i 封)中出現的次數。

在這裡我們會使用 scikit-learn 機器學習庫來訓練分類器,scikit-learn 庫的相關連結如下:

<a href="http://t.cn/smzaoz" target="_blank">http://t.cn/smzaoz</a>

這是一個綁定在第三方 python 發行版 anaconda 的開源機器學習庫,可以跟随 anaconda 一同下載下傳安裝,或者也可以按照以下連結中的提示獨立安裝:

<a href="http://t.cn/8kkrvlq" target="_blank">http://t.cn/8kkrvlq</a>

安裝好了之後,我們隻需要将其 import 到我們的程式中就可以使用了。

這裡我們訓練了兩個模型,分别是樸素貝葉斯分類器和 svm(支援向量機)。樸素貝葉斯分類器是一個傳統的監督型機率分類器,在文本分類的場景中非常常用,它基于貝葉斯定理,假設每一對特征都是互相獨立的。svm 是監督型的二分類器,面對特征數量較多的場景時非常有效,其最終目标是從訓練資料中分離出一組子集,稱為支援向量(分離超平面的邊界)。判定測試資料最終類别的 svm 決策函數正是基于該支援向量和核心技巧(kernel trick)的。

分類器訓練完成後,我們可以在測試集上測試模型的性能。這裡我們為測試集中的每封郵件提取字數向量,然後用訓練好的樸素貝葉斯分類器和 svm 模型,預測它的類别(普通郵件或垃圾郵件)。下面是垃圾郵件分類器的完整 python 代碼,另外還需要包含我們在步驟 2 和步驟 3 中定義的兩個函數。

這裡我們的測試集中包含 130 封垃圾郵件和 130 封非垃圾郵件,如果你已經順利完成了之前的所有步驟,那麼你将會得到如下的結果。這裡顯示的是兩個模型在測試資料中的混淆矩陣,對角元素代表了正确識别的郵件數,非對角元素代表的則是錯誤的分類。

手把手教你用 python 和 scikit-learn 實作垃圾郵件過濾

可以看到,兩個模型在測試集上有着相近的性能,但 svm 更傾向垃圾郵件的判定。需要注意的是,這裡的測試資料集既沒有用于建立字典,也沒有用于模型訓練。

感興趣的朋友可以按照上文所述的步驟進行一些拓展,這裡介紹拓展相關的資料庫和結果。

拓展使用的是已經預處理好的 euron-spam 資料庫,其中包含了 6 個目錄,33716 封郵件,每個目錄中都包含非垃圾郵件和垃圾郵件子目錄,非垃圾郵件和垃圾郵件的總數分别為 16545 封和 17171 封。euron-spam 庫的下載下傳連結如下:

<a href="http://t.cn/rk84mv6" target="_blank">http://t.cn/rk84mv6</a>

需要注意的是,由于 euron-spam 資料庫的組織形式有别于上文提到的 ling-spam 庫,是以上文的一些函數也需要做少量的修改才能應用于 euron-spam。

這裡我們将 euron-spam 資料庫按照 3:2 的比例分為訓練集和測試集,按照上文的步驟,我們在 13478 封測試郵件中得到了如下結果:

手把手教你用 python 和 scikit-learn 實作垃圾郵件過濾

可以看到,svm 的表現略勝于樸素貝葉斯。

在本文中我們盡量保持簡單易懂的叙述,省略了許多技術性強的講解和名詞。我們希望這是一篇簡單易懂的教程,希望這篇教程可以對文本分析感興趣的初學者們有所裨益。

有些朋友可能會對樸素貝葉斯模型和 svm 模型背後的數學原理感到好奇,這裡需要指出的是,svm 在數學上屬于比較複雜的模型,而樸素貝葉斯則相對更容易了解一些。我們當然鼓勵對數學原理感興趣的朋友們深入探索,關于這些數學模型網上有非常詳細的教程和執行個體。除此之外,采用不同的方式實作同一個目标,也是一種很好的研究方法。例如可以調節如下一些參數,觀察它們對垃圾郵件過濾的實際效果的影響:

a) 訓練資料的大小 b) 詞典的大小 c) 不同的機器學習模型,包括 gaussiannb,bernoullinb,svc d) 不同的 svm 模型參數 e) 删除無關緊要的詞來改進詞典 (例如手動删除) f) 采用其他特征模型 (尋找 td-idf)

最後,部落格中提到的完整 python 代碼詳見如下連結:

<a href="http://t.cn/r6zeuin" target="_blank">http://t.cn/r6zeuin</a>

若有問題,歡迎在文末留言讨論。

====================================分割線================================

本文作者:ai研習社