SVM原理与实践

时间:2024-05-30 21:35:50

SVM迅速发展和完善,在解决小样本、非线性及高维模式识别问题中表现出许多特有的优势,并能够推广应用到函数拟合等其他机器学习问题中.从此迅速的发展起来,已经在许多领域(生物信息学,文本和手写识别等)都取得了成功的应用.在地球物理反演当中解决非线性反演也有显著成效,例如(SVM在预测地下水涌水量问题等).

SVM中的一大亮点是在传统的最优化问题中提出了对偶理论,主要有最大最小对偶及拉格朗日对偶.

SVM的关键在于核函数.低维空间向量集通常难于划分,解决的方法是将它们映射到高维空间.但这个办法带来的困难就是计算复杂度的增加,而核函数正好巧妙地解决了这个问题.也就是说,只要选用适当的核函数,就可以得到高维空间的分类函数.

在确定了核函数之后,由于确定核函数的已知数据也存在一定的误差,考虑到推广性问题,因此引入了松弛系数以及惩罚系数两个参变量(注:引入松弛变量之后w依然是唯一的,但是b不是唯一的)来加以校正.在确定了核函数基础上,再经过大量对比实验等将这两个系数取定,该项研究就基本完成,适合相关学科或业务内应用,且有一定能力的推广性.

原理

SVM原理与实践

SVM原理与实践

SVM原理与实践

SVM原理与实践

SVM原理与实践

SVM原理与实践

SVM原理与实践

SVM的优缺点:

SVM优点:

(1)内积核函数:非线性映射是SVM方法的理论基础,SVM利用内积核函数代替向高维空间的非线性映射;

(2)最大化分类边际:对特征空间划分的最优超平面是SVM的目标,最大化分类边际的思想是SVM方法的核心;

(3)支持向量:支持向量是SVM的训练结果,在SVM分类决策中起决定作用的是支持向量. SVM 的最终决策函数只由少数的支持向量所确定,计算的复杂性取决于支持向量的数目,而不是样本空间的维数,这在某种意义上避免了“维度灾难”;

(4)坚实理论基础的新颖的小样本学习方法:SVM 是一种有坚实理论基础的新颖的小样本学习方法.它基本上不涉及概率测度及大数定律等,因此不同于现有的统计方法.从本质上看,它避开了从归纳到演绎的传统过程,实现了高效的从训练样本到预报样本的“转导推理”,大大简化了通常的分类和回归等问题;

(5)鲁棒性:少数支持向量决定了最终结果,这不但可以帮助我们抓住关键样本、“剔除”大量冗余样本,而且注定了该方法不但算法简单,而且具有较好的“鲁棒”性.这种“鲁棒”性主要体现在:①增、删非支持向量样本对模型没有影响;②支持向量样本集具有一定的鲁棒性;③有些成功的应用中,SVM 方法对核的选取不敏感.

不足:

(1) SVM
算法对大规模训练样本难以实施:

由于SVM是借助二次规划来求解支持向量,而求解二次规划将涉及m阶矩阵的计算(m为样本的个数),当m数目很大时该矩阵的存储和计算将耗费大量的机器内存和运算时间.针对以上问题的主要改进有J.Platt的SMO算法、T.Joachims的SVM、C.J.C.Burges等的PCGC、张学工的CSVM以及O.L.Mangasarian等的SOR算法

(2) 用SVM解决多分类问题存在困难:

经典的SVM算法只给出了二类分类的算法,而在数据挖掘的实际应用中,一般要解决多类的分类问题.可以通过多个二类SVM的组合来解决.主要有一对多组合模式、一对一组合模式和SVM决策树;再就是通过构造多个分类器的组合来解决.主要原理是克服SVM固有的缺点,结合其他算法的优势,解决多类问题的分类精度.如:与粗集理论结合,形成一种优势互补的多类问题的组合分类器.

代码

####################################R包###################################

R的函数包e1071提供了libsvm的接口。使用e1071包中svm函数可以得到与libsvm相同的结果。write.svm()更是可以把R训练得到的结果写为标准的Libsvm格式,以供其他环境下libsvm的使用。下面我们来看看svm()函数的用法。有两种格式都可以。 

svm(formula,data=NULL,…,subset,na.action=na.omit,sacle=TRUE)

或者  svm(x, y = NULL, scale = TRUE, type = NULL, kernel =  "radial", degree = 3, gamma = if (is.vector(x)) 1 else 1 / ncol(x), coef0 = 0, cost = 1, nu = 0.5,  class.weights = NULL, cachesize = 40, tolerance = 0.001, epsilon = 0.1, shrinking = TRUE, cross = 0, probability = FALSE, fitted = TRUE, ..., subset, na.action = na.omit)  

主要参数说明如下: 

formula:分类模型形式,在第二个表达式中可以理解为y~x,即y相当于标签,x相当于特征(变量) data:数据框。  subset:可以指定数据集的一部分作为训练数据。

na.cation:缺失值处理,默认为删除缺失数据。 

