1. 程式人生 > >機器學習5---支援向量機

機器學習5---支援向量機

1. 線性可分的支援向量機

1.1 支援向量機(SVM)基本型

對於給定的在樣本空間中線性可分的訓練集,我們有多重辦法對其進行劃分,以二分類問題為例,如圖:

紅線和黑線(超平面)都能將兩類樣本很好的劃分開,但是當新樣本進入時,黑線比紅線更加有可能正確劃分新的樣本,換句話說:越位於兩類樣本“中心”的劃分超平面越能夠容忍樣本的區域性擾動,其的泛化能力越好。

基於以上思想,我們準備求解最優超平面。

首先,記超平面的線性方程為w^{T}x+b=0,其中w為法向量。根據點到直線的距離公式,得到樣本空間任一點x超平面的距離可以寫成r=\frac{|w^{T}x+b|}{||w||}

接著,為了方便計算,我們將兩類樣本使用正類和負類表示,即若y_{i}=+1,則w^{T}x_{i}+b\geqslant +1;若y_{i}=-1

,則w^{T}x_{i}+b\leqslant -1,能夠使得等號成立的樣本向量稱之為“支援向量”,因為它們是離超平面最近的訓練樣本,它們確定了兩個類別之間的“間隔”。

然後,找到最優超平面也就轉換成尋找“最大間隔”問題,即

\underset{w,b}{max} \frac{2}{||w||}   (w^{T}x+b=1w^{T}x+b=-1之間的距離)

s.t. y_{i}(w^{T}x_{i}+b)\geqslant 1,i=1,2,...m

等價於:\underset{w,b}{min} \frac{1}{2}||w||^{2},至此就是SVM的基本模型建立完成。

1.2 求解SVM基本型

求解SVM這種“凸二次規劃問題”時,通常採用“對偶問題”方法。

(1)用拉格朗日乘數法將約束條件加入L函式。

L(w,b,a)=\frac{1}{2}||w||^{2}+ \sum^{m}_{i=1}a_{i}(1-y_{i}(w^{T}x_{i}+b)),其中a為拉格朗日乘子。

(2)對w,b求偏導,並將 w(a) , b(a) 帶入L(w,b,a)中,整理得到SVM的對偶問題有

\underset{a}{max} \sum^{m}_{i=1}a_{i}-\frac{1}{2}\sum_{i=1}^{m}\sum_{j=1}^{m}a_{i}a_{j}y_{i}y_{j}x_{i}^{T}x_{j}

s.t. \sum^{m}_{i=1}a_{i}y_{i}=0,a_{i}\geqslant 0,且滿足KKT條件,即表明支援向量機的最終模型僅與支援向量相關。

解出a後,即可得到模型:f(x)=w^{T}x+b=\sum^{m}_{i=1}a_{i}y_{i}x_{i}^{T}+b。求解a這種二次規劃問題通常使用SMO(sequential minimal optimization)演算法。

1.3 帶有核函式的支援向量機模型

假設樣本集是線性可分的,但是在原來的樣本空間無法直接使用一個超平面進行劃分,那麼我們經常將該樣本空間投影到一個更高維的特徵空間中,使其能在高維空間中尋找到一個劃分超平面。

\phi (x)表示樣本投影到高維空間的特徵向量,於是超平面的方程變成:

f(x)=w^{T}\phi (x)+b

後面就和1.1和1.2有類似的推導,找到目標函式再求其對偶問題。

但是,投影到高維空間有一個很大的風險就是面臨維度爆炸的問題,為了避開這個問題,我們可以直接通過一個函式變換替代高維對映,

k(x_{i},x_{j})=<\phi (x_{i}),(x_{j})>=\phi(x_{i})^{T}\phi(x_{j}),這個神奇的函式就叫做“核函式”(kernel function)。

對於核函式的要求是對稱,核矩陣總是半正定的。

典型的核函式有:線性核、多項式核、高斯核、拉普拉斯核、sigmoid核,核的函式組合等。

 

matlab程式碼參見:

https://blog.csdn.net/u010412719/article/details/46794051http://blog.sina.com.cn/s/blog_631a4cc40101df0f.html  有使用系統自帶函式,也有作者自己編寫的函式實現,比較詳細,這裡搬過來。

matlab自帶函式實現:

clc;
clear;
N=10;
%下面的資料是我們實際專案中的訓練樣例(樣例中有8個屬性)
correctData=[0,0.2,0.8,0,0,0,2,2];
errorData_ReversePharse=[1,0.8,0.2,1,0,0,2,2];
errorData_CountLoss=[0.2,0.4,0.6,0.2,0,0,1,1];
errorData_X=[0.5,0.5,0.5,1,1,0,0,0];
errorData_Lower=[0.2,0,1,0.2,0,0,0,0];
errorData_Local_X=[0.2,0.2,0.8,0.4,0.4,0,0,0];
errorData_Z=[0.53,0.55,0.45,1,0,1,0,0];
errorData_High=[0.8,1,0,0.8,0,0,0,0];
errorData_CountBefore=[0.4,0.2,0.8,0.4,0,0,2,2];
errorData_Local_X1=[0.3,0.3,0.7,0.4,0.2,0,1,0];
 sampleData=[correctData;errorData_ReversePharse;errorData_CountLoss;errorData_X;errorData_Lower;errorData_Local_X;errorData_Z;errorData_High;errorData_CountBefore;errorData_Local_X1];%訓練樣例

type1=1;%正確的波形的類別,即我們的第一組波形是正確的波形,類別號用 1 表示
type2=-ones(1,N-2);%不正確的波形的類別,即第2~10組波形都是有故障的波形,類別號用-1表示
groups=[type1 ,type2]';%訓練所需的類別號
j=1;
%由於沒有測試資料,因此我將錯誤的波形資料輪流從訓練樣例中取出作為測試樣例
for i=2:10
   tempData=sampleData;
   tempData(i,:)=[];
    svmStruct = svmtrain(tempData,groups);
    species(j) = svmclassify(svmStruct,sampleData(i,:));
    j=j+1;
end
species

使用作者自己編寫的函式實現:

%主函式
clear all;
clc;
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]);
xlabel('x軸');
ylabel('y軸');
hold on;

X = [x1,x2];        %訓練樣本d*n矩陣,n為樣本個數,d為特徵向量個數,在這裡,X為一個2*100的陣列
Y = [y1,y2];        %訓練目標1*n矩陣,n為樣本個數,值為+1或-1,在這裡,Y為一個1*100的陣列
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';%LargeScale指大規模搜尋,off表示在規模搜尋模式關閉
options.Display = 'off';%這樣設定意味著沒有輸出

n = length(Y);%陣列Y的長度
H = (Y'*Y).*kernel(X,X,kertype);%呼叫kernel函式,

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 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);%sum(a,2)程式碼中引數2的意思是將a矩陣a中的按“行”為單位進行求和
    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
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);