第10章 支持向量机

目录

1 总述:

2 引入原因:

2.1 用于解决线性不可分问题(如:异或问题)

2.2 更好的泛化能力(强的鲁棒性)

2.3 处理小样本数

2.4 多类别分类

2.5 依赖支持向量(减小存储和计算的开销)

3 前置知识:

3.1 线性可分:

3.2 最大间隔超平面:

3.3 支持向量: 

3.4 SVM最优化问题:

4 如何解决这个最优化问题呢?

4.1 拉格朗日乘子法:

4.1.1 等式约束

4.1.2 不等式约束

4.2 对偶问题:

4.3 求解线性可分的SVM的步骤:

4.4 核函数与软间隔:

4.4.1 核函数引入原因(解决线性不可分):

4.4.2 核函数的作用:

4.4.3 常见的核函数:

4.4.4 软间隔:

4.4.5 求解非线性可分的SVM的步骤:

4.5 松弛变量和惩罚因子:

5 SVM的优缺点 

6 实战(使用支持向量机(SVM)进行线性和非线性分类任务):

6.1 目的:

6.2 步骤:

6.3 代码:

7 本文参考链接:


1 总述:

我们先简单了解一下SVM的关键概念及优缺点,并在下文深入开展探讨。

支持向量机(Support Vector Machine,SVM)是一种常用的监督学习算法,用于二分类和多分类问题。SVM的目标是找到一个最优的超平面,将不同类别的样本分开,并且使得分类边界具有最大的间隔

SVM的主要思想是将数据映射到高维特征空间,并在该空间中寻找一个最优的超平面来进行分类。它基于以下关键概念:

  1. 支持向量:在训练过程中,SVM选择一部分样本作为支持向量,这些支持向量是离分类边界最近的样本点,它们决定了最终的分类结果。

  2. 超平面:在二维空间中,超平面就是一条直线,而在高维空间中,超平面是一个具有 N-1 维的线性子空间,其中 N 是特征的维数。SVM试图找到一个最优的超平面,使得两个不同类别的样本在该超平面上的投影尽可能分开。

  3. 间隔:SVM通过最大化分类边界两侧样本点到超平面的间隔来确定最优超平面。这个间隔被称为几何间隔,是指分类边界两侧最近的样本点到超平面的距离。SVM的目标是找到具有最大几何间隔的超平面。

  4. 核函数:对于非线性可分的问题,SVM使用核函数将输入数据映射到高维特征空间,使其线性可分。常用的核函数有线性核、多项式核、高斯核等。

SVM的训练过程可以简化为一个凸优化问题,通过求解约束最优化问题来确定最优超平面和支持向量。一旦训练完成,SVM可以用于预测新样本的类别。

SVM在实际应用中具有以下优点:

  1. 在处理高维数据和特征空间较小的情况下表现良好。
  2. 可以通过选择不同的核函数适应不同的数据分布和非线性问题。
  3. 通过最大化间隔,SVM对噪声数据具有较强的鲁棒性
  4. 支持向量的数量相对较少,占用内存较少

然而,SVM也有一些注意事项:

  1. 对于大规模数据集,训练时间可能较长
  2. 需要选择合适的核函数和调节相关参数,否则可能导致性能下降。
  3. SVM本身是二分类算法,对于多分类问题需要进行扩展,如使用一对多或一对一策略。

总的来说,SVM是一种强大的分类算法,广泛应用于模式识别、图像分类、文本分类、生物信息学等领域。它在处理小样本、高维数据和非线性问题时表现出色,并且具有较好的泛化能力。

2 引入原因:

在简单了解了SVM是什么之后,我们先思考,我们为什么需要SVM?简单的逻辑回归、线性模型它不香吗?是的,它不香。为什么?

从解决问题的角度讲,有什么问题是SVM能轻松解决但是这哥俩死活解决不了的?

2.1 用于解决线性不可分问题(如:异或问题)

下图这类异或问题,线性模型就解决不了,即找不到任何一条直线能分割两类样本。我们一般有两种思路解决这个问题。一种是用感知机组成的有向图构造函数逼近器,思路是多画几条线以区分样本点,对应多层感知机;另一种就是使用核函数将这些点映射到高维空间,再用超平面分割,对应支持向量机

从更好的解决问题的角度讲,SVM具有啥优势?

2.2 更好的泛化能力(强的鲁棒性)

我们可以看到,SVM找到的超平面拥有强大的泛化能力,对于可能出现的新的接近划分平面的样本点(蓝色标注点)的分类能力强于另外两种方法,因为线性模型很难保证每次都取到距离所有点都很远的划分线。

