怎样用支持向量机从零制作一个垃圾邮件识别器 | 机器学习

428 阅读6分钟

1. 问题

支持向量机(Support Vector Machines)是当下最流行的机器学习算法之一,今天我们一起来了解下,并来个实战。

2. 分析

支持向量机属于有监督学习,主要有三个用途

  1. 分类(Classification);
  2. 回归(Regression);
  3. 异常检测(Outliers Detection);

功能强大实用,可以说集美貌与才华于一身。

相比其他模型,支持向量机的主要优势有

  • 高维空间运算效率很高;
  • 在 feature 数量大于 case 数量的时候依然有很高的效率;
  • 只需计算训练集里面的部分数据(support vectors);
  • 灵活,有多种核函数(Kernel functions)可选,甚至可以自定义核函数;

当然,它也有不足的地方,例如

  • 如果 feature 的数量远大于样本数时,需要注意过度拟合(over-fitting);
  • 支持向量机不直接计算概率,需要通过5倍交叉验证(five-fold cross-validation)来计算,运算成本很高;

作为经典算法,很多软件包已经继承了支持向量机,我们无需手动实现。以scikit learn 为例,SVCLinearSVC 可以实现分类算法,SVRLinearSVR 可以实现回归算法,OneClassSVM 可以实现异常检测算法。

使用支持向量机的时候需要注意一些细节

  • 选择合适的C。该参数是用来调节模型柔度的,默认为 1,如果数据噪音较大,可以尝试将其减小以避免过度拟合;
  • 提前标准化参数。支持向量机对数据大小敏感,所以训练之前应先将数据标准化。可以标准化为[0, 1]之间、[-1, 1]之间,或者均值为0、标准差为 1 的数据。需要注意的是,所有参数都应该用同一种方法标准化,这样结果才有意义;

3. 实现

经过前几次的学习,我们对 scikit learn 的基本操作已经比较熟悉了。今天我们在实现阶段做一个稍微有点挑战性的工作,从零设计一个支持向量机的垃圾邮件识别工具。

要实现垃圾邮件分类,首先需要把邮件处理成算法能识别的数据,也即 Tokenize 。而 Tokenize 之前,需要先把邮件预处理一下。

首先,加载相应的库

import numpy as np
import re
from sklearn import svm
from sklearn.model_selection import train_test_split

然后构造垃圾邮件语料库

vocablist = [line.strip().split('\t')[-1for line in open('vocab.txt''r', encoding='UTF8')]
vocab = {}
for i in range(len(vocablist)):
    vocab[vocablist[i]] = i

然后读入待处理邮件并进行相应预处理

with open('emailSample1.txt''r', encoding='UTF8'as email:
    email = email.read()

email = email.lower()
email = re.sub('[0-9]+''number', email)
email = re.sub('(http|https)://[^\s]*''httpaddr', email)
email = re.sub('[^\s]+@[^\s]+''emailaddr', email)
email = re.sub('[$]+''dollar', email)
email = re.sub('<[^<>]+>'' ', email)
email = re.sub('[^0-9a-z]'' ', email)
email = re.sub('(\s+)'' ', email).strip()
email = email.split()
email

这里用到了Python的正则表达式。正则表达式是文本处理的神兵利器,不可不用。

接下来,我们提取邮件的特征(feature)

wordidx = []
for i in range(len(email)):
    if email[i] in vocablist:
        wordidx.append(vocab[email[i]])

feature = [0 for i in range(len(vocab))]
for i in range(len(wordidx)):
    feature[wordidx[i]] = 1

提取特征的意思是,将邮件处理后的单词一一映射到垃圾邮件语料库的索引里面。此处引用的语料库共1899个单词,就会组成一个1899大小的向量。

举例说,award 在语料库里面对应的数字是 144,那么如果邮件里面有 award 这个单词,就将向量 144 处赋值为 1;如果没有,就赋值为 0。

这样,我们就可以为每一封邮件建立一个对应语料库的特征向量。我们将其赋值给变量 X

支持向量机是有监督学习,所以我们的训练集里面,会有很多不同的邮件,有些是垃圾邮件,将其 y标记为 1,有的不是垃圾邮件,标记 y 为 0。

这样,我们就形成了一个 Tokenize 后的邮件输入矩阵 X 和对应标及其是否是垃圾邮件的 y。我们可以数据分为 Training set 和 Test set,先用 Training set 训练模型,然后用 Test set 检查结果。

data = np.loadtxt('svmSpam.txt', delimiter=' ')
X = data[:, 0:-1]; y = data[:, -1]

X_train, X_test, y_train, y_test = train_test_split(X, y)
clf = svm.SVC()
clf.fit(X_train, y_train)

print("Training set score: {:.2f}".format(clf.score(X_train, y_train)))
print("Test set score: {:.2f}".format(clf.score(X_test, y_test)))

最后,结果输出为

Training set score: 0.99
Test set score: 0.96

吼吼,测试准确率高达0.96,Cool~

4. 总结

今天我们大致介绍了支持向量机的用法,并用其实现了一个简单的垃圾邮件处理工具。相关代码均已上传到Github(https://github.com/jetorz/Data2Science)。

从今天的例子中我们学到

  1. 技术重要,但更重要的是能用技术来实现什么。学完机器学习,不能就丢一边了,而是要想办法在生活中用起来;
  2. 数据很关键。学习模型需要数据,甚至大量数据。Kaggle 是个好地方,可以用起来;
  3. 编程是个厚积薄发的功夫。比如搞机器学习要处理文本,就不能不知道正则表达式。其他类似;

路漫漫其修远兮,继续上下求索吧。

5. 交流

独学而无友则孤陋寡闻。现有「数据与统计科学」微信交流群,内有数据行业资深从业人员、海外博士、硕士等,欢迎对数据科学、数据分析、机器学习、人工智能有兴趣的朋友加入,一起学习讨论。

大家可以扫描下面二维码,添加荔姐微信邀请加入,暗号:机器学习加群。

6. 扩展

6.1. 延伸阅读

6.2. 参考文献

  1. G. James, D. Witten, T. Hastie R. Tibshirani, An introduction to statistical learning: with applications in R. New York: Springer, 2013.
  2. T. Hastie, R. Tibshirani, J. H. Friedman, The elements of statistical learning: data mining, inference, and prediction, 2nd ed. New York, NY: Springer, 2009.
  3. W. Härdle, L. Simar, Applied multivariate statistical analysis, 3rd ed. Heidelberg ; New York: Springer, 2012.

本文使用 mdnice 排版