支持向量机(SVM):原理、应用与挑战
1. SVM基本思想 - 可分情况
在许多实际分类问题中,我们常常希望找到一条线(或超平面)来清晰地划分不同的类别。但在之前的例子里,我们所画的线并不能干净利落地将两类数据分开,线的两侧都存在不同类别的数据点。这种情况不仅在逻辑回归生成的线中常见,在支持向量机(SVM)生成的线中也是如此。不过,为了便于理解SVM的基本思想,我们先考虑两类数据可以被清晰分开的情况。
为了简化讨论,我们聚焦于二分类问题,并且假设特征数量 ( p = 2 ),此时分隔线就是一条直线。这里所说的“数据”,指的是训练数据。我们的目标是为训练数据找到一条边界线,然后依据这条线对未来的数据进行分类预测。
1.1 示例:安德森鸢尾花数据集
R语言中包含的埃德加·安德森的鸢尾花数据集,是众多书籍和网站中常用的示例。该数据集包含三个类别:山鸢尾(setosa)、变色鸢尾(versicolor)和维吉尼亚鸢尾(virginica)。
以下是查看数据集前几行的代码:
> head(iris)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
4 4.6 3.1 1.5 0.2 setosa
5 5.0 3.6 1.4 0.2 setosa
6 5.4 3.9 1.7 0.4 setosa
在这个示例中,我们希望找到能被直线清晰分开的两类数据。当我们选择山鸢尾和非山鸢尾这两类,并以萼片长度(Sepal.Length)和花瓣宽度(Petal.Width)作为特征时,就满足了这个条件。
下面是绘制数据的代码:
> j2 <- iris[,c(2,4,5)] # 萼片宽度,花瓣宽度,物种
# 设置物种编码,山鸢尾为1,非山鸢尾为0
> head(j2)
Sepal.Width Petal.Width Species
1 3.5 0.2 setosa
2 3.0 0.2 setosa
3 3.2 0.2 setosa
4 3.1 0.2 setosa
5 3.6 0.2 setosa
6 3.9 0.4 setosa
> j2$Species <- toSubFactor(j2$Species,'setosa')
> j2[c(7,77),]
Sepal.Width Petal.Width Species
7 3.4 0.3 setosa
77 2.8 1.4 zzzOther
> plot(j2[,1:2],pch=3*as.numeric(j2[,3]))
从绘制的图形中可以看到,我们可以轻松地在两类数据之间画出很多条直线,但哪条直线才是最优的呢?
1.2 优化准则
选择边界线实际上就是选择系数向量 ( w ) 和 ( w_0 ) 项。这与线性模型和广义线性模型类似,我们需要通过优化问题来确定这些系数。在线性模型中,我们通过最小化某个平方和来选择系数;而SVM同样是最小化某个和,但使用的损失函数与平方误差不同。
为了更直观地理解SVM的优化准则,我们可以从几何角度来考虑。首先,我们将两类数据分别围成凸包(convex hulls)。虽然这里只是为了说明原理,实际计算时我们会使用
qeSVM()
函数,不需要手动计算凸包。
从数学上可以证明,SVM的边界线位于两个凸包的“中间”。具体来说,我们先找到两个凸包中距离最近的两个点,边界线就是连接这两个点的线段的垂直平分线。同时,我们还会画出两条与之相关的虚线,这两条虚线所定义的区域就是SVM拟合的“间隔”(margin)。
以下是关于间隔和支持向量的一些重要概念:
-
间隔
:两条虚线之间的区域称为间隔。对于可分数据,间隔内不会有数据点。
-
支持向量
:位于间隔边界上的点称为支持向量(SVM中的SV)。在这个数据集中,我们有三个支持向量,一个属于山鸢尾类,坐标为 (2.7, 1.0);另外两个属于非山鸢尾类,坐标分别为 (2.3, 0.3) 和 (3.5, 0.6)。
在 ( w ) 和 ( w_0 ) 的表示下,对于不同位置的数据点,( w_0 + w \cdot x ) 的值有以下特点:
- 边界上的任意点 ( x ),( w_0 + w \cdot x = 0 )。
- ( Y = +1 ) 类(这里是山鸢尾类)的支持向量,( w_0 + w \cdot x = +1 )。
- ( Y = -1 ) 类(这里是非山鸢尾类)的支持向量,( w_0 + w \cdot x = -1 )。
- ( Y = +1 ) 类的非支持向量,( w_0 + w \cdot x > +1 )。
- ( Y = -1 ) 类的非支持向量,( w_0 + w \cdot x < -1 )。
需要注意的是,( w ) 和 ( w_0 ) 的值并不是唯一的。为了方便计算和比较,我们通常选择让支持向量上的 ( w_0 + w \cdot x ) 的值为 +1 或 -1。
要对新的数据点 ( X = x_{new} ) 进行分类预测,我们根据 ( w_0 + w \cdot x_{new} ) 的值是大于还是小于 0 来猜测其类别为 +1 或 -1。即使我们假设训练数据是可分的,但新的数据点仍有可能落在间隔内。
SVM选择 ( w ) 和 ( w_0 ) 的优化准则是使间隔的宽度最大。这意味着SVM不仅要将两类数据点分开,还要让两类数据尽可能地远离边界,形成一个“缓冲区”,即间隔。训练集中较大的间隔意味着两类数据被很好地分开,这有望使未来的新数据得到正确的分类。
1.3 支持向量的意义
支持向量对模型的拟合起着关键作用。任何一个支持向量的变化都会改变模型的拟合结果,而其他数据点的变化(只要在凸包内)则不会影响模型的拟合。此外,有人认为SVM在可分情况下倾向于产生稀疏拟合,即模型的本质维度较低。但这种观点可能存在问题,因为如果某些支持向量是异常值或错误数据,模型的拟合结果将会严重依赖这些不可靠的数据。而且,由于 ( w ) 对少数支持向量非常敏感,不同的样本可能会有不同的支持向量,导致 ( w ) 具有较高的方差。
下面用mermaid流程图展示SVM在可分情况下的工作流程:
graph TD;
A[获取训练数据] --> B[计算凸包];
B --> C[找到凸包中最近的两点];
C --> D[计算两点连线的垂直平分线作为边界线];
D --> E[确定间隔和支持向量];
E --> F[选择w和w0使间隔最大];
F --> G[用模型对新数据分类];
2. 主要问题:缺乏线性可分性
在实际应用中,大多数情况下两类数据是相互重叠的,不存在能清晰分开两类数据的直线(或超平面)。例如,在鸢尾花数据集中,变色,维吉尼亚鸢尾在某些特征上就无法用直线分开。
> plot(iris[,c(1,3)],pch=as.numeric(iris$Species))
针对这个问题,有两种解决方案:
-
使用核函数进行数据变换
:将数据进行变换,使其变得线性可分或接近线性可分。
-
创建软间隔
:允许部分数据点落在间隔内。
通常,我们会将这两种方法结合使用。因为即使进行了核函数变换,仍然可能找不到能清晰分开数据的超平面,此时就需要允许一些例外的数据点落在间隔内。不过,例外的数据点越少越好,所以最好同时使用这两种方法,而不是直接采用软间隔解决方案。
2.1 应用“核函数”
核函数是一种数据变换方法,其目标是使数据变得可分。核函数 ( K(u, v) ) 是一个以两个向量为输入的函数,许多核函数与点积有关,因为点积在SVM中起着关键作用。
以下是一些常见的核函数:
-
多项式核函数
:
[ K(u, v) = (\gamma u^T v + r)^d ]
其中 ( d ) 和 ( \gamma ) 是超参数。当 ( d = 2 ) 时,与我们之前对 ( X ) 值进行平方变换的效果类似,只不过这里是对向量的点积进行平方。
-
径向基函数(RBF)
:
[ K(u, v) = \exp(-\gamma | u - v |^2) ]
其中 ( \gamma ) 是超参数。
在选择核函数时,并没有一种绝对最优的核函数,这取决于数据集的类型、大小和特征数量等因素。
为了更好地理解核函数的作用,我们来看一个“甜甜圈形状”数据的示例:
# 生成250对以(0,0)为中心的数据点
> set.seed(9999)
> z <- matrix(rnorm(500),ncol=2)
# 从z中选取特定点形成新数据
> plus1 <- z[z[,1]^2 + z[,2]^2 > 4,] # 外圆环,类别+1
> minus1 <- z[z[,1]^2 + z[,2]^2 < 2,] # 内圆盘,类别-1
> plus1 <- cbind(plus1,+1) # 添加Y列
> minus1 <- cbind(minus1,-1) # 添加Y列
> head(plus1) # 查看数据
[,1] [,2] [,3]
[1,] 2.9038161 0.7172792 1
[2,] -0.4499405 2.0006861 1
[3,] 2.3329026 0.2288606 1
[4,] -0.2989460 2.3790936 1
[5,] -2.0778949 0.1488060 1
[6,] -0.9867098 -2.2020235 1
> head(minus1)
[,1] [,2] [,3]
[1,] 1.0840991 0.670507239 -1
[2,] 0.8431089 -0.074557109 -1
[3,] -0.7730161 -0.009357795 -1
[4,] 0.9088839 -1.050183477 -1
[5,] -0.1882887 -1.348365272 -1
[6,] 0.9864382 0.936775923 -1
> pm1 <- rbind(plus1,minus1) # 合并为一个数据集
> plot(pm1[,1:2],pch=pm1[,3]+2)
从绘制的图形中可以看出,这两类数据可以用一个圆分开,但不能用直线分开。我们可以通过添加平方项来解决这个问题:
> pm2 <- pm1[,1:2]^2 # 将每个X值替换为其平方
> pm2 <- cbind(pm2,pm1[,3]) # 将Y添加到新数据集中
> plot(pm2[,1:2],pch=pm2[,3]+2)
经过变换后的数据可以用直线轻松分开。这就是SVM用户通常所做的:尝试找到一种数据变换方法,使变换后的数据变得线性可分或接近线性可分。当然,实际操作中SVM软件会自动完成这些工作,不需要我们手动进行数据变换。
2.2 软间隔
软间隔允许部分数据点落在间隔内,以处理数据缺乏线性可分性的问题。下面介绍两种看待软间隔的方式:
-
几何视角 :不计算原始的凸包,而是使用缩小后的凸包。将两个原始凸包替换为缩小版本,然后根据缩小后的凸包计算间隔。即使训练集中的部分数据会落在间隔内,仍按照正常的流程进行模型拟合。缩小的程度是一个需要用户设置的超参数,通常可以通过交叉验证来确定。
-
代数视角 :更常见的方法是通过“成本”来控制。引入一个成本超参数 ( C ),对于训练集中的数据点 ( X_i ) 和类别标签 ( Y_i ),在可分情况下,间隔边界上的数据点满足 ( w_0 + w \cdot X_i = \pm 1 )。在软间隔情况下,我们允许一定的偏差 ( d_i ),即 ( Y_i (w_0 + w \cdot X_i) \geq 1 - d_i )。
如果 ( 0 < d_i < 1 ),数据点违反了间隔规则,但仍在决策边界的正确一侧,会被正确分类;如果 ( d_i > 1 ),数据点会在决策边界的另一侧,从而被错误分类。
我们通过设置超参数 ( C ) 来控制总偏差量,即 ( \sum_{i=1}^{n} d_i \leq C )。用户选择 ( C ) 的值,不同的 ( w ) 和 ( w_0 ) 组合会产生不同的 ( d_i )。较小的 ( C ) 值意味着间隔内的数据点较少,但间隔宽度也会变窄;我们希望间隔尽可能宽,SVM算法会在满足约束条件的情况下找到使间隔宽度最大的 ( w ) 和 ( w_0 ) 值。
下面用表格总结核函数和软间隔的相关信息:
| 方法 | 原理 | 超参数 | 优点 | 缺点 |
| ---- | ---- | ---- | ---- | ---- |
| 核函数 | 对数据进行变换使其线性可分 | 多项式核:( d, \gamma );RBF:( \gamma ) | 能处理非线性可分数据 | 超参数选择困难 |
| 软间隔 | 允许部分数据点落在间隔内 | ( C ) | 增加模型的灵活性 | 可能导致过拟合 |
3. 示例:森林覆盖数据
下面我们使用
qeSVM()
函数对森林覆盖数据进行分类预测:
> z <- qeSVM(f500,'V55',holdout=NULL)
# 预测一个新的案例,类似数据中的第8个案例,但将第二个特征值改为2888
> newx <- f500[8,1:2]
> newx
V1 V6
8 3085 2977
> newx[2] <- 2888
> predict(z,newx)
$predClasses
[1] "zzzOther"
$probs
1 zzzOther
8 0.4829782 0.5170218
我们预测该案例为非类型1覆盖,不过预测为非类型1的可能性仅略高于类型1。
这里我们使用的是默认值,其中核函数设置为径向基函数。如果我们只想使用软间隔(即不进行核函数变换),可以将核函数设置为线性。超参数
gamma
的默认值为 1.0,可选超参数
cost
对应我们之前讨论的软间隔中的 ( C ) 值。
4. 核技巧
核技巧是SVM成功的关键因素之一。在不使用核函数的情况下,通过多项式变换数据会使数据集的规模大幅增加。例如,使用森林覆盖数据和
polyreg
包进行二次多项式变换时,原始数据集只有 54 个特征,但变换后的数据集特征数量超过 1500 个。这不仅会占用大量的内存,还会使计算时间变得非常长。
而核技巧可以避免计算和存储这些额外的列。通过使用核函数,我们可以在原始特征的基础上进行计算,得到与高维变换后相同的数学结果。例如,在森林覆盖数据中,我们可以直接使用原始的 54 个特征,而不需要计算和存储 1564 个特征。
5. “警告:达到最大迭代次数”
与许多机器学习方法一样,SVM的计算是迭代进行的。但与其他方法不同的是,SVM通常不应该存在收敛问题,因为其搜索空间具有凸性,类似于碗状,容易找到最小值。
然而,如果某些成本值和核函数(及其超参数)的组合不存在能清晰分开两类数据的解,就会出现收敛问题。在这种情况下,我们需要尝试其他的组合。
6. 总结
SVM主要用于分类问题,通过一对多(OVA)或一对一(AVA)配对,SVM可以处理任意数量的类别。为了简化讨论,我们这里主要假设为二分类问题。
- 当特征数量 ( p = 2 ) 时,目标是找到一条直线来分开两类数据;当 ( p = 3 ) 时,要找到一个三维空间中的平面;当 ( p > 3 ) 时,我们需要找到一个超平面。虽然我们无法直观地看到高维超平面,但可以通过计算数据点与超平面的 ( w ) 向量的点积,并加上 ( w_0 ),根据结果的正负来判断数据点的类别。
- 与分隔超平面相关联的是一对平行的超平面,它们形成了间隔。SVM选择 ( w ) 的优化准则是使间隔宽度最大。
- 由于通常情况下两类数据会相互重叠,不存在能清晰分开的超平面,我们需要采用一些人为的方法来解决这个问题,主要有两种方式:一是使用核函数对数据进行变换,使其变得线性可分或接近线性可分;二是创建软间隔,允许部分数据点落在间隔内。这两种方法通常会结合使用。
尽管SVM比之前介绍的一些工具更复杂,但它在实际应用中广泛使用,并且取得了许多成功的案例,因此深入学习SVM是非常值得的。
通过以上内容,我们对SVM的原理、应用和挑战有了更深入的了解。在实际使用SVM时,我们需要根据具体的数据集和问题选择合适的核函数、超参数,并注意可能出现的收敛问题,以获得更好的分类效果。
支持向量机(SVM):原理、应用与挑战
7. SVM在多分类问题中的应用
虽然前面的讨论主要集中在二分类问题上,但SVM可以通过一些策略处理多分类问题。常见的方法有一对多(One - Versus - All, OVA)和一对一(One - Versus - One, OVA)。
-
一对多(OVA) :对于有 ( n ) 个类别的问题,OVA方法会构建 ( n ) 个二分类器。每个二分类器将一个类别与其余所有类别区分开来。例如,在鸢尾花数据集的三个类别(山鸢尾、变色鸢尾、维吉尼亚鸢尾)中,我们会构建三个二分类器:山鸢尾与非山鸢尾、变色鸢尾与非变色鸢尾、维吉尼亚鸢尾与非维吉尼亚鸢尾。对于一个新的数据点,我们将其输入到这三个二分类器中,哪个二分类器输出为正类,就将该数据点分类到对应的类别中。
-
一对一(AVA) :AVA方法会为每一对类别构建一个二分类器。对于 ( n ) 个类别,需要构建 ( C_{n}^2=\frac{n(n - 1)}{2} ) 个二分类器。在鸢尾花数据集中,需要构建 ( C_{3}^2 = 3 ) 个二分类器:山鸢尾与变色鸢尾、山鸢尾与维吉尼亚鸢尾、变色鸢尾与维吉尼亚鸢尾。对于新的数据点,将其输入到所有的二分类器中,统计每个类别被分类为正类的次数,最终将数据点分类到被分类为正类次数最多的类别中。
下面用mermaid流程图展示OVA和AVA的工作流程:
graph LR;
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;
A([多分类数据]):::startend --> B{选择策略}:::decision;
B -->|OVA| C(构建n个二分类器):::process;
B -->|AVA| D(构建n(n - 1)/2个二分类器):::process;
C --> E(对新数据在n个分类器中预测):::process;
D --> F(对新数据在n(n - 1)/2个分类器中预测):::process;
E --> G(选择输出为正类的分类器对应的类别):::process;
F --> H(统计各类别被分类为正类的次数):::process;
H --> I(选择次数最多的类别):::process;
G --> J([输出分类结果]):::startend;
I --> J;
8. 超参数调优
SVM中有多个超参数需要调整,如核函数的参数(多项式核的 ( d ) 和 ( \gamma )、RBF核的 ( \gamma ))、软间隔的成本超参数 ( C ) 等。超参数的选择对SVM的性能有很大影响,下面介绍几种常见的超参数调优方法:
-
网格搜索(Grid Search) :网格搜索是一种简单直接的方法。我们为每个超参数定义一个取值范围,然后对这些取值的所有可能组合进行评估。例如,对于 ( C ) 我们可以选择取值范围为 ([0.1, 1, 10]),对于 ( \gamma ) 选择取值范围为 ([0.01, 0.1, 1]),网格搜索会对 ( C ) 和 ( \gamma ) 的所有 ( 3\times3 = 9 ) 种组合进行评估,选择性能最好的组合作为最终的超参数。
-
随机搜索(Random Search) :随机搜索在超参数的取值范围内随机选择一定数量的组合进行评估。相比于网格搜索,随机搜索可以在更广泛的范围内探索超参数空间,尤其是当超参数较多时,随机搜索可以在较短的时间内找到较好的超参数组合。
下面是使用R语言进行简单网格搜索调优的示例代码:
library(e1071)
# 假设我们有训练数据train_data和对应的标签train_labels
# 定义超参数的取值范围
C_values <- c(0.1, 1, 10)
gamma_values <- c(0.01, 0.1, 1)
best_accuracy <- 0
best_C <- 0
best_gamma <- 0
for (C in C_values) {
for (gamma in gamma_values) {
model <- svm(train_data, train_labels, kernel = "radial", cost = C, gamma = gamma)
predictions <- predict(model, train_data)
accuracy <- sum(predictions == train_labels) / length(train_labels)
if (accuracy > best_accuracy) {
best_accuracy <- accuracy
best_C <- C
best_gamma <- gamma
}
}
}
cat("Best C:", best_C, "\n")
cat("Best gamma:", best_gamma, "\n")
cat("Best accuracy:", best_accuracy, "\n")
9. SVM与其他分类算法的比较
SVM与其他常见的分类算法(如逻辑回归、决策树等)相比,有其独特的优缺点。
| 算法 | 优点 | 缺点 |
|---|---|---|
| SVM |
1. 可以处理非线性可分的数据,通过核函数进行变换。
2. 在高维空间中表现良好。 3. 有严格的数学理论支持,优化目标明确。 |
1. 计算复杂度较高,尤其是在处理大规模数据集时。
2. 超参数调优比较困难,需要一定的经验和技巧。 3. 对缺失数据敏感。 |
| 逻辑回归 |
1. 计算简单,易于理解和实现。
2. 可以输出概率值,方便进行概率预测。 |
1. 只能处理线性可分的数据,对于非线性问题需要进行特征变换。
2. 对异常值比较敏感。 |
| 决策树 |
1. 可以处理非线性数据,不需要进行特征变换。
2. 模型解释性强,易于理解。 |
1. 容易过拟合,尤其是在树的深度较大时。
2. 对数据的微小变化比较敏感,稳定性较差。 |
10. 实际应用场景
SVM在许多领域都有广泛的应用,下面介绍几个典型的应用场景:
-
图像分类 :在图像分类任务中,我们可以将图像的特征(如颜色、纹理等)作为输入,使用SVM对图像进行分类。例如,区分猫和狗的图像,通过提取图像的特征并训练SVM模型,可以实现对新图像的准确分类。
-
文本分类 :在文本分类中,我们通常将文本转换为向量表示(如词袋模型、TF - IDF向量等),然后使用SVM进行分类。例如,将新闻文章分类为体育、政治、娱乐等类别。
-
生物信息学 :在生物信息学中,SVM可以用于基因表达数据分析、蛋白质结构预测等。例如,通过分析基因表达数据,使用SVM预测疾病的发生风险。
11. 未来发展趋势
随着机器学习技术的不断发展,SVM也在不断改进和扩展。以下是一些未来的发展趋势:
-
与深度学习结合 :深度学习在处理大规模数据和复杂任务方面表现出色,而SVM在处理小规模数据和可解释性方面有优势。未来可能会将SVM与深度学习模型结合,发挥两者的优势。例如,使用深度学习模型提取特征,然后使用SVM进行分类。
-
分布式计算 :为了处理大规模数据集,SVM的分布式计算将变得越来越重要。通过将计算任务分布到多个计算节点上,可以提高SVM的计算效率。
-
自适应核函数 :目前核函数的选择和超参数的设置主要依赖于经验和实验,未来可能会出现自适应核函数,根据数据的特点自动选择合适的核函数和超参数。
12. 总结与建议
SVM是一种强大的分类算法,具有处理非线性可分数据的能力,在许多领域都有广泛的应用。但SVM也存在一些挑战,如计算复杂度高、超参数调优等。
在实际应用中,我们可以根据数据集的特点和任务的需求选择合适的分类算法。如果数据集较小且需要较高的可解释性,可以考虑使用SVM;如果数据集较大且任务复杂,可以考虑使用深度学习模型。
为了提高SVM的性能,我们可以采取以下措施:
- 进行数据预处理,处理缺失值和异常值,提高数据的质量。
- 选择合适的核函数和超参数,可以使用网格搜索、随机搜索等方法进行调优。
- 结合其他算法,如使用特征选择算法选择重要的特征,减少数据的维度。
总之,SVM是一个值得深入研究和应用的算法,通过不断的实践和探索,我们可以更好地发挥SVM的优势,解决实际问题。
超级会员免费看
861

被折叠的 条评论
为什么被折叠?



