R语言中的数据挖掘算法/分类/惩罚SVM
分类器是最常见的数据分析工具之一。有很多已实现的技术,但我们可以将SVM(支持向量机)作为最强大的技术之一,尤其是在高维数据中。最著名的SVM算法是由弗拉基米尔·瓦普尼克创建的。[1]
标准的SVM实现SVM接收一个输入数据集,并针对每个给定的输入预测该输入集属于两个可能类别中的哪一个。这是算法最常见的用途,用于预测输入是否属于某个二分法,或者不属于。由于此特性,SVM被称为非概率二元线性分类器。
在基于机器学习的算法(如SVM)中,输入数据必须分成两个集合:训练集和测试集。训练集和测试集之间的区别在于,在训练集中,示例的类别事先已知。测试集包含应该预测其类别的示例。给定一组训练示例,SVM算法构建一个模型来预测测试集示例的类别。
在d维空间中表示示例,算法构建的模型是一个超平面,它将属于二分法的示例与不属于二分法的示例分开。然后将新示例映射到该空间,以便我们可以根据其落入的间隙的哪一侧来预测其所属的类别。
此处描述的技术是使用惩罚函数的标准SVM的变体。该技术在称为惩罚SVM的R包中实现,该包具有平滑截断绝对偏差(SCAD)、“L1范数”、“弹性网络”(“L1范数”和“L2范数”)和“弹性SCAD”(SCAD和“L2范数”)作为可用的惩罚。
事实上,找到最佳模型来对新示例进行分类类似于找到最佳超平面的问题。算法构建的模型的质量通过其超平面的边距来衡量。边距是超平面wx+b = 1和wx+b = -1之间的距离,因此每个超平面的一侧最靠近wx+b = 0的点都被另外两个超平面穿过。最佳超平面是具有最大边距的超平面。
找到具有最大边距的最佳超平面的问题通过凸优化来解决。最大化边距可以通过求解以下问题来实现:
术语
在 SVM 实现中具有 L2 范数('岭惩罚')的形式。这种惩罚会导致系数的减少,但并不总是减少到大于零的值。
模型的质量也可以通过计算训练集预测误差来衡量。需要较低的预测误差,但将其降低到零可能会导致一个称为过拟合的问题。这意味着构建的模型能够很好地对训练集中的样本进行分类,但并不适合对测试集中的样本进行分类。在这种情况下,对新样本的预测通常会出错。
不仅低预测误差定义了模型的质量。可以通过识别在判别中起重要作用的协变量并评估其对分类器的贡献来进一步改进模型。这可以通过应用特征选择方法来实现。
特征选择方法分为两类:过滤方法和包装方法[2]。过滤方法在算法构建模型之前丢弃不相关的特征。包装方法通过在优化过程中进行选择来提高预测能力。
R 包 'penalizedSVM' 提供了一些特征选择方法。其中之一是包装特征选择 SCAD(平滑剪切绝对偏差)。SCAD 是一种非凸惩罚函数,最初由 Fan[3]提出,并在[4]中进行了讨论。[5]将 SVM 与 SCAD 相结合用于特征选择。SCAD SVM 的惩罚项形式为
其中,每个系数 wj 的 SCAD 惩罚函数定义为
其中调整参数 a > 2(在包中,a = 3.7)和 λ > 0。pλ (w) 对应于在 λ 和 aλ 处有节点的二次样条函数。
对于较小的系数,SCAD 与 L1 的行为相同。然而,对于较大的系数,SCAD 应用恒定惩罚,这与 L1 惩罚形成对比,后者随着系数的增加而线性增加。SCAD 惩罚的这个绝对最大值独立于输入数据,减少了估计大系数的可能偏差。
本节描述的包为 penalizedSVM。此包使用惩罚函数提供特征选择 SVM。平滑剪切绝对偏差 (SCAD)、'L1 范数'、'弹性网络'('L1 范数' 和 'L2 范数')和 '弹性 SCAD'(SCAD 和 'L2 范数')惩罚可用。可以使用固定网格或区间搜索找到调整参数。
此包有几个依赖项。需要安装的包及其描述如下所示
- e1071 用于潜在类别分析、短时傅里叶变换、模糊聚类、支持
向量机、最短路径计算、袋装聚类、朴素贝叶斯分类器等。
- MASS支持 Venables 和 Ripley 的函数和数据集,'现代应用统计与 S'(第 4
版)。
- corpcor此包实现了用于协方差矩阵的 James-Stein 型收缩估计器,
分别对方差和相关性进行收缩。该方法的详细信息在 Sch\"afer 和 Strimmer (2005) 以及 Opgen-Rhein 和 Strimmer (2007) 中有解释。
- stadmod 各种统计建模函数,包括生长曲线比较、限制稀释
分析、混合线性模型、异方差回归、Tweedie 族广义线性模型、逆高斯分布和高斯求积。
- tgp 基于树的高斯过程的贝叶斯非平稳、半参数非线性回归和设计
带有跳跃到限制线性模型 (LLM)。
- mlepg 用于单变量和多维输出的最大似然高斯过程建模
带有诊断图。请联系维护者获取实现灵敏度分析功能的包版本。
- lhs 此包提供了多种创建和增强拉丁超立方样本的方法
penalizedSVM 中的主要函数是 svm.fs。其用法可以描述如下
## Default S3 method: svm.fs( x, y, fs.method = c("scad", "1norm", "scad+L2", "DrHSVM"), ### tuning parameter settings # chose the search method for tuning lambda1,2: 'interval' or 'discrete' grid.search=c("interval","discrete"), #fixed grid for lambda1, lambda2 lambda1.set=NULL, lambda2.set=NULL, # define range for lambda1,2 for interval search bounds=NULL, # parms.coding="none" or "log2" parms.coding= c("log2","none"), # internal parameter for DIRECT maxevals=500, ### valuidation settings # fot nested validation, 'cross.outer'-fold cv #cross.outer= 0, # method for the inner validation: cross validation, gacv inner.val.method = c("cv", "gacv"), # 'cross.inner'-fold cv cross.inner= 5, # show plots in Direct? show= c("none", "final"), ### other settings # internal parameter for svm calc.class.weights=FALSE, class.weights=NULL, #seed seed=123, # max iterations for the feature selection svm method maxIter=700, # verbose? verbose=TRUE, ...)
其中参数为
- x: 输入矩阵,列为基因,行为样本!
- y: 类标签的数值向量,-1,1
- fs.method: 特征选择方法。可用 'scad'、'1norm' 表示 1 范数、"DrHSVM" 表示弹性网络和 "scad+L2" 表示弹性 SCAD
- grid.search: 选择 lambda1、2 的搜索方法:'interval' 或 'discrete',默认:'interval'
- lambda1.set: 用于固定网格搜索:lambda1 的固定网格,默认:NULL
- lambda2.set: 用于固定网格搜索:lambda2 的固定网格,默认值:NULL
- bounds: 用于区间网格搜索:lambda2 的固定网格,默认值:NULL
- parms.coding: 用于区间网格搜索:parms.coding:none 或 log2,默认值:log2
- maxevals: DIRECT 函数评估的最大次数,默认值:500。
- cross.outer: 外层交叉验证的折叠数,默认值为 0,表示不进行交叉验证。
- calc.class.weights: 为 SVM 计算 class.weights,默认值:FALSE
- class.weights: 用于非对称类的不同类的权重命名向量。
大小。并非所有因子水平都需要提供(默认权重:1)。所有组件都必须命名。
- inner.val.method: 内部验证的方法:交叉验证、gacv,默认 cv
- cross.inner: ‘cross.inner’ 折叠交叉验证,默认值:5
- show: 用于区间搜索:显示 DIRECT 算法的绘图:none、最终迭代、所有迭代。默认值:none
- seed: 随机数种子
- maxIter: 最大迭代次数,默认值:700
- verbose: 是否详细输出?默认值:TRUE
- ... additional: 其他参数
要可视化算法的结果,可以使用 show 函数,如上例所示。
在本节中,我们将说明一个使用 penalizedSVM 的案例研究。
目标是判断一张图片是否属于之前选择的那张图片的同一类别。为此,我们使用这些特征值之间的差异。用作输入的数据的属性表示所选图片中特征值的差异以及我们想要分类的图片。
训练集和测试集是使用下面显示的命令生成的。
> train<-sim.data(n = 200, ng = 100, nsg = 10, corr=FALSE, seed=seed ) > print(str(train)) List of 3 $ x : num [1:100, 1:200] -0.5605 2.1988 -0.0736 1.074 0.3563 ... ..- attr(*, "dimnames")=List of 2 .. ..$ : chr [1:100] "pos1" "pos2" "pos3" "pos4" ... .. ..$ : chr [1:200] "1" "2" "3" "4" ... $ y : Named num [1:200] 1 -1 1 1 1 -1 -1 -1 1 -1 ... ..- attr(*, "names")= chr [1:200] "1" "2" "3" "4" ... $ seed: num 123 NULL > test<-sim.data(n =20, ng = 100, nsg = 10, corr=FALSE, seed=seed+1 ) > print(str(test)) List of 3 $ x : num [1:100, 1:20] -1.3851 -1.1036 -0.2677 0.2836 -0.0951 ... ..- attr(*, "dimnames")=List of 2 .. ..$ : chr [1:100] "pos1" "pos2" "pos3" "pos4" ... .. ..$ : chr [1:20] "1" "2" "3" "4" ... $ y : Named num [1:20] -1 1 -1 1 1 1 1 1 1 -1 ... ..- attr(*, "names")= chr [1:20] "1" "2" "3" "4" ... $ seed: num 124 NULL
要构建模型,使用以下命令。
> bounds=t(data.frame(log2lambda1=c(-10, 10))) >colnames(bounds)<-c("lower", "upper") # computation intensive; for demostration reasons only for the first 100 features # and only for 10 Iterations maxIter=10, default maxIter=700 >system.time( scad<- svm.fs(t(train$x)[,1:100], y=train$y, fs.method="scad", bounds=bounds, + cross.outer= 0, grid.search = "interval", maxIter = 10, + inner.val.method = "cv", cross.inner= 5, maxevals=500, + seed=seed, parms.coding = "log2", show="none", verbose=FALSE ) )
查看创建的模型。
> print(str(scad$model)) List of 11 $ w : Named num [1:23] 0.625 0.616 0.353 0.258 0.959 ... ..- attr(*, "names")= chr [1:23] "pos1" "pos2" "pos3" "pos4" ... $ b : num -0.115 $ xind : int [1:23] 1 2 3 4 5 6 7 8 9 10 ... $ index : int [1:83] 3 4 9 14 17 18 22 35 37 40 ... $ fitted : num [1:200] 2.6 1.24 0.65 1 1.15 ... $ type : num 0 $ lambda1 : num 0.126 $ lambda2 : NULL $ iter : num 10 $ q.val : num 0.195 $ fit.info:List of 13 ..$ fmin : num 0.195 ..$ xmin : Named num -2.99 .. ..- attr(*, "names")= chr "log2lambda1" ..$ iter : num 26 ..$ neval : num 46 ..$ maxevals : num 500 ..$ seed : num 123 ..$ bounds : num [1, 1:2] -10 10 .. ..- attr(*, "dimnames")=List of 2 .. .. ..$ : chr "log2lambda1" .. .. ..$ : chr [1:2] "lower" "upper" ..$ Q.func : chr ".calc.scad" ..$ points.fmin:'data.frame': 1 obs. of 2 variables: .. ..$ log2lambda1: num -2.99 .. ..$ f : num 0.195 ..$ Xtrain : num [1:46, 1] -7.52 -2.26 -1.34 9.99 9.03 ... .. ..- attr(*, "dimnames")=List of 2 .. .. ..$ : NULL .. .. ..$ : chr "log2lambda1" ..$ Ytrain : num [1:46] 3.65e-01 3.20e-01 4.60e-01 1.00e+16 1.00e+16 ... ..$ gp.seed : num [1:25] 123 124 125 126 127 128 129 130 131 132 ... ..$ model.list :List of 1 .. ..$ model:List of 10 .. .. ..$ w : Named num [1:23] 0.625 0.616 0.353 0.258 0.959 ... .. .. .. ..- attr(*, "names")= chr [1:23] "pos1" "pos2" "pos3" "pos4" ... .. .. ..$ b : num -0.115 .. .. ..$ xind : int [1:23] 1 2 3 4 5 6 7 8 9 10 ... .. .. ..$ index : int [1:83] 3 4 9 14 17 18 22 35 37 40 ... .. .. ..$ fitted : num [1:200] 2.6 1.24 0.65 1 1.15 ... .. .. ..$ type : num 0 .. .. ..$ lambda1 : num 0.126 .. .. ..$ iter : num 10 .. .. ..$ q.val : num 0.195 .. .. ..$ inner.val.method: chr "cv" NULL
预测测试集上示例的类别。
>(scad.5cv.test<-predict.penSVM(scad, t(test$x)[,1:100], newdata.labels=test$y) ) $pred.class [1] -1 1 -1 -1 -1 1 1 1 1 -1 -1 -1 1 1 1 -1 1 1 -1 -1 Levels: -1 1 $fitted [,1] 1 -2.5344366 2 2.3440943 3 -1.3972349 4 -0.3613470 5 -2.1187284 6 1.1287477 7 2.5584662 8 1.9155333 9 1.5543941 10 -0.7128084 11 -1.6944994 12 -0.2943272 13 1.8497781 14 2.7800572 15 0.8927699 16 -0.1289518 17 2.4560094 18 0.8756835 19 -2.2114729 20 -1.7342811 $tab newdata.labels pred.class -1 1 -1 6 4 1 1 9 $error [1] 0.25 $sensitivity [1] 0.6923077 $specificity [1] 0.8571429 > test<-sim.data(n = 20, ng = 100, nsg = 10, corr=FALSE, seed=seed+1 ) > print(str(test)) List of 3 $ x : num [1:100, 1:20] -1.3851 -1.1036 -0.2677 0.2836 -0.0951 ... ..- attr(*, "dimnames")=List of 2 .. ..$ : chr [1:100] "pos1" "pos2" "pos3" "pos4" ... .. ..$ : chr [1:20] "1" "2" "3" "4" ... $ y : Named num [1:20] -1 1 -1 1 1 1 1 1 1 -1 ... ..- attr(*, "names")= chr [1:20] "1" "2" "3" "4" ... $ seed: num 124 NULL > (scad.5cv.test<-predict.penSVM(scad, t(test$x)[,1:100], newdata.labels=test$y)) $pred.class [1] -1 1 -1 -1 -1 1 1 1 1 -1 -1 -1 1 1 1 -1 1 1 -1 -1 Levels: -1 1 $fitted [,1] 1 -2.5344366 2 2.3440943 3 -1.3972349 4 -0.3613470 5 -2.1187284 6 1.1287477 7 2.5584662 8 1.9155333 9 1.5543941 10 -0.7128084 11 -1.6944994 12 -0.2943272 13 1.8497781 14 2.7800572 15 0.8927699 16 -0.1289518 17 2.4560094 18 0.8756835 19 -2.2114729 20 -1.7342811 $tab newdata.labels pred.class -1 1 -1 6 4 1 1 9 $error [1] 0.25 $sensitivity [1] 0.6923077 $specificity [1] 0.8571429
要分析结果,可以使用以下命令。
> print(paste("minimal 5-fold cv error:", scad$model$fit.info$fmin, + "by log2(lambda1)=", scad$model$fit.info$xmin)) [1] "minimal 5-fold cv error: 0.195 by log2(lambda1)= -2.99093721912059" > print(" all lambdas with the same minimum? ") [1] " all lambdas with the same minimum? " > print(scad$model$fit.info$ points.fmin) log2lambda1 f 36 -2.990937 0.195 > print(paste(scad$model$fit.info$neval, "visited points")) [1] "46 visited points" #Plot the results >.plot.EPSGO.parms (scad$model$fit.info$Xtrain, scad$model$fit.info$Ytrain, + bound=bounds, Ytrain.exclude=10^16, plot.name=NULL )
- ↑ Corinna Cortes 和 V. Vapnik,支持向量机,机器学习,20,1995。http://www.springerlink.com/content/k238jx04hm87j80g/
- ↑ Blum A 和 Langley P,机器学习中相关特征和示例的选择。Artif. Intell. 1997;97:245-271。
- ↑ Fan J.,关于 A. Antoniadis 的“统计中的小波:综述”的评论。和 J. Italian Stat.Assoc. 1997;6:131-138。
- ↑ Fan J.,关于 A. Antoniadis 的“统计中的小波:综述”的评论。和 J. Italian Stat.Assoc. 1997;6:131-138。
- ↑ Zhang HH 等,使用具有非凸惩罚的支持向量机的基因选择。Bioinformatics 2006;22:88-95。