SVM原理與實踐


SVM迅速發展和完善,在解決小樣本、非線性及高維模式識別問題中表現出許多特有的優勢,並能夠推廣應用到函數擬合等其他機器學習問題中.從此迅速的發展起來,已經在許多領域(生物信息學,文本和手寫識別等)都取得了成功的應用.在地球物理反演當中解決非線性反演也有顯著成效,例如(SVM在預測地下水涌水量問題等).

 SVM中的一大亮點是在傳統的最優化問題中提出了對偶理論,主要有最大最小對偶及拉格朗日對偶.

 SVM的關鍵在於核函數.低維空間向量集通常難於划分,解決的方法是將它們映射到高維空間.但這個辦法帶來的困難就是計算復雜度的增加,而核函數正好巧妙地解決了這個問題.也就是說,只要選用適當的核函數,就可以得到高維空間的分類函數.

 在確定了核函數之后,由於確定核函數的已知數據也存在一定的誤差,考慮到推廣性問題,因此引入了松弛系數以及懲罰系數兩個參變量(注:引入松弛變量之后w依然是唯一的,但是b不是唯一的)來加以校正.在確定了核函數基礎上,再經過大量對比實驗等將這兩個系數取定,該項研究就基本完成,適合相關學科或業務內應用,且有一定能力的推廣性.

原理

 

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

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM