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
