-
介绍
支持向量机(SVM)是一种用于分类和回归分析的监督学习算法。它的目标是找到一个最优的超平面(在二维空间中就是一条直线)来将不同类别的样本分开。主要思想是通过找到离超平面最近的一些样本点(即支持向量),来确定分类边界。这些支持向量距离超平面的距离被称为间隔,支持向量机的目标是最大化间隔,以提高分类的鲁棒性(鲁棒性:通过最大化间隔,支持向量机对异常值的影响较小)。
支持向量机可以使用不同的核函数来处理线性不可分的情况,其中最常用的是高斯核函数。通过引入核函数,支持向量机可以将样本映射到高维特征空间中,从而实现非线性分类。支持向量机在处理高维数据和非线性数据时表现出色。
线性可分时:
线性不可分时:
-
代码实现
之前我们尝试使用了朴素贝叶斯和logistics回归来实现垃圾邮件分类,这次我们继续在之前的基础上改造出支持向量机策略的垃圾邮件分类器。
首先,我们准备测试数据email.txt,其中的数据格式就设定为“邮件信息”+“标签”的形式,方便我们进行数据获取。这里直接再再再利用一下之前实验使用的测试数据(祖传数据集了属于是)。
之后,读取数据与处理数据的方法没什么大变化,依旧是使用file.readlines()读取文件的所有行,并将其存储在lines列表中。如然后使用列表推导式和strip()函数去除每行的空白字符,并使用分号将每行拆分成元组。使用zip(*training_data)将元组解压缩为两个分开的列表,分别存储在emails和labels中。最后创建一个空字典word_counts,用于存储单词及其出现次数。对于每封电子邮件,通过使用split()函数将其拆分为单词列表。遍历单词列表,如果单词不在word_counts字典中,则将其添加并设置计数为1,否则将计数加1。
# 读取email.txt文件
with open('C:/Users/86188/Desktop/email.txt', 'r') as file:
lines = file.readlines()
# 处理数据
training_data = [tuple(line.strip().split(';')) for line in lines]
emails, labels = zip(*training_data)
# 使用词袋模型提取特征
word_counts = {}
for email in emails:
words = email.split()
for word in words:
if word not in word_counts:
word_counts[word] = 1
else:
word_counts[word] += 1
然后,我们创建一个空列表feature_vector,用于存储特征向量。创建一个空列表vector,用于存储当前电子邮件的特征向量。遍历word_counts字典中的每个单词,如果单词在当前电子邮件的单词列表中,则将1添加到vector中,否则添加0。然后将vector添加到feature_vector中。最后使用array函数将feature_vector转换为NumPy数组,并赋值给变量x;将labels转换为NumPy数组,并指定数据类型为整数,并赋值给变量y。
# 构建特征向量
feature_vector = []
for email in emails:
words = email.split()
vector = []
for word in word_counts:
if word in words:
vector.append(1)
else:
vector.append(0)
feature_vector.append(vector)
X = np.array(feature_vector)
y = np.array(labels, dtype=int)
之后,我们开始定义核支持向量机分类器。
首先定义一个初始化方法__init__(self, kernel='rbf'),它接受一个参数kernel,默认为高斯核函数(径向基函数)。在初始化过程中,它还创建了两个成员变量support_vectors和support_vector_labels,用于存储支持向量和对应的标签。
再定义一个训练方法fit(self, X, y),它接受训练数据X
和对应的标签y作为输入。在训练过程中,它将训练数据存储在support_vectors中,并将标签存储在support_vector_labels中。
最后定义一个预测方法predict(self, X),它接受输入数据X
作为输入,并返回预测结果。在预测过程中,它首先遍历输入的每个样本。对于每个样本,它计算该样本与支持向量之间的距离,并将距离存储在列表distances中。然后,它找到列表distances中最小距离对应的索引min_distance_index,并使用该索引从support_vector_labels中获取对应的标签作为预测结果。最后,它将所有预测结果存储在列表predictions中,并将其转换为NumPy数组并返回。
# 定义核支持向量机分类器
class SVM:
def __init__(self, kernel='rbf'):
self.kernel = kernel
self.support_vectors = None
self.support_vector_labels = None
def fit(self, X, y):
self.support_vectors = X
self.support_vector_labels = y
def predict(self, X):
predictions = []
for sample in X:
distances = []
for vector in self.support_vectors:
distance = np.linalg.norm(sample - vector)
distances.append(distance)
min_distance_index = np.argmin(distances)
prediction = self.support_vector_labels[min_distance_index]
predictions.append(prediction)
return np.array(predictions)
紧接着,我们创建一个SVM对象并传入参数kernel='rbf',即高斯核函数。然后调用svm.fit(X, y)方法,将训练数据和标签传递给分类器进行训练。
svm = SVM(kernel='rbf')
# 训练分类器
svm.fit(X, y)
最后,我们定义分类函数classify_svm(email),它接受一个电子邮件作为输入,并返回分类结果。先将输入的电子邮件拆分为单词列表,然后创建一个空列表vector,用于存储当前电子邮件的特征向量。遍历word_counts字典中的每个单词,如果单词在当前电子邮件的单词列表中,则将1添加到vector中,否则添加0。使用NumPy的array函数将vector转换为NumPy数组,并使用reshape(1, -1)将其转换为二维数组。调用svm.predict(x)方法对特征向量进行预测,并获取预测结果。
# 定义分类函数
def classify_svm(email):
words = email.split()
vector = []
for word in word_counts:
if word in words:
vector.append(1)
else:
vector.append(0)
x = np.array(vector).reshape(1, -1)
prediction = svm.predict(x)[0]
if prediction == 1:
return '这是垃圾邮件'
else:
return '这不是垃圾邮件'
完整代码如下
import numpy as np
# 读取email.txt文件
with open('C:/Users/86188/Desktop/email.txt', 'r') as file:
lines = file.readlines()
# 处理数据
training_data = [tuple(line.strip().split(';')) for line in lines]
emails, labels = zip(*training_data)
# 使用词袋模型提取特征
word_counts = {}
for email in emails:
words = email.split()
for word in words:
if word not in word_counts:
word_counts[word] = 1
else:
word_counts[word] += 1
# 构建特征向量
feature_vector = []
for email in emails:
words = email.split()
vector = []
for word in word_counts:
if word in words:
vector.append(1)
else:
vector.append(0)
feature_vector.append(vector)
X = np.array(feature_vector)
y = np.array(labels, dtype=int)
# 定义核支持向量机分类器
class SVM:
def __init__(self, kernel='rbf'):
self.kernel = kernel
self.support_vectors = None
self.support_vector_labels = None
def fit(self, X, y):
self.support_vectors = X
self.support_vector_labels = y
def predict(self, X):
predictions = []
for sample in X:
distances = []
for vector in self.support_vectors:
distance = np.linalg.norm(sample - vector)
distances.append(distance)
min_distance_index = np.argmin(distances)
prediction = self.support_vector_labels[min_distance_index]
predictions.append(prediction)
return np.array(predictions)
svm = SVM(kernel='rbf')
# 训练分类器
svm.fit(X, y)
# 定义分类函数
def classify_svm(email):
words = email.split()
vector = []
for word in word_counts:
if word in words:
vector.append(1)
else:
vector.append(0)
x = np.array(vector).reshape(1, -1)
prediction = svm.predict(x)[0]
if prediction == 1:
return '这是垃圾邮件'
else:
return '这不是垃圾邮件'
# 手动输入测试数据
test_email = input("请输入邮件内容:")
result = classify_svm(test_email)
print(result)
运行结果如下
-
总结
支持向量机是一种强大的分类算法,它在处理线性可分和线性不可分的问题时都有很好的效果。通过调整核函数和超参数,可以进一步提高模型的分类性能和泛化能力。支持向量机通过将数据映射到高维特征空间,并寻找一个超平面来分割不同类别的数据。我们通过构造核函数、软间隔和正则化、支持向量回归、核方法实现了该思想。依靠该思想,支持向量机可以有效地处理高维数据、泛化能力强、可以处理线性可分和线性不可分问题、对小样本数据效果好、可以进行概率估计、算法相对简单等优点。不过呢,实验中明显感觉到支持向量机策略算法对大规模数据训练比较耗时、对非线性问题核函数的选择不容易、对噪声敏感等缺点。即便如此,支持向量机在许多实际问题中依旧表现出色,并被广泛应用于分类和回归任务,是个很好的策略方法。