1、SVM相关

基本概念

  • 超平面:比数据集的变量少一个维度的平面,也称为决策边界;
  • 间隔:(对于硬间隔)训练数据中最接近决策边界的样本点与决策边界之间的距离;
  • 支持向量:(对于硬间隔)接触间隔边界的数据样本,它们是支持超平面的位置。(对于软间隔)间隔内的样本点也属于支持向量,因为移动它们也会改变超平面的位置。

如下图所示,SVM算法将寻找一个最优的线性超平面进行分类。

Support Vector Machine(SVM): A Complete guide for beginners

超参数类别

1、间隔与cost超参数

(1)如上图所示的间隔内没有样本点,是比较理想的超平面。

(2)当类别并不能完美的分隔开,如果一味追求上述的结果,可能造成过拟合,甚至无法找到超平面。

(3)cost(C)超参数用于表示对间隔内存在的样本的惩罚。cost越大,代表越不允许间隔内存在样本,容易过拟合;cost越小,代表间隔内的样本数据就越多,容易欠拟合。

algorithm - SVM - hard or soft margins? - Stack Overflow

2、核函数与kernel超参数

如果当前维度的数据找不到一个合适线性超平面,SVM通过核方法会引入一个新的维度,使变得线性可分。

  • (1)将线性不可分的数据(n个特征向量,n维)增加一个维度(enlarged kernel-induced feature space),从而成为线性可分数据(n+1)维;

  • (2)在n+1 维的空间里确定合适的决策边界(线性);然后投射到原来n维空间中,即得到我们真正需要的决策平面(非线性)

常见的核方法有:多项式核函数、高斯径向基核函数、sigmoid核函数等

image-20220407174357088

3、gamma超参数

  • gamma超参数越大,表明单个样本对决策边界的位置影响越大,导致决策边界越复杂,越容易过拟合。

SVM | Support Vector Machine Algorithm in Machine Learning

SVM的分类性能确实比其他算法好,但同时SVM模型的计算开销也大,而且有多个超参数需要优化。所以训练处性能最优的SVM模型需要花费相当长的时间。

2、mlr建模

1
library(mlr)

2.1 垃圾邮件特征数据

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
data(spam, package = "kernlab")
spamTib <- spam
head(spamTib)
dim(spamTib)
# [1] 4601   58
##最后一列为标签列:是否为垃圾数据
##前面的57列均为邮件的特征数据,且都是数值型。
table(spamTib$type)
# nonspam    spam 
#    2788    1813

Note: (1)SVM算法不能处理分类预测变量。(2)SVM算法对不同尺度的变量很敏感,需要归一化处理

2.2 确定预测目标与训练方法

  • 根据57列的邮件特征数据预测该邮件是否为垃圾邮件
1
spamTask <- makeClassifTask(data = spamTib, target = "type")
  • 使用SVM分类算法,并设置候选超参数范围
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
##(1)定义学习器方法
svm <- makeLearner("classif.svm")

##(2)查看SVM算法的超参数
getParamSet("classif.svm")
#                        Type  len             Def                             Constr Req Tunable Trafo
# type               discrete    - C-classifica... C-classification,nu-classification   -    TRUE     -
# cost                numeric    -               1                           0 to Inf   Y    TRUE     -
# kernel             discrete    -          radial   linear,polynomial,radial,sigmoid   -    TRUE     -
# degree              integer    -               3                           1 to Inf   Y    TRUE     -
# gamma               numeric    -               -                           0 to Inf   Y    TRUE     -
# scale         logicalvector <NA>            TRUE                                  -   -    TRUE     -

## Type列:超参数值的类型,可以是数值、整型、离散值或逻辑值
## Def列:默认值。如果不调节超参数,将使用默认值。
## Constr:取值范围
## Req:学习器是否需要超参数
## Tunable:学习器是否需要超参数

##(3)自定义超参数空间
svmParamSpace <- makeParamSet(
  makeDiscreteParam("kernel", values = c("polynomial", "radial", "sigmoid")),
  makeIntegerParam("degree", lower = 1, upper = 3),
  makeNumericParam("cost", lower = 0.1, upper = 10),
  makeDiscreteParam("gamma", values = seq(0.1,10, 0.1)))
# 共 3*3*100*100=90000种超参数组合

Note:(1)makeDiscreteParam()适用于接受特定值的超参数,可以是各种类型的。(2)makeIntegerParam与makeNumericParam的lower与upper参数分别指定最小值与最大值,步长分别是1、0.1。(3)对于SVM的kernel的linear等价于degree为1的polynomial。

  • 定义参数组合遍历方法与交叉验证方法
1
2
3
4
5
6
7
##(1) 遍历组合:随机搜索(不能确保找到最优组合,可找到良好的组合)
randSearch <- makeTuneControlRandom(maxit = 50)
# maxit = 50 表示从90000种组合中随机挑选50种组合,取其中性能最优的。

##(2) 交叉验证
cvForTuning <- makeResampleDesc("Holdout", split = 2/3)
#如上使用了留出法的交叉验证方法

Note:在计算资源与时间允许的情况下应该尽可能遍历多组超参数组合,并且使用10折交叉验证方式。

2.3 模型训练

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#由于训练SVM模型耗时,使用下面的并行策略,不足就是无法查看进程
library(parallel)
library(parallelMap)
detectCores() #查看当前电脑的核数

##(1)开始训练:设置调用的进程数
parallelStartSocket(cpus = 8)
tunedSvmPars <- tuneParams("classif.svm", task = spamTask,
                           resampling = cvForTuning, 
                           par.set = svmParamSpace, 
                           control = randSearch)

##(2)训练结束,停止进程
parallelStop()

##(3) 查看随机搜索的最佳超参数组合
tunedSvmPars
# Tune result:
# Op. pars: kernel=polynomial; degree=1; cost=6.93; gamma=4.4
# mmce.test.mean=0.0651890
tunedSvmPars$x
# $kernel
# [1] "polynomial"
# $degree
# [1] 1
# $cost
# [1] 6.933503
# $gamma
# [1] 4.4

SvmTuningData <- generateHyperParsEffectData(tunedSvmPars,partial.dep=T)
head(SvmTuningData$data)
#       kernel degree      cost gamma mmce.test.mean iteration exec.time
# 1    sigmoid      3 0.5896223   3.1      0.2314211         1      2.50
# 2 polynomial      2 5.1783061   4.6      0.1264668         2      8.68
# 3 polynomial      2 9.0000612   5.4      0.1264668         3     13.31
# 4    sigmoid      2 7.4176505   6.3      0.2353325         4      2.37
# 5    sigmoid      1 7.4689163   1.9      0.2392438         5      2.62
# 6     radial      3 7.8813946   1.7      0.2327249         6      7.88

2.4 嵌套交叉验证

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#inner
inner <- makeResampleDesc("Holdout", split = 2/3)
#outer
outer <- makeResampleDesc("CV", iters = 3)

#在内循环寻找最佳的超参数交给外循环
svmWrapper <- makeTuneWrapper("classif.svm", resampling = inner, 
                              par.set = svmParamSpace, 
                              control = randSearch)

parallelStartSocket(cpus = 8)
cvWithTuning <- resample(svmWrapper, spamTask, resampling = outer)
parallelStop()

##查看结果
cvWithTuning
# Resample Result
# Task: spamTib
# Learner: classif.svm.tuned
# Aggr perf: mmce.test.mean=0.0710711
# Runtime: 66.8189