2.3 处理小样本数

当数据量较小时,逻辑回归和线性模型可能容易过拟合。而SVM通过间隔最大化的策略,可以更好地处理小样本数据,避免过拟合问题。 

2.4 多类别分类

逻辑回归和线性模型通常是二分类器,对于多类别分类问题需要采用其他策略,如一对多或一对一。而SVM本身是二分类器,通过一对多的方式可以直接进行多类别分类。

2.5 依赖支持向量(减小存储和计算的开销)

SVM在训练过程中选择支持向量作为决策边界的依据,这些支持向量是离分类边界最近的样本点。通过依赖支持向量,SVM可以忽略大部分非支持向量样本,从而降低了对整个训练集的依赖,减少了存储和计算的开销。

3 前置知识:

在了解了SVM的引入原因之后,我们需要先了解一些关于SVM的前置知识。

3.1 线性可分:

在二维空间上,两类点被一条直线完全分开叫做线性可分。

3.2 最大间隔超平面:

3.3 支持向量: 

样本中距离超平面最近的一些点,这些点叫做支持向量。

3.4 SVM最优化问题:

SVM想要的就是找到各类样本点到超平面的距离最远,也就是找到最大间隔超平面。任意超平面可以用下面这个线性方程来描述:

一些补充: 

正如聪明的读者所料,添加的系数二分之一平方,皆是为求导数所需;

最小间隔为啥要设置为1呢?这是因为如果我们设置为0等,相当于没有限制条件,若||w||取0的时候,两个直线之间的距离会达到无穷大,此时所有样本点都将落在这两个平行直线内,这不符合我们预期的效果。

4 如何解决这个最优化问题呢?

  • 在标准的线性可分支持向量机(SVM)中,优化问题是一个凸二次规划问题。其目标是最小化一个带有约束的凸二次目标函数,其中约束包括数据点的正确分类和间隔的限制。通过拉格朗日乘子法和KKT条件,可以将这个问题转化为对拉格朗日乘子进行求解的凸二次规划问题。
  • 然而,在实际应用中,当数据线性不可分或需要使用非线性决策边界时,SVM可以通过引入核函数来进行扩展,构建非线性SVM。这时,优化问题变成了一个凸二次规划的对偶问题,而不是非凸问题。通过求解对偶问题,可以得到最优解。
  • 对偶问题是通过对原始问题中的拉格朗日乘子进行求解得到的。对于线性可分的SVM,原始问题和对偶问题是等价的,即它们具有相同的最优解。但是,在引入核函数后,原始问题变为非凸问题,而对偶问题仍然是凸二次规划问题,并且可以通过合适的核函数进行求解。
  • 因此,在线性可分的情况下,SVM的优化问题是一个凸二次规划问题;而在引入核函数构建非线性SVM时,优化问题变为凸二次规划的对偶问题。

4.1 拉格朗日乘子法:

整体思路是通过引入拉格朗日乘子,可将有 d 个变量与 k 个约束条件的最优化问题转化为具有 d+k 个变量的无约束优化问题求解。

如果高数上讲的拉格朗日乘子法忘完了,请先浏览这篇博客:优化-拉格朗日乘子法 - 知乎

浅浅总结一下,对约束条件分情况讨论,约束条件一般分为两种——等式约束和不等式约束。

4.1.1 等式约束

4.1.2 不等式约束

4.2 对偶问题:

拉格朗日里面有个对偶问题,这里需要提一下,不然后面公式推导会有问题。我们通俗的讲就是这样的:

4.3 求解线性可分的SVM的步骤:

  1. 构造拉格朗日函数:根据SVM的优化目标和约束条件,构造拉格朗日函数。拉格朗日函数由原始问题的目标函数和约束条件组成,通过引入拉格朗日乘子来表示约束条件。(这样做的好处是,我们可以使用拉格朗日乘子来表示约束条件,并将原始问题转化为一个包含拉格朗日乘子的优化问题。)

  2. 强对偶性转化:利用强对偶性质,将原始问题转化为对拉格朗日乘子进行求解的问题。这意味着最优解可以通过求解对偶问题得到。(通过转化为对偶问题,我们可以更方便地求解优化问题。对偶问题的求解通常更高效,因为它的变量维度与训练样本数量相关,而不是特征的维度。)

  3. 使用序列最小最优化(Sequential Minimal Optimization,SMO)算法求解对偶问题:SMO算法是一种常用的求解SVM对偶问题的方法。它通过选取一对拉格朗日乘子,并固定其他拉格朗日乘子来最小化对偶问题的目标函数。这个步骤是迭代进行的,直到满足收敛条件。(这种逐步优化的方法使得求解过程更加高效,并且能够处理大规模数据集。)

  4. 计算权重和偏置:在求解对偶问题后,可以根据最优的拉格朗日乘子计算权重向量和偏置项。权重向量可以用于定义最大分割超平面,而偏置项则用于划分数据点的类别。

  5. 得到最大分割超平面。