scale:将数据标准化,中心化,使其均值为0,方差为1,将自动执行。

type:svm的形式。

为:C-classification ,nu-classification, one-classification (for novelty detection) ,eps-regression,  nu-regression 五种形式。后面两者为做回归时用到。默认为C分类器。

kernel:在非线性可分时,我们引入核函数来做。

R中提供的核函数如下

线性核:   u'*v  多项式核:  

(gamma*u'*v + coef0)^degree  

高斯核:   exp(-gamma*|u-v|^2) 

sigmoid核:   tanh(gamma*u'*v + coef0)  默认为高斯核。顺带说一下,在kernel包中可以自定义核函数。

degree:多项式核的次数,默认为3 

gamma:除去线性核外,其他核的参数,默认为1/数据维数

coef0:多项式核与sigmoid核的参数,默认为0.

cost:C分类中惩罚项c的取值

nu:Nu分类,单一分类中nu的值

cross:做k折交叉验证,计算分类正确性。

 

我们依然使用iris数据集来做svm分类。

如下

> data(iris)

>  ir<-iris

> set.seed(124) 

> count.test<-round(runif(50,1,150))

> test<-ir[count.test,]

> library(e1071) 

>sv<-svm(Species~.,data=ir,cross=5,type='C-classification',kernel='sigmoid') 

> summary(sv)  #查看支持向量机sv的具体信息,发现做5倍交叉验证的正确率为92%   

> pre<-predict(sv,test) #对测试样本作预测。pre是一个类别向量。

> dim(test[test$Species!=pre,])[1]/dim(test)[1] #计算错误率 [1] 0.06我们发现错误率为6%

##################################MATLAB####################################

%主函数

clear all;

close all;

C = 10;

kertype = 'linear';

%训练样本

n = 50;

randn('state',6);

x1 = randn(2,n);    %2行N列矩阵

y1 = ones(1,n);       %1*N个1

x2 = 5+randn(2,n);   %2*N矩阵

y2 = -ones(1,n);      %1*N个-1

 

figure;

plot(x1(1,:),x1(2,:),'bx',x2(1,:),x2(2,:),'k.'); 

axis([-3 8 -3 8]);

hold on;

 

X = [x1,x2];        %训练样本d*n矩阵,n为样本个数,d为特征向量个数

Y = [y1,y2];        %训练目标1*n矩阵,n为样本个数,值为+1或-1

svm = svmTrain(X,Y,kertype,C);

plot(svm.Xsv(1,:),svm.Xsv(2,:),'ro');

 

%测试

[x1,x2] = meshgrid(-2:0.05:7,-2:0.05:7);  %x1和x2都是181*181的矩阵

[rows,cols] = size(x1);  

nt = rows*cols;                  

Xt = [reshape(x1,1,nt);reshape(x2,1,nt)];

Yt = ones(1,nt);

result = svmTest(svm, Xt, Yt, kertype);

 

Yd = reshape(result.Y,rows,cols);

contour(x1,x2,Yd,'m');

 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function svm = svmTrain(X,Y,kertype,C)

 

options = optimset;    % Options是用来控制算法的选项参数的向量

options.LargeScale = 'off';

options.Display = 'off';

 

n = length(Y);

H = (Y'*Y).*kernel(X,X,kertype);

f = -ones(n,1); %f为1*n个-1,f相当于Quadprog函数中的c

A = [];

b = [];

Aeq = Y; %相当于Quadprog函数中的A1,b1

beq = 0;

lb = zeros(n,1); %相当于Quadprog函数中的LB,UB

ub = C*ones(n,1);

a0 = zeros(n,1);  % a0是解的初始近似值

[a,fval,eXitflag,output,lambda]  = quadprog(H,f,A,b,Aeq,beq,lb,ub,a0,options);

 

epsilon = 1e-8;                     

sv_label = find(abs(a)>epsilon);  %0<a<a(max)则认为x为支持向量     

svm.a = a(sv_label);

svm.Xsv = X(:,sv_label);

svm.Ysv = Y(sv_label);

svm.svnum = length(sv_label);

%svm.label = sv_label;

 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function result = svmTest(svm, Xt, Yt, kertype)

temp = (svm.a'.*svm.Ysv)*kernel(svm.Xsv,svm.Xsv,kertype);

total_b = svm.Ysv-temp;

b = mean(total_b);

w = (svm.a'.*svm.Ysv)*kernel(svm.Xsv,Xt,kertype);

result.score = w + b;

Y = sign(w+b);

result.Y = Y;

result.accuracy = size(find(Y==Yt))/size(Yt);

 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function K = kernel(X,Y,type)

%X 维数*个数

switch type

case 'linear'

    K = X'*Y;

case 'rbf'

    delta = 5;

    delta = delta*delta;

    XX = sum(X'.*X',2);

    YY = sum(Y'.*Y',2);

    XY = X'*Y;

    K = abs(repmat(XX,[1 size(YY,1)]) + repmat(YY',[size(XX,1) 1]) - 2*XY);

    K = exp(-K./delta);

end