当前位置: 首页 > news >正文

机器学习:支持向量机(SVM)原理解析及垃圾邮件过滤实战

一、什么是支持向量机(SVM)

1. 基本概念

1.1 二分类问题的本质

在机器学习中,分类问题是最常见的任务之一。最简单的情况就是二分类:比如一封邮件是“垃圾邮件”还是“正常邮件”?一个病人是“患病”还是“健康”?一个图像是“猫”还是“狗”?
SVM专门擅长处理这种“把样本分成两类”的问题。它的核心目标是:找到一个最优的边界,把两类样本尽可能清晰地分开。

1.2 最大间隔划分思想

SVM的最大特点,就是它不像KNN那样靠近邻,也不像逻辑回归那样直接拟合概率,而是追求“最大间隔”:

它试图在两个类别之间,找到一条“超平面”(一个直线、一个面、或者一个高维空间中的超平面),这个超平面与两类样本中最近的点之间的距离最大,这个“最近的点”就是“支持向量”。

为什么要最大化这个间隔?
简单来说:更大的间隔 = 更强的容错率 = 更好的泛化能力。

1.3 支持向量的意义

在SVM中,真正决定这个“最佳分隔线”的,并不是所有数据点,而是最接近这条线的一小部分点,我们称之为“支持向量”。

这些支持向量对模型训练有决定性作用,一旦它们的位置改变,分界线就可能会改变。而其他点的影响几乎为零。


2. 超平面与间隔

  1. 超平面:在二维中是直线,在三维中是平面,在更高维中是“超平面”。SVM的目标就是找到这样一个能分开两类样本的超平面。

  2. 间隔:超平面到支持向量的最小距离。SVM通过最大化这个间隔来优化模型。

这是一种几何直觉非常强的优化方式,适合处理线性可分的数据。

2.1 硬间隔

**硬间隔(Hard Margin)**是支持向量机(SVM)中的一个概念,指的是在分类过程中,模型要求训练数据必须被完全正确分类,且每个样本点都不能落在分类间隔区域内
直白解释:

硬间隔就是:“我要找到一条完美的分界线,一个样本都不能错分,也不能碰到分界线附近的空白区域。”

2.1.1 硬间隔的定义

设训练数据集为:

{ ( x 1 , y 1 ) , ( x 2 , y 2 ) , … , ( x n , y n ) } , x i ∈ R d , y i ∈ { − 1 , + 1 } \{(x_1, y_1), (x_2, y_2), \dots, (x_n, y_n)\},\quad x_i \in \mathbb{R}^d,\quad y_i \in \{-1, +1\} {(x1,y1),(x2,y2),,(xn,yn)},xiRd,yi{1,+1}

SVM 要求找到一个线性可分的超平面:

w T x + b = 0 w^T x + b = 0 wTx+b=0

使得所有训练样本被完全正确分类,并且分类间隔最大


约束条件(分类正确 + 间隔大):

对所有样本 i = 1 , 2 , . . . , n i = 1, 2, ..., n i=1,2,...,n,要求:

y i ( w T x i + b ) ≥ 1 y_i (w^T x_i + b) \geq 1 yi(wTxi+b)1

这表示:

  • 如果 y i = + 1 y_i = +1 yi=+1,则 w T x i + b ≥ 1 w^T x_i + b \geq 1 wTxi+b1

  • 如果 y i = − 1 y_i = -1 yi=1,则 w T x i + b ≤ − 1 w^T x_i + b \leq -1 wTxi+b1

也就是说:每个样本都要落在自己那一侧的“边界外”,而且不能在间隔区域里、也不能分类错误