4.4 核函数与软间隔:

这部分是SVM的精髓。我们之前推导的SMO算法等都是在线性约束条件下的,但是面对非线性问题以及一些线性不可分的问题的时候,我们还是需要核函数映射一下的,把非线性问题转化为线性问题求解。

例如:左下图中线性不可分,这种情况的解决方法就是:将二维线性不可分样本映射到高维空间中,让样本点在高维空间线性可分,比如:

4.4.1 核函数引入原因(解决线性不可分):

非线性问题的求解大概分两步:

  1. 把非线性问题在高维空间转化为线性问题
  2. 找到对应的核函数,在求解时把高维的问题在低维下求解

对于在有限维度向量空间中线性不可分的样本,我们将其映射到更高维度的向量空间里,再通过间隔最大化的方式,学习得到支持向量机,就是非线性SVM。

4.4.2 核函数的作用:

 也就是核技巧允许我们在算法中使用核函数的形式,而无需直接计算高维特征空间的内积。

4.4.3 常见的核函数:

4.4.4 软间隔:

软间隔是允许SVM存在分错的样本,但是要控制其错误数量尽可能的少。所以软间隔SVM引入了一个描述分错样本数量的损失,加入了目标函数共同进行优化。

SVM因为支持向量的选取的原因,很容易受噪声干扰,在现实中很容易因为部分样本导致支持向量间距过窄。这个时候我们引入软间隔,允许部分样本在间隔内。两者对比图如下。 

软间隔SVM的原理推导同硬间隔SVM,只是在目标函数中多了一个正则项。对于软间隔SVM,在间隔内的点同样可以影响超平面的位置,所以也属于支持向量。 

4.4.5 求解非线性可分的SVM的步骤:

使用核函数求解非线性支持向量机(SVM)的步骤可以总结如下:

  1. 数据准备:准备训练数据集,包括输入特征和对应的类别标签。

  2. 核函数选择:根据问题的性质和数据的分布,选择适合的核函数,如线性核函数、多项式核函数、高斯径向基函数核等。

  3. 核矩阵计算:通过核函数计算训练集中样本两两之间的核函数值,构成一个核矩阵。核矩阵的每个元素表示两个样本在高维特征空间中的内积。

  4. 优化问题建立:将核矩阵代入SVM的对偶问题中,构建优化问题。优化问题的目标是最大化间隔,并且满足一定的约束条件。

  5. 求解优化问题:使用相应的优化算法(如SMO算法)求解对偶问题,得到最优的拉格朗日乘子。

  6. 计算权重和偏置:根据最优的拉格朗日乘子,计算权重向量和偏置项,用于定义最大分割超平面。

  7. 预测新样本:对于新的样本,将其通过核函数映射到高维特征空间,然后使用计算得到的权重向量和偏置项进行分类预测。

4.5 松弛变量和惩罚因子:

如果使用核函数向高维空间映射后,问题仍然是线性不可分的,那怎么办?

在支持向量机(SVM)中,为了处理线性不可分的情况,引入了松弛变量和惩罚因子。

松弛变量是一组非负变量,用于允许一些样本点位于错误的一侧或在间隔边界上。它们允许在一定程度上违反线性分割规则,以处理线性不可分的情况。每个样本点都会对应一个松弛变量,用于衡量其违反分类规则的程度。

惩罚因子是一个超参数(通常表示为C),用于控制松弛变量的权重。它决定了对误分类的惩罚程度。较大的惩罚因子会使模型更加关注分类的准确性,对错误分类的容忍程度较低;而较小的惩罚因子则会更加容忍错误分类,允许更多的样本点违反分类规则。

通过引入松弛变量和惩罚因子,SVM的优化目标可以重新定义为最小化分类误差和松弛变量的总和,同时尽量使间隔最大化。这可以通过解决一个带有约束的优化问题来实现。

在支持向量机(SVM)的参数设置中,通常使用惩罚因子 C 控制训练误差和模型复杂度之间的权衡。这个惩罚因子 C 就是用来调整松弛变量的,它控制了对误分类样本的惩罚程度,从而影响了最终决策边界的位置。

