5.11 程序示例--垃圾邮件检测-机器学习笔记-斯坦福吴恩达教授
程序示例–垃圾郵件檢測
郵件內容的預處理
下面展示了一封常見的 email,郵件內容包含了一個 URL (http://www.rackspace.com/),一個郵箱地址(groupname-unsubscribe@egroups.com),若干數字,美元符號等:
Anyone knows how much it costs to host a web portal ?Well, it depends on how many visitors youre expecting. This can be anywhere from less than 10 bucks a month to a couple of $100. You should checkout http://www.rackspace.com/ or perhaps Amazon EC2 if youre running something big..To unsubscribe yourself from this mailing list, send an email to: groupname-unsubscribe@egroups.com許多其他郵件可能也包含了這些信息,因此,在對郵件內容的預處理階段,就是要 “標準化” 這些參數。例如,我們需要將所有的 URL鏈接都替換為 httpaddr,這能讓垃圾郵件分類器在獲得決策邊界時不受限于某個具體的 URL。標準化的手段能顯著提升分類器的性能,這是因為,垃圾郵件通常會隨機產生 URL,因此,在新的垃圾郵件中,發現之前見過的 URL 的可能性是不高的。
在預處理郵件內容階段,我們將完成如下內容:
- 轉換內容為小寫:郵件的所有單詞都會被轉化為小寫。
- 去除 HTML 標簽:
- 標準化 URL:將所有的 URL 鏈接替換為 httpaddr。
- 標準化郵箱地址:將所有的郵箱地址替換為 emailaddr。
- 標準化所有的數字:將所有的數字替換為 number。
- 標準化所有的美元符號:將所有的美元符號 $ 替換為 dollar。
- 詞干提取(Word-Stemming):例如,我們會將 “discount”、“discounts”、“discounted” 及 “discounting” 都替換為 “discount”。
- 刪去非單詞字符:將空格、tab、換行符等刪去。
上述郵件經過預處理后,內容如下:
anyon know how much it cost to host a web portal well it depend on how mani visitor your expect thi can be anywher from less than number buck a month to a coupl of dollarnumb you should checkout httpaddr or perhap amazon ecnumb if your run someth big to unsubscrib yourself from thi mail list send an email to emailaddr接下來,我們需要確定用于垃圾郵件分類器的單詞,亦即,需要構建一個用于垃圾郵件分類器的詞匯列表。在本例中,將選擇在垃圾郵件語料庫(spam corpus)中,出現至少 100 次的單詞。這么做的原因是,如果選擇將出現寥寥的單詞放到訓練樣本中,可能就會造成模型的過擬合。最終完整的詞匯列表存入了文件 vocab.txt 中,當中含有共計 1899 個單詞:
1 aa 2 ab 3 abil ... 86 anyon ... 916 know ... 1898 zero 1899 zip在生產環境中,詞匯列表的規模在 10,000 到 50,000 個單詞之間。
有了詞匯表之后,我們現在就能將預處理后的郵件映射為一個坐標集,每個坐標反映了郵件中單詞在詞匯表的位置:
86 916 794 1077 883 370 1699 790 1822 1831 883 431 1171 794 1002 1893 1364 592 1676 238 162 89 688 945 1663 1120 1062 1699 375 1162 479 1893 1510 799 1182 1237 810 1895 1440 1547 181 1699 1758 1896 688 1676 992 961 1477 71 530 1699 531特別地,“anyone” 被標準化了詞匯表的第86個單詞 “anyon”。
預處理的代碼片如下,我們用到了函數式編程庫 pydash 以及詞干提取庫 stemming:
# coding: utf8 # svm/spam.py# ... def processEmail(email):"""預處理郵件Args:email 郵件內容Returns:indices 單詞在詞表中的位置"""# 轉換為小寫 --> 標準化 URL --> 標準化 郵箱地址# --> 去除 HTML 標簽 --> 標準化數字# --> 標準化美元 --> 刪除非空格字符return py_(email) \.strip_tags() \.reg_exp_replace(r'(http|https)://[^\s]*', 'httpaddr') \.reg_exp_replace(r'[^\s]+@[^\s]+', 'emailaddr') \.reg_exp_replace(r'\d+', 'number') \.reg_exp_replace(r'[$]+', 'dollar') \.lower_case() \.trim() \.words() \.map(stem) \.map(lambda word : py_.index_of(vocabList, word) + 1) \.value()郵件特征提取
我們定義特征 x(i)x^{(i)}x(i) 為:
x(i)={1,如果詞匯表的第i個單詞出現0,otherwisex^{(i)}=\begin{cases}1,\quad\quad 如果詞匯表的第\ i\ 個單詞出現\\ 0,\quad\quad otherwise\end{cases}x(i)={1,如果詞匯表的第?i?個單詞出現0,otherwise?
則知, x∈Rnx∈\R^nx∈Rn , nnn 為詞匯表長度。
特征提取的代碼同樣封裝到了項目的 svm/spam.py中:
# coding: utf8 # svm/spam.py# .... def extractFeatures(indices):"""提取特征Args:indices 單詞索引Returns:feature 郵件特征"""feature = py_.map(range(1, len(vocabList) + 1),lambda index: py_.index_of(indices, index) > -1)return np.array(feature, dtype=np.uint)Top Predictors
在 SVM 訓練后獲得的模型中,權值向量 www 評估了每個特征的重要性,對應到詞匯表的坐標中,我們也就知道了那些詞匯最能分辨垃圾郵件,這些詞匯稱為 Top Predictors。
# coding: utf8 # svm/spam.py# .... def getTopPredictors(weights, count):"""獲得最佳標識詞匯Args:weights 權值count top countReturns:predictors predicators"""return py_(vocabList) \.map(lambda word, idx: (word, weights[idx])) \.sort_by(lambda item: item[1], reverse = True) \.take(count) \.value()測試
下面,我們會使用 sklearn 提供的 SVM 模型進行訓練以加快訓練效率,它是基于 libsvm 的,有不錯的運算性能:
# coding: utf8 # svm/test_spam.py import spam import numpy as np from scipy.io import loadmat from sklearn.svm import SVC import matplotlib.pyplot as plt# 垃圾郵件分類器 data = loadmat('data/spamTrain.mat') X = np.mat(data['X']) y = data['y'] m, n = X.shape C = 0.1 tol = 1e-3# 使用訓練集訓練分類器 clf = SVC(C=C, kernel='linear', tol=tol) clf.fit(X, y.ravel()) predictions = np.mat([clf.predict(X[i, :]) for i in range(m)]) accuracy = 100 * np.mean(predictions == y) print 'Training set accuracy: %0.2f %%' % accuracy# 使用測試集評估訓練結果 data = loadmat('data/spamTest.mat') XTest = np.mat(data['Xtest']) yTest = data['ytest'] mTest, _ = XTest.shapeclf.fit(XTest, yTest.ravel()) print 'Evaluating the trained Linear SVM on a test set ...' predictions = np.mat([clf.predict(XTest[i, :]) for i in range(mTest)]) accuracy = 100 * np.mean(predictions == yTest) print 'Test set accuracy: %0.2f %%' % accuracy# 獲得最能標識垃圾郵件的詞匯(在模型中獲得高權值的) weights = abs(clf.coef_.flatten()) top = 15 predictors = spam.getTopPredictors(weights, top) print 'Top %d predictors of spam:'%top for word, weight in predictors:print '%-15s (%f)' % (word, weight)# 使用郵件測試 def genExample(f):email = open(f).read()indices = spam.processEmail(email)features = spam.extractFeatures(indices)return featuresfiles = ['data/emailSample1.txt','data/emailSample1.txt','data/spamSample1.txt','data/spamSample2.txt' ]emails = np.mat([genExample(f) for f in files], dtype=np.uint8) labels = np.array([[0, 0, 1, 1]]).reshape(-1, 1) predictions = np.mat([clf.predict(emails[i, :]) for i in range(len(files))]) accuracy = 100 * np.mean(predictions == labels) print('Test set accuracy for own datasets: %0.2f %%' % accuracy)測試結果為:
Training set accuracy: 99.83 % Test set accuracy: 99.90 %Top 15 predictors of spam: click (0.477352) url (0.332529) date (0.316182) wrote (0.282825) spamassassin (0.266681) remov (0.250697) there (0.248973) numbertnumb (0.240243) the (0.238051) pleas (0.235655) our (0.233895) do (0.226717) basenumb (0.218456) we (0.218421) free (0.214057)Test set accuracy for own datasets: 100.00 %總結
以上是生活随笔為你收集整理的5.11 程序示例--垃圾邮件检测-机器学习笔记-斯坦福吴恩达教授的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 5.10 程序示例--模型选择-机器学习
- 下一篇: 6.1 无监督学习-机器学习笔记-斯坦福