在信息化高度发达的今天,电子邮件已经成为日常通信的重要工具。然而,垃圾邮件的泛滥极大地影响了用户体验和信息安全。因此,构建一个高效的垃圾邮件过滤系统变得尤为重要。本文将介绍如何使用支持向量机(SVM)来实现一个简单而高效的垃圾邮件分类器,并详细解析相关的实现过程和核心技术。
一、项目目标
本项目的目标是基于已标注的数据集训练一个垃圾邮件分类器。该分类器可以:
1.识别一封邮件是否为垃圾邮件
2.对新输入的邮件内容做出分类判断
二、SVM 简介
1. 什么是支持向量机(SVM)
支持向量机(Support Vector Machine)是一种二分类监督学习算法,主要用于分类问题,也可以通过扩展用于回归。
它的基本目标是: 在特征空间中找到一个最优的超平面,将正类和负类分开,并最大化两类样本到这个超平面的距离。
2. 几何解释:最优超平面与间隔
假设我们在二维空间中进行分类,正类和负类可以用一条直线(超平面)分开。SVM 不仅要找到能分开两类的数据的“任意一条线”,而是要找到“离两类样本最远”的那一条。这样的分界线就是最优超平面。
支持向量:最靠近分界线的样本点,它们决定了超平面的位置
间隔(Margin):支持向量到超平面的距离,SVM 追求最大化这个间隔
3. 线性 SVM 的数学形式
我们要找到一个超平面:
使得满足:
并最大化间隔 2/∣∣w∣∣,等价于最小化目标函数:
这是硬间隔 SVM的形式,仅适用于完全线性可分的数据。
4. 软间隔与 C 参数
在现实中,数据往往不能完全线性可分。为了容忍部分样本分类错误,引入“松弛变量” ξi,得到:
C 是惩罚因子:越大越不容许分类错误;越小则允许更多误分,但具有更好泛化能力
5. 核函数与非线性 SVM
当数据无法线性分割时,SVM 使用核函数将数据映射到高维空间,在高维空间里再进行线性分类。
三、数据预处理与特征提取
1. 邮件预处理流程
我们对邮件内容进行如下处理:
转小写
去除 HTML 标签
用通用占位符替换 URL、数字、邮箱地址、美元符号
分词(Tokenization)
去停用词(如 "the", "is", "in" 等)
词干提取(Stemming),保留词根
#1. 邮件预处理函数
def process_email(email_contents):
#转为小写
email_contents = email_contents.lower()
#去除所有 HTML 标签
email_contents = re.sub('<[^<>]+>', ' ', email_contents)
#处理数字、网址、邮箱地址和美元符号
email_contents = re.sub('[0-9]+', 'number', email_contents)
email_contents = re.sub('(http|https)://[^\s]*', 'httpaddr', email_contents)
email_contents = re.sub('[^\s]+@[^\s]+', 'emailaddr', email_contents)
email_contents = re.sub('[$]+', 'dollar', email_contents)
#分词并词干提取
stemmer = PorterStemmer()
tokens = re.split('[ @$/#.-:&*+=\[\]?!(){},\'\">_<;%\n\r]', email_contents)
words = []
for token in tokens:
token = re.sub('[^a-zA-Z0-9]', '', token)
if len(token) < 1 or token in stopwords.words('english'):
continue
words.append(stemmer.stem(token))
return words
2. 构建词汇表
我们将出现频率较高的单词汇总成一个词汇表,并为每个词分配一个索引。这个词汇表是后续特征向量化的依据。
# 2. 构建词汇表
def get_vocab_list():
vocab = {}
with open(r"C:\Users\26687\Desktop\test\deep learning\e6\svm_data\data\vocab.txt", "r") as f:
for line in f:
index, word = line.strip().split('\t')
vocab[word] = int(index)
return vocab
3. 向量化邮件内容
将处理后的单词映射为固定长度的0/1向量,表示该词是否出现在邮件中(词袋模型)
#3. 将处理后的邮件内容转换为特征向量
def email_features(email_words, vocab_dict):
n = len(vocab_dict)
features = np.zeros(n)
for word in email_words:
if word in vocab_dict:
index = vocab_dict[word] - 1 # 词汇表索引从 1 开始
features[index] = 1
return features
四、模型训练与测试
使用 SciPy 提供的 .mat
数据文件加载训练数据,并用 scikit-learn
中的 SVC
类来训练 SVM 模型
训练过程:
#训练 SVM 模型
model = svm.SVC(C=0.1, kernel='linear')
model.fit(X, y)
五、新邮件预测
可以读取新邮件文件,对其进行同样的预处理,然后输入训练好的模型进行预测:
#预测新邮件是否为垃圾邮件
with open(r'C:\Users\26687\Desktop\test\deep learning\e6\svm_data\data\emailSample1.txt', 'r') as file:
content = file.read()
words = process_email(content)
x = email_features(words, vocab)
pred = model.predict([x])
print("该邮件被分类为:", "垃圾邮件" if pred[0] == 1 else "非垃圾邮件")
声明:本博客仅为个人理解,如有错误,敬请谅解并指出