松弛变量本身并不是一个独立的参数,而是由惩罚因子 C 控制的。因此,在设置 SVM 模型时,通过调整 C 的值来间接地控制松弛变量的影响,从而实现对模型的调优。

具体的请参考SVM(支持向量机)原理及数学推导全过程详解(附MATLAB程序) - 知乎

SVM(六):带松弛变量的SVM数学模型_松弛变量怎么加-CSDN博客

5 SVM的优缺点 

优点:

  • 有严格的数学理论支持,可解释性强,不依靠统计方法,从而简化了通常的分类和回归问题;
  • 能找出对任务至关重要的关键样本(即:支持向量);
  • 采用核技巧之后,可以处理非线性分类/回归任务;
  • 最终决策函数只由少数的支持向量所确定,计算的复杂性取决于支持向量的数目,而不是样本空间的维数,这在某种意义上避免了“维数灾难”。

缺点:

  • 训练时间长。当采用SMO算法时,由于每次都需要挑选一对参数,因此时间复杂度O(N^2),其中N为训练样本的数量;
  • 当采用核技巧时,如果需要存储核矩阵,则空间复杂度为O(N^2);
  • 模型预测时,预测时间与支持向量的个数成正比。当支持向量的数量较大时,预测计算复杂度较高。

因此支持向量机目前只适合小批量样本的任务,无法适应百万甚至上亿样本的任务。

6 实战(使用支持向量机(SVM)进行线性和非线性分类任务):

6.1 目的:

使用支持向量机(SVM)进行线性和非线性分类任务。

6.2 步骤:

  1. 导入需要的库:numpymatplotlibdatasetsStandardScaler等。

  2. 使用datasets.load_iris()加载鸢尾花数据集,并选择只使用前两个特征。

  3. 对特征进行标准化处理,使用StandardScaler将特征按照均值为0、方差为1的方式进行缩放。

  4. 创建一个线性SVM模型,并使用标准化后的特征进行训练。

  5. 定义了一个名为plot_decision_boundary的函数,用于绘制决策边界。函数内部使用网格化的方式生成决策边界的预测结果,并使用contourf函数进行可视化。

  6. 绘制线性SVM模型的决策边界和样本点的散点图。

  7. 定义了一个名为plot_svc_decision_boundary的函数,用于绘制SVM模型的决策边界和间隔边界。函数内部除了绘制决策边界外,还绘制了间隔边界(即支持向量)的两条直线。

  8. 绘制线性SVM模型的决策边界、间隔边界和样本点的散点图。

  9. 生成一个非线性可分的数据集,并绘制散点图。

  10. 使用SVM中的多项式核函数构建一个非线性SVM模型,其中核函数采用RBF(径向基函数)核。

  11. 绘制非线性SVM模型的决策边界和样本点的散点图。

6.3 代码:

import numpy as np
import matplotlib
matplotlib.use("TkAgg")
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.preprocessing import StandardScaler#用于数据预处理的类
iris = datasets.load_iris()#鸢尾花(Iris)数据集
X = iris.data
y = iris.target
X = X[y<2,:2]#只使用前两个特征
y = y[y<2]#只保留了两个类别的样本
standardScaler = StandardScaler()
standardScaler.fit(X)
X_standard = standardScaler.transform(X)#将特征按照均值为0、方差为1的方式进行缩放,消除特征之间的量纲差异

# SVM线性分割
from sklearn.svm import LinearSVC # Support Vector Classifier
svc = LinearSVC(C=1e9) # 参数C表示正则化参数,其中C的值越大,表示模型对错误分类的惩罚越大,即越倾向于拟合训练数据
svc.fit(X_standard, y)#训练,拟合
def plot_decision_boundary(model, axis):#绘制决策边界
    x0, x1 = np.meshgrid(
        np.linspace(axis[0], axis[1], int((axis[1]-axis[0])*100)).reshape(-1, 1),
        np.linspace(axis[2], axis[3], int((axis[3]-axis[2])*100)).reshape(-1, 1),)
    X_new = np.c_[x0.ravel(), x1.ravel()]
    y_predict = model.predict(X_new)
    zz = y_predict.reshape(x0.shape)
    from matplotlib.colors import ListedColormap
    custom_cmap = ListedColormap(['#EF9A9A','#FFF59D','#90CAF9'])
    plt.contourf(x0, x1, zz, cmap=custom_cmap)