优化目标(最大间隔 = 最小化 ∥ w ∥ 2 \|w\|^2 w2

支持向量机通过最大化间隔来实现最优划分。因为几何间隔是 2 ∥ w ∥ \frac{2}{\|w\|} w2,最大化它等价于最小化 ∥ w ∥ 2 \|w\|^2 w2

所以硬间隔 SVM 的优化问题是:

min ⁡ w , b 1 2 ∥ w ∥ 2 subject to y i ( w T x i + b ) ≥ 1 , ∀ i = 1 , . . . , n \begin{aligned} \min_{w, b} \quad & \frac{1}{2} \|w\|^2 \\ \text{subject to} \quad & y_i (w^T x_i + b) \geq 1,\quad \forall i = 1, ..., n \end{aligned} w,bminsubject to21w2yi(wTxi+b)1,i=1,...,n


硬间隔只适用于:

  • 数据完全线性可分

  • 没有噪声和异常值

如果你的数据本身是完全线性可分的,比如下图中的两类点完全不重叠,那么硬间隔SVM就可以很完美地找到一个“最大间隔的超平面”来分开它们。

在这里插入图片描述

一旦数据中有噪声或重叠样本,硬间隔就无法找到合理解,甚至根本无法收敛。这时我们就要用软间隔,允许一些“点分类错了”,换取更强的容错能力。


2.1.2 硬间隔的对偶问题

构造拉格朗日函数(Lagrangian)

引入拉格朗日乘子 α i ≥ 0 \alpha_i \geq 0 αi0,对应约束 y i ( w T x i + b ) ≥ 1 y_i(w^T x_i + b) \geq 1 yi(wTxi+b)1

构造拉格朗日函数:

L ( w , b , α ) = 1 2 ∥ w ∥ 2 − ∑ i = 1 n α i [ y i ( w T x i + b ) − 1 ] \mathcal{L}(w, b, \alpha) = \frac{1}{2} \|w\|^2 - \sum_{i=1}^n \alpha_i [y_i(w^T x_i + b) - 1] L(w,b,α)=21w2i=1nαi[yi(wTxi+b)1]


对偶问题推导步骤

我们要最小化 L \mathcal{L} L 关于 w w w b b b,最大化关于 α \alpha α
先求偏导设置为 0:

1. 对 w w w 求导并令其为 0:

∂ L ∂ w = w − ∑ i = 1 n α i y i x i = 0 ⇒ w = ∑ i = 1 n α i y i x i \frac{\partial \mathcal{L}}{\partial w} = w - \sum_{i=1}^n \alpha_i y_i x_i = 0 \Rightarrow w = \sum_{i=1}^n \alpha_i y_i x_i wL=wi=1nαiyixi=0w=i=1nαiyixi

2. 对 b b b 求导并令其为 0:

∂ L ∂ b = − ∑ i = 1 n α i y i = 0 ⇒ ∑ i = 1 n α i y i = 0 \frac{\partial \mathcal{L}}{\partial b} = - \sum_{i=1}^n \alpha_i y_i = 0 \Rightarrow \sum_{i=1}^n \alpha_i y_i = 0 bL=i=1nαiyi=0i=1nαiyi=0


代入得对偶问题

w w w 表达式代入 L \mathcal{L} L,得到只关于 α \alpha α 的对偶问题:

max ⁡ α ∑ i = 1 n α i − 1 2 ∑ i = 1 n ∑ j = 1 n α i α j y i y j x i T x j s.t. ∑ i = 1 n α i y i = 0 α i ≥ 0 , ∀ i \begin{aligned} \max_{\alpha} \quad & \sum_{i=1}^n \alpha_i - \frac{1}{2} \sum_{i=1}^n \sum_{j=1}^n \alpha_i \alpha_j y_i y_j x_i^T x_j \\ \text{s.t.} \quad & \sum_{i=1}^n \alpha_i y_i = 0 \\ & \alpha_i \geq 0,\quad \forall i \end{aligned} αmaxs.t.i=1nαi21i=1nj=1nαiαjyiyjxiTxji=1nαiyi=0αi0,i

这就是 硬间隔 SVM 的对偶形式

它是一个凸二次规划问题,可以用标准优化算法求解。

2.2 软间隔

软间隔(Soft Margin)是支持向量机(SVM)在面对现实中不可完美划分数据时,引入的一种“宽容机制”。

通俗来说:

如果“硬间隔”是一个完美主义者,要求训练集所有点都正确分类;
那么“软间隔”就是个现实主义者,承认一些点可能分类错误,但整体效果更重要


现实中的数据常常:

  • 噪声(例如标注错误、输入异常);

  • 两类样本有重叠

  • 完全线性可分几乎不可能。

此时,如果继续使用硬间隔 SVM,会导致:

  • 模型无法收敛;

  • 过拟合噪声点,泛化能力差。

所以我们需要“放松限制”——允许一部分样本距离边界近,甚至被分错,但整体间隔仍尽可能大。


2.2.1 软间隔的形式定义

引入松弛变量 ξ i ≥ 0 \xi_i \geq 0 ξi0 来表示第 i i i 个样本允许“违背间隔要求”的程度。

优化问题变成:

min ⁡ w , b , ξ 1 2 ∥ w ∥ 2 + C ∑ i = 1 n ξ i subject to y i ( w T x i + b ) ≥ 1 − ξ i , ∀ i ξ i ≥ 0 , ∀ i \begin{aligned} \min_{w, b, \xi} \quad & \frac{1}{2} \|w\|^2 + C \sum_{i=1}^{n} \xi_i \\ \text{subject to} \quad & y_i (w^T x_i + b) \geq 1 - \xi_i,\quad \forall i \\ & \xi_i \geq 0,\quad \forall i \end{aligned} w,b,ξminsubject to21w2+Ci=1nξiyi(wTxi+b)1ξi,iξi0,i

解释各个部分含义:

  • 1 2 ∥ w ∥ 2 \frac{1}{2} \|w\|^2 21w2:仍然是“最大化间隔”的目标;
  • ξ i \xi_i ξi:表示第 i i i 个样本有多“违反”分类边界;
    * ξ i = 0 \xi_i = 0 ξi=0:正常分类、在间隔外;
    * 0 < ξ i < 1 0 < \xi_i < 1 0<ξi<1:在间隔边界内但没错分;
    * ξ i > 1 \xi_i > 1 ξi>1:被分错类;
  • C C C:是一个超参数,控制“间隔最大化”与“容忍错误”的权衡:
    * C 大:更偏向少错分(严格)→ 更可能过拟合;
    * C 小:更偏向宽容误差(松弛)→ 更强泛化能力。

2.2.2 软间隔的对偶问题

构造拉格朗日函数

引入拉格朗日乘子:

  • α i ≥ 0 \alpha_i \geq 0 αi0:对应约束 y i ( w T x i + b ) ≥ 1 − ξ i y_i(w^T x_i + b) \geq 1 - \xi_i yi(wTxi+b)1ξi

  • μ i ≥ 0 \mu_i \geq 0 μi0:对应约束 ξ i ≥ 0 \xi_i \geq 0 ξi0

拉格朗日函数为:
在这里插入图片描述


对偶问题推导(KKT 条件)

我们将对 w , b , ξ w, b, \xi w,b,ξ 求偏导并设为 0:

w w w 求导:

∂ L ∂ w = w − ∑ i = 1 n α i y i x i = 0 ⇒ w = ∑ i = 1 n α i y i x i \frac{\partial \mathcal{L}}{\partial w} = w - \sum_{i=1}^n \alpha_i y_i x_i = 0 \Rightarrow w = \sum_{i=1}^n \alpha_i y_i x_i wL=wi=1nαiyixi=0w=i=1nαiyixi

b b b 求导:

∂ L ∂ b = − ∑ i = 1 n α i y i = 0 ⇒ ∑ i = 1 n α i y i = 0 \frac{\partial \mathcal{L}}{\partial b} = -\sum_{i=1}^n \alpha_i y_i = 0 \Rightarrow \sum_{i=1}^n \alpha_i y_i = 0 bL=i=1nαiyi=0i=1nαiyi=0

ξ i \xi_i ξi 求导:

∂ L ∂ ξ i = C − α i − μ i = 0 ⇒ α i ≤ C ( 因为  μ i ≥ 0 ) \frac{\partial \mathcal{L}}{\partial \xi_i} = C - \alpha_i - \mu_i = 0 \Rightarrow \alpha_i \leq C \quad (\text{因为 } \mu_i \geq 0) ξiL=Cαiμi=0αiC(因为 μi0)


最终对偶问题形式

整理后,软间隔 SVM 的对偶问题为:

max ⁡ α ∑ i = 1 n α i − 1 2 ∑ i = 1 n ∑ j = 1 n α i α j y i y j x i T x j s.t. ∑ i = 1 n α i y i = 0 0 ≤ α i ≤ C , ∀ i \begin{aligned} \max_{\alpha} \quad & \sum_{i=1}^n \alpha_i - \frac{1}{2} \sum_{i=1}^n \sum_{j=1}^n \alpha_i \alpha_j y_i y_j x_i^T x_j \\ \text{s.t.} \quad & \sum_{i=1}^n \alpha_i y_i = 0 \\ & 0 \leq \alpha_i \leq C,\quad \forall i \end{aligned} αmaxs.t.i=1nαi21i=1nj=1nαiαjyiyjxiTxji=1nαiyi=00αiC,i

相比于硬间隔的对偶问题,这里:

  • 增加了上界 α i ≤ C \alpha_i \leq C αiC,体现对误差的容忍;

  • 因此更适合实际带噪音的数据;

  • 仍然是一个凸二次规划问题

3. 核函数

3.1 核函数的定义

支持向量机算法分类和回归方法的中都支持线性性和非线性类型的数据类型。非线性类型通常是二维平面不可分,为了使数据可分,需要通过一个函数将原始数据映射到高维空间,从而使得数据在高维空间很容易可分,需要通过一个函数将原始数据映射到高维空间,从而使得数据在高维空间很容易区分,这样就达到数据分类或回归的目的,而实现这一目标的函数称为核函数。

在这里插入图片描述在这里插入图片描述

3.2 常见的核函数

1. 线性核(Linear Kernel)
K ( x , x ′ ) = x T x ′ K(x, x') = x^T x' K(x,x)=xTx
适用场景:

  • 特征数非常大(如文本分类)

  • 数据本身已经线性可分或接近线性


2. 多项式核

K ( x , x ′ ) = ( x T x ′ + c ) d K(x, x') = (x^T x' + c)^d K(x,x)=(xTx+c)d

其中 d d d:多项式的次数, c c c:常数项(通常 c ≥ 0 c \geq 0 c0

适用场景:

  • 特征间有高阶交互关系的情况

  • 对非线性边界较敏感的问题


3. 高斯核

K ( x , x ′ ) = exp ⁡ ( − ∥ x − x ′ ∥ 2 2 σ 2 ) K(x, x') = \exp\left(-\frac{\|x - x'\|^2}{2 \sigma^2} \right) K(x,x)=exp(2σ2xx2)

其中 σ \sigma σ:控制“邻近范围”的宽度(或使用 γ = 1 2 σ 2 \gamma = \frac{1}{2\sigma^2} γ=2σ21

适用场景:

  • 不知道数据的具体分布情况

  • 默认首选的非线性核


4. Sigmoid 核(双曲正切核)

K ( x , x ′ ) = tanh ⁡ ( κ x T x ′ + c ) K(x, x') = \tanh(\kappa x^T x' + c) K(x,x)=tanh(κxTx+c)

类似于神经元中的激活函数

适用场景:

  • 模拟神经网络的效果(如早期神经 SVM 研究)

  • 情况较少使用


二、代码实战

1. 实验内容

实战要求:使用SVM建立自己的垃圾邮件过滤器。首先需要将每个邮件x变成一个n维的特征向量,并训练一个分类器来分类给定的电子邮件x是否属于垃圾邮件 ( y = 1 ) (y=1)(y=1) 或者非垃圾邮件 ( y = 0 ) (y=0)(y=0) 。

已有数据集:emailSample1.txt, vocab.txt, spamTrain.mat, spamTest.mat

2.代码实现

1. 加载并查看样例邮件内容

#查看样例邮件
f = open('emailSample1.txt', 'r').read()
print(f)

读取一封样例邮件的原始文本内容,便于后续处理。

2. 邮件预处理函数 processEmail

def processEmail(email):email = email.lower() #转化为小写email = re.sub('<[^<>]+>', ' ', email) #移除所有HTML标签email = re.sub(r'(http|https)://[^\s]*', 'httpaddr', email) #将所有的URL替换为'httpaddr'email = re.sub(r'[^\s]+@[^\s]+', 'emailaddr', email) #将所有的地址替换为'emailaddr'email = re.sub(r'\d+', 'number', email) #将所有数字替换为'number'email = re.sub('[$]+', 'dollar', email) #将所有美元符号($)替换为'dollar'#将所有单词还原为词根//移除所有非文字类型,空格调整stemmer = nltk.stem.PorterStemmer() #使用Porter算法tokens = re.split(r'[ @$/#.-:&*+=\[\]?!()\{\},\'\">_<;%]', email) #把邮件分割成单个的字符串,[]里面为各种分隔符tokenlist = []for token in tokens:token = re.sub('[^a-zA-Z0-9]', '', token) #去掉任何非字母数字字符try: #porterStemmer有时会出现问题,因此用trytoken = stemmer.stem(token) #词根except:token = ''if len(token) < 1: continue #字符串长度小于1的不添加到tokenlist里tokenlist.append(token)return tokenlist

核心步骤解释:

  • 统一格式:转小写、去 HTML 标签、替换网址、邮箱、数字、货币符号等。

  • 分词:使用正则表达式切分文本成单词。

  • 词干提取(stemming):调用 NLTK 的 PorterStemmer,还原单词基本形式,如 running → run。

  • 清洗:剔除空词、特殊符号,返回标准词汇列表。

  1. 词汇表映射及向量化处理
vocab_list = np.loadtxt('vocab.txt', dtype='str', usecols=1)

词汇表 vocab.txt 中存有 1899 个关键词。

下面两个函数实现了“文本 → 向量”转换:

def word_indices(processed_f, vocab_list):indices = []for i in range(len(processed_f)):for j in range(len(vocab_list)):if processed_f[i]!=vocab_list[j]:continueindices.append(j+1)return indices
def emailFeatures(indices):features = np.zeros((1899))for each in indices:features[each-1] = 1 #若indices在对应单词表的位置上词语存在则记为1return features

效果:

每封邮件被表示成一个 1899维的二进制特征向量,其中:

  • i i i 个位置为 1,表示邮件中包含词汇表中第 i i i 个词。

  • 类似 One-hot 编码,但是多热(multi-hot)表示。

  1. 训练 SVM 模型
train = scio.loadmat('spamTrain.mat')
train_x = train['X']
train_y = train['y']
  • 载入 .mat 格式的训练数据。
  • X 为 4000 封邮件的特征矩阵,y 为对应的垃圾与非垃圾标签(1 或 0)。
clf = svm.SVC(C=0.1, kernel='linear')
clf.fit(train_x, train_y)
  • 使用线性核训练 SVM 模型。
  • 参数 C=0.1 控制软间隔的惩罚程度,越小越宽容。
  1. 模型评估
def accuracy(clf, x, y):predict_y = clf.predict(x)m = y.sizecount = 0for i in range(m):count = count + np.abs(int(predict_y[i])-int(y[i])) #避免溢出错误得到225return 1-float(count/m) 
  • 自定义精度计算函数,统计预测正确率。
train_accuracy = accuracy(clf, train_x, train_y) 
test_accuracy = accuracy(clf, test['Xtest'], test['ytest'])
  1. 解释模型——重要单词排序
print(vocab_list[np.argsort(clf.coef_).flatten()[i]], end=' ')
  • SVM 的线性模型可以通过系数权重判断哪些词对“判定为垃圾邮件”影响最大。
    打印前 15 个正权重最大词汇,说明:
    邮件中若含这些词,更可能是垃圾邮件。
  1. 预测新邮件是否为垃圾邮件
t = open('spamSample2.txt', 'r').read()
processed_f = processEmail(t) 
f_indices = word_indices(processed_f, vocab_list)
x = np.reshape(emailFeatures(f_indices), (1,1899))
clf.predict(x)
  • 流程和训练集一致,对新邮件样本做预处理 → 向量化 → 调用模型预测。
  • 输出为 1(垃圾)或 0(正常)。
  1. PCA 可视化 SVM 决策边界
# PCA降维到2维
pca = PCA(n_components=2)
train_x_pca = pca.fit_transform(train_x)# 重新训练一个2维的SVM,用于绘制决策边界
clf_pca = svm.SVC(C=0.1, kernel='linear')
clf_pca.fit(train_x_pca, train_y)# 画图
plt.figure(figsize=(10, 6))# 绘制不同类别样本点
plt.scatter(train_x_pca[train_y==0, 0], train_x_pca[train_y==0, 1], c='blue', label='Non-spam', edgecolors='k')
plt.scatter(train_x_pca[train_y==1, 0], train_x_pca[train_y==1, 1], c='red', label='Spam', edgecolors='k')# 绘制决策边界
# 创建一个网格
x_min, x_max = train_x_pca[:, 0].min() - 1, train_x_pca[:, 0].max() + 1
y_min, y_max = train_x_pca[:, 1].min() - 1, train_x_pca[:, 1].max() + 1
xx, yy = np.meshgrid(np.linspace(x_min, x_max, 500),np.linspace(y_min, y_max, 500))# 计算决策函数值
Z = clf_pca.decision_function(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)# 绘制决策边界和间隔带
plt.contour(xx, yy, Z, levels=[0], linewidths=2, colors='green')
plt.contour(xx, yy, Z, levels=[-1, 1], linestyles='--', colors='gray')plt.legend()
plt.title('SVM Decision Boundary (PCA Reduced 2D)')
plt.xlabel('Principal Component 1')
plt.ylabel('Principal Component 2')
plt.show()
  • 用 PCA 将高维特征压缩成 2 维空间。
  • 使用 SVM 在这个低维空间重新训练一个模型(仅用于可视化)。
  • 展示不同类别的点分布情况,以及 SVM 的分界线与间隔。
  1. 完整代码
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import scipy.io as scio
from sklearn import svm 
import re #处理正则表达式的模块
import nltk #自然语言处理工具包
from sklearn.decomposition import PCA#查看样例邮件
f = open('emailSample1.txt', 'r').read()
print(f)def processEmail(email):email = email.lower() #转化为小写email = re.sub('<[^<>]+>', ' ', email) #移除所有HTML标签email = re.sub(r'(http|https)://[^\s]*', 'httpaddr', email) #将所有的URL替换为'httpaddr'email = re.sub(r'[^\s]+@[^\s]+', 'emailaddr', email) #将所有的地址替换为'emailaddr'email = re.sub(r'\d+', 'number', email) #将所有数字替换为'number'email = re.sub('[$]+', 'dollar', email) #将所有美元符号($)替换为'dollar'#将所有单词还原为词根//移除所有非文字类型,空格调整stemmer = nltk.stem.PorterStemmer() #使用Porter算法tokens = re.split(r'[ @$/#.-:&*+=\[\]?!()\{\},\'\">_<;%]', email) #把邮件分割成单个的字符串,[]里面为各种分隔符tokenlist = []for token in tokens:token = re.sub('[^a-zA-Z0-9]', '', token) #去掉任何非字母数字字符try: #porterStemmer有时会出现问题,因此用trytoken = stemmer.stem(token) #词根except:token = ''if len(token) < 1: continue #字符串长度小于1的不添加到tokenlist里tokenlist.append(token)return tokenlist#查看处理后的样例
processed_f = processEmail(f)
for i in processed_f:print(i, end=' ')#得到单词表,序号为索引号+1
vocab_list = np.loadtxt('vocab.txt', dtype='str', usecols=1)
#得到词汇表中的序号
def word_indices(processed_f, vocab_list):indices = []for i in range(len(processed_f)):for j in range(len(vocab_list)):if processed_f[i]!=vocab_list[j]:continueindices.append(j+1)return indices#查看样例序号
f_indices = word_indices(processed_f, vocab_list)
for i in f_indices:print(i, end=' ')def emailFeatures(indices):features = np.zeros((1899))for each in indices:features[each-1] = 1 #若indices在对应单词表的位置上词语存在则记为1return featuressum(emailFeatures(f_indices)) #45def emailFeatures(indices):features = np.zeros((1899))for each in indices:features[each-1] = 1 #若indices在对应单词表的位置上词语存在则记为1return featuressum(emailFeatures(f_indices)) #45#训练模型
train = scio.loadmat('spamTrain.mat')
train_x = train['X']
train_y = train['y']clf = svm.SVC(C=0.1, kernel='linear')
clf.fit(train_x, train_y)#精度
def accuracy(clf, x, y):predict_y = clf.predict(x)m = y.sizecount = 0for i in range(m):count = count + np.abs(int(predict_y[i])-int(y[i])) #避免溢出错误得到225return 1-float(count/m) train_accuracy = accuracy(clf, train_x, train_y) #0.99825
print("Train accuracy:", train_accuracy)#测试模型
test = scio.loadmat('spamTest.mat')test_accuracy = accuracy(clf, test['Xtest'], test['ytest']) #0.989
print("Test accuracy:", test_accuracy)#打印权重最高的前15个词,邮件中出现这些词更容易是垃圾邮件
i = (clf.coef_).size-1
while i >1883:#返回从小到大排序的索引,然后再打印print(vocab_list[np.argsort(clf.coef_).flatten()[i]], end=' ')i = i-1t = open('spamSample2.txt', 'r').read()
#预处理
processed_f = processEmail(t) 
f_indices = word_indices(processed_f, vocab_list)
#特征提取
x = np.reshape(emailFeatures(f_indices), (1,1899))
#预测
clf.predict(x)# 载入训练数据
train = scio.loadmat('spamTrain.mat')
train_x = train['X']
train_y = train['y'].flatten()  # 拉平成1维数组方便使用# 用线性核训练SVM
clf = svm.SVC(C=0.1, kernel='linear')
clf.fit(train_x, train_y)# PCA降维到2维
pca = PCA(n_components=2)
train_x_pca = pca.fit_transform(train_x)# 重新训练一个2维的SVM,用于绘制决策边界
clf_pca = svm.SVC(C=0.1, kernel='linear')
clf_pca.fit(train_x_pca, train_y)# 画图
plt.figure(figsize=(10, 6))# 绘制不同类别样本点
plt.scatter(train_x_pca[train_y==0, 0], train_x_pca[train_y==0, 1], c='blue', label='Non-spam', edgecolors='k')
plt.scatter(train_x_pca[train_y==1, 0], train_x_pca[train_y==1, 1], c='red', label='Spam', edgecolors='k')# 绘制决策边界
# 创建一个网格
x_min, x_max = train_x_pca[:, 0].min() - 1, train_x_pca[:, 0].max() + 1
y_min, y_max = train_x_pca[:, 1].min() - 1, train_x_pca[:, 1].max() + 1
xx, yy = np.meshgrid(np.linspace(x_min, x_max, 500),np.linspace(y_min, y_max, 500))# 计算决策函数值
Z = clf_pca.decision_function(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)# 绘制决策边界和间隔带
plt.contour(xx, yy, Z, levels=[0], linewidths=2, colors='green')
plt.contour(xx, yy, Z, levels=[-1, 1], linestyles='--', colors='gray')plt.legend()
plt.title('SVM Decision Boundary (PCA Reduced 2D)')
plt.xlabel('Principal Component 1')
plt.ylabel('Principal Component 2')
plt.show()

3.运行结果在这里插入图片描述

  1. 决策边界与支持向量带
    绿色实线:SVM 的决策边界(分类超平面),表示模型判断垃圾/非垃圾邮件的分界线。
    灰色虚线(上下各一条):代表 SVM 的“间隔边界”(margin)——支持向量带。
    SVM 的目标就是最大化这两条边界之间的间隔(margin)。
    落在虚线之间的点是支持向量,最影响决策边界的位置。

  2. 分类结果分布
    红色点(Spam):预测为垃圾邮件
    蓝色点(Non-spam):预测为非垃圾邮件
    观察结果:
    大部分红点和蓝点被成功分开,说明模型效果不错。
    决策边界大致水平(沿 x 轴延展),说明分类器主要依据 PCA 的第 2 主成分 进行分类(也就是 y 轴方向)。
    有少量红蓝点混杂,尤其靠近边界或 margin 区域,是分类难度较大的样本,也可能是误分类点。

相关文章:

  • mac电脑安装 nvm 报错如何解决
  • 前端自动化测试利器:Playwright 全面介绍
  • Python-120:摇骰子的胜利概率
  • 23. Merge k Sorted Lists
  • 鸿蒙进阶——Mindspore Lite AI框架源码解读之模型加载详解(一)
  • DAY41 CNN
  • DAY 41 简单CNN
  • Python----目标检测(训练YOLOV8网络)
  • SpringBoot手动实现流式输出方案整理以及SSE规范输出详解
  • JavaSE知识总结(集合篇) ~个人笔记以及不断思考~持续更新
  • 学习经验分享【40】目标检测热力图制作
  • [HTML5]快速掌握canvas
  • (Python网络爬虫);抓取B站404页面小漫画
  • 智慧零工平台前端开发实战:从uni-app到跨平台应用
  • uniapp路由跳转toolbar页面
  • 通俗易懂解析:@ComponentScan 与 @MapperScan 的异同与用法
  • Java连接Redis和基础操作命令
  • 微软markitdown PDF/WORD/HTML文档转Markdown格式软件整合包下载
  • GODOT引擎学习日志
  • Gartner《Emerging Patterns for Building LLM-Based AIAgents》学习心得
  • 北京教育学会网站建设/国外网站排名 top100
  • 学做网站设计/搜索推广
  • 关于做摄影的网站/上海宝山网站制作
  • 丽水做企业网站的公司/seo外链怎么做
  • 做设计排版除了昵图网还有什么网站/采集站seo提高收录
  • 西宁网站制作多少钱/乔拓云网站建设