plot_decision_boundary(svc, axis=[-3, 3, -3, 3])
## 需要标准化之后的
plt.scatter(X_standard[y==0,0], X_standard[y==0,1], color='red')
plt.scatter(X_standard[y==1,0], X_standard[y==1,1], color='blue')
plt.show()

# 绘制margin
def plot_svc_decision_boundary(model, axis):#绘制SVM模型的决策边界和间隔边界
    x0, x1 = np.meshgrid(
        np.linspace(axis[0], axis[1], int((axis[1]-axis[0])*100)).reshape(-1, 1),
        np.linspace(axis[2], axis[3], int((axis[3]-axis[2])*100)).reshape(-1, 1),)
    X_new = np.c_[x0.ravel(), x1.ravel()]
    y_predict = model.predict(X_new)
    zz = y_predict.reshape(x0.shape)
    from matplotlib.colors import ListedColormap
    custom_cmap = ListedColormap(['#EF9A9A','#FFF59D','#90CAF9'])
    plt.contourf(x0, x1, zz, cmap=custom_cmap)
    # 增加margin的那两根直线
    w = model.coef_[0]
    b = model.intercept_[0]
    # w0*x0 + w1*x1 + b = 0
    # => x1 = -w0/w1 * x0 - b/w1  纵轴
    plot_x = np.linspace(axis[0], axis[1], 200)
    up_y =  -w[0]/w[1] * plot_x - b/w[1]  + 1/w[1]
    down_y =  -w[0]/w[1] * plot_x - b/w[1]  - 1/w[1]
    up_index = (up_y >= axis[2]) & (up_y <= axis[3])
    down_index = (down_y >= axis[2]) & (down_y <= axis[3])
    plt.plot(plot_x[up_index], up_y[up_index], color='black')
    plt.plot(plot_x[down_index], down_y[down_index], color='black')
# hard svm margin 两个直线里面没有样本
plot_svc_decision_boundary(svc, axis=[-3, 3, -3, 3])
plt.scatter(X_standard[y==0,0], X_standard[y==0,1], color='red')
plt.scatter(X_standard[y==1,0], X_standard[y==1,1], color='blue')
plt.show()

# SVM非线性分割
X, y = datasets.make_moons(noise=0.15,random_state=666)#使用Scikit-learn的datasets模块中的make_moons函数生成一个非线性可分的数据集。参数noise表示添加的噪声水平
plt.scatter(X[y==0, 0], X[y==0, 1])
plt.scatter(X[y==1, 0], X[y==1, 1])
plt.show()
# 使用SVC中的多项式核函数
from sklearn.preprocessing import PolynomialFeatures#用于生成多项式特征的预处理类
from sklearn.svm import SVC
from sklearn.pipeline import Pipeline#它允许将多个预处理步骤和估计器(模型)组合在一起,形成一个完整的工作流程
def plot_decision_boundary(model, axis):#决策边界
    x0, x1 = np.meshgrid(
        np.linspace(axis[0], axis[1], int((axis[1]-axis[0])*100)).reshape(-1, 1),
        np.linspace(axis[2], axis[3], int((axis[3]-axis[2])*100)).reshape(-1, 1),)
    X_new = np.c_[x0.ravel(), x1.ravel()]
    y_predict = model.predict(X_new)
    zz = y_predict.reshape(x0.shape)
    from matplotlib.colors import ListedColormap
    custom_cmap = ListedColormap(['#EF9A9A','#FFF59D','#90CAF9'])
    plt.contourf(x0, x1, zz, cmap=custom_cmap)
def RBFKernelSVC(gamma =1.0):
    return Pipeline([
        ("std_scaler", StandardScaler()),#特征标准化
        ("rbfSVC", SVC(kernel='rbf', gamma=gamma)),#核函数为RBF核(径向基函数核)。参数gamma用于控制核函数的宽度,较小的gamma值会导致较宽的RBF核,而较大的gamma值会导致较窄的RBF核。
    ])
rbf_svc = RBFKernelSVC()
print(rbf_svc.fit(X, y))
plot_decision_boundary(rbf_svc,axis=[-1.5, 2.5, -1, 1.5])
plt.scatter(X[y==0, 0], X[y==0, 1])
plt.scatter(X[y==1, 0], X[y==1, 1])
plt.show()

线性SVM: 

非线性SVM:

7 本文参考链接:

支持向量机(SVM)原理详解、公式推导(手推)、面试问题、简单实例(sklearn调包)

SVM详解

SVM(支持向量机)原理及数学推导全过程详解(附MATLAB程序)  

  • 28
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值