解密SVM系列(五):matlab下libsvm的簡單使用:分類與迴歸

本節簡單介紹一下libsvm的使用方法。關於libsvm似乎曾經使用過,那個時候主要用libsvm進行簡單的人臉識別實驗。當時還翻譯過關於libsvm裏面的matlab英文文檔

介紹與分類實驗

那麼現在最新版本的libsvm爲3.2.0,下載地址如下:
http://www.csie.ntu.edu.tw/~cjlin/libsvm/

下載下來的libsvm其實包含好多個平臺的工具箱軟件,c++,matlab,java,python都有。他們的函數使用方法是一樣的。

那麼在下載完以後,點擊裏面的matlab下平臺,直接在點擊裏面的make.m函數就可以了。正常情況下如果你的matlab含有編譯平臺的話直接就可以運行了,如果沒有,還需要選擇一個平臺 mex -setup 。小提醒一下,這個編譯過程不要在c盤下使用,也就是libsvm先不要放在c盤,涉及到權限,機器不讓編譯。編譯完後在matlab的設置路徑中添加進去編譯的文件夾及其內容,那麼就可以使用了。正常編譯的過程是這樣的:
這裏寫圖片描述

在上面的人臉識別實驗中曾經介紹過裏面的主要函數,這裏爲了放在一塊,把那裏的拿過來吧:

目前版LIBSVM(3.2.0)在matlab下編譯完後只有四個函數,libsvmread,Libsvmwrite,svmtrain(matlab自帶的工具箱中有一個同名的函數),svmpredict。

(1)libsvmread主要用於讀取數據
這裏的數據是非matlab下的.mat數據,比如說是.txt,.data等等,這個時候需要使用libsvmread函數進行轉化爲matlab可識別數據,比如自帶的數據是heart_scale數據,那麼導入到matlab有兩種方式,一種使用libsvmread函數,在matlab下直接libsvmread(heart_scale);第二種方式爲點擊matlab的‘導入數據’按鈕,然後導向heart_scale所在位置,直接選擇就可以了。個人感覺第二種方式超級棒,無論對於什麼數據,比如你在哪個數據庫下下載的數據,如何把它變成matlab下數據呢?因爲有的數據libsvmread讀取不管用,但是‘導入數據’後就可以變成matlab下數據。

(2)libsvmwrite寫函數,就是把已知數據存起來
使用方式爲:libsvmwrite(‘filename’,label_vector, instance_matrix);
label_vector是標籤,instance_matrix爲數據矩陣(注意這個數據必須是稀疏矩陣,就是裏面的數據不包含沒用的數據(比如很多0),有這樣的數據應該去掉再存)。

(3)svmtrain訓練函數,訓練數據產生模型的
一般直接使用爲:model=svmtrain(label,data,cmd); label爲標籤,data爲訓練數據(數據有講究,每一行爲一個樣本的所有數據,列數代表的是樣本的個數),每一個樣本都要對應一個標籤(分類問題的話一般爲二分類問題,也就是每一個樣本對應一個標籤)。cmd爲相應的命令集合,都有哪些命令呢?很多,-v,-t,-g,-c,等等,不同的參數代表的含義不同,比如對於分類問題,這裏-t就表示選擇的核函數類型,-t=0時線性核。-t=1多項式核,-t=2,徑向基函數(高斯),-t=3,sigmod核函數,新版出了個-t=4,預計算核(還不會用);-g爲核函數的參數係數,-c爲懲罰因子係數,-v爲交叉驗證的數,默認爲5,這個參數在svmtrain寫出來使用與不寫出來不使用的時候,model出來的東西不一樣,不寫的時候,model爲一個結構體,是一個模型,可以帶到svmpredict中直接使用,寫出來的時候,出來的是一個訓練模型的準確率,爲一個數值。一般情況下就這幾個參數重要些,還有好多其他參數,可以自己參考網上比較全的,因爲下面的這種方法的人臉識別就用到這麼幾個參數,其他的就不寫了。

(3)svmpredict訓練函數,使用訓練的模型去預測來的數據類型
使用方式爲:
[predicted_label,accuracy,decision_values/prob_estimates]= svmpredict(testing_label_vector,testing_instance_matrix,model,’libsvm_options’)
或者:
[predicted_label]=svmpredict(testing_label_vector,testing_instance_matrix, model, ‘libsvm_options’)
第一種方式中,輸出爲三個參數,預測的類型,準確率,評估值(非分類問題用着),輸入爲測試類型(這個可與可無,如果沒有,那麼預測的準確率accuracy就沒有意義了,如果有,那麼就可以通過這個值與預測出來的那個類型值相比較得出準確率accuracy,但是要說明一點的是,無論這個值有沒有,在使用的時候都得加上,即使沒有,也要隨便加上一個類型值,反正你也不管它對不對,這是函數使用所規定的的),再就是輸入數據值,最後是參數值(這裏的參數值只有兩種選擇,-p和-b參數),曾經遇到一個這樣的問題,比如說我在訓練函數中規定了-g參數爲0.1,那麼在預測的時候是不是也要規定這個參數呢?當你規定了以後,程序反而錯誤,提醒沒有svmpredict的-g參數,原因是在svmtrain後會出現一個model,而在svmpredict中你已經用了這個model,而這個model中就已經包含了你所有的訓練參數了,所以svmpredict中沒有這個參數,那麼對於的libsvm_options就是-p和-b參數了。對於函數的輸出,兩種方式調用的方法不一樣,第一種調用把所有需要的數據都調用出來了,二第二種調用,只調用了predicted_label預測的類型,這裏我們可以看到,在單純的分類預測模型中,其實第二種方式更好一些吧,既簡單有實用。

致此,四個函數在分類問題中的介紹大概如此,當然還有很多可以優化的細節就不詳細說了,比如可以再使用那些參數的時候,你如果不規定參數的話,所有的-參數都是使用默認的,默認的就可能不是最好的吧,這樣就涉及到如何去優化這個參數了。

使用就介紹到這裏吧,下面實戰一下,樣本集選擇前面使用的200個非線性樣本集,函數如下:

%%
% * libsvm 工具箱簡單使用
%
%% 加載數據
% * 最終data格式:m*n,m樣本數,n維度
% * label:m*1  標籤爲-1與1這兩類
clc
clear
close all
data = load('data_test1.mat');
data = data.data';
%選擇訓練樣本個數
num_train = 80;
%構造隨機選擇序列
choose = randperm(length(data));
train_data = data(choose(1:num_train),:);
gscatter(train_data(:,1),train_data(:,2),train_data(:,3));
label_train = train_data(:,end);
test_data = data(choose(num_train+1:end),:);
label_test = test_data(:,end);
predict = zeros(length(test_data),1);
%% ----訓練模型並預測分類
model = svmtrain(label_train,train_data(:,1:end-1),'-t 2');
% -t = 2 選擇徑向基函數核 
true_num = 0;
for i = 1:length(test_data)
    % 作爲預測,svmpredict第一個參數隨便給個就可以
    predict(i) = svmpredict(1,test_data(i,1:end-1),model);
end
%% 顯示結果
figure;
index1 = find(predict==1);
data1 = (test_data(index1,:))';
plot(data1(1,:),data1(2,:),'or');
hold on
index2 = find(predict==-1);
data2 = (test_data(index2,:))';
plot(data2(1,:),data2(2,:),'*');
hold on
indexw = find(predict~=(label_test));
dataw = (test_data(indexw,:))';
plot(dataw(1,:),dataw(2,:),'+g','LineWidth',3);
accuracy = length(find(predict==label_test))/length(test_data);
title(['predict the testing data and the accuracy is :',num2str(accuracy)]);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

可以看到,關於svm的部分就那麼一點,其他的都是輔助吧,那麼一個結果如下:
這裏寫圖片描述

數據人爲設置了一些重疊,這個結果算是非常好了。當然對於libsvm函數,裏面還有許多細節,像參數選擇等等,不同的參數結果是不一樣的,這就待你去探究了。

至此SVM系列文章就到這裏吧,感謝能看到這裏的朋友~_~。

迴歸實驗

迴歸問題不像分類問題,迴歸問題相當於根據訓練樣本訓練出一個擬合函數一樣,可以根據這個擬合函數可以來預測給定一個樣本的輸出值。可以看到分類問題輸出的是樣本所屬於的類,而回歸問題輸出的是樣本的預測值。

常用的地方典型的比如股票預測,人口預測等等此類預測問題。

libsvm同樣可以進行迴歸預測,所需要改變的只是裏面的參數設置。查看libsvm的官網介紹參數詳情如下:

options:
-s svm_type : set type of SVM (default 0)
    0 -- C-SVC
    1 -- nu-SVC
    2 -- one-class SVM
    3 -- epsilon-SVR
    4 -- nu-SVR
-t kernel_type : set type of kernel function (default 2)
    0 -- linear: u'*v
    1 -- polynomial: (gamma*u'*v + coef0)^degree
    2 -- radial basis function: exp(-gamma*|u-v|^2)
    3 -- sigmoid: tanh(gamma*u'*v + coef0)
-d degree : set degree in kernel function (default 3)
-g gamma : set gamma in kernel function (default 1/num_features)
-r coef0 : set coef0 in kernel function (default 0)
-c cost : set the parameter C of C-SVC, epsilon-SVR, and nu-SVR (default 1)
-n nu : set the parameter nu of nu-SVC, one-class SVM, and nu-SVR (default 0.5)
-p epsilon : set the epsilon in loss function of epsilon-SVR (default 0.1)
-m cachesize : set cache memory size in MB (default 100)
-e epsilon : set tolerance of termination criterion (default 0.001)
-h shrinking: whether to use the shrinking heuristics, 0 or 1 (default 1)
-b probability_estimates: whether to train a SVC or SVR model for probability estimates, 0 or 1 (default 0)
-wi weight: set the parameter C of class i to weight*C, for C-SVC (default 1)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

可以看到-s svm_type 控制的就是訓練類型,而當-s等於3或4的時候,就是迴歸模型SVR。
-s 3 就是常用的帶懲罰項的 SVR模型,我們用這個實驗。我使用的是libsvm3.2.0工具箱,版本不同可能會帶來調用方式的不同。測試實驗的代碼如下,可能會有一些細節需要自己去探索:

close all;
clear;
clc;
%%
% 生成待迴歸的數據
x = (-1:0.1:1)';
y = -100*x.^3 + x.^2 - x + 1;
% 加點噪聲
y = y+ 20*rand(length(y),1);
%% 採用交叉驗證選擇參數
mse = 10^7;
for log2c = -10:0.5:3,
    for log2g = -10:0.5:3,
        % -v 交叉驗證參數:在訓練的時候需要,測試的時候不需要,否則出錯
        cmd = ['-v 3 -c ', num2str(2^log2c), ' -g ', num2str(2^log2g) , ' -s 3 -p 0.4 -t 3'];
        cv = svmtrain(y,x,cmd);
        if (cv < mse),
            mse = cv; bestc = 2^log2c; bestg = 2^log2g;
        end
    end
end
%%  訓練--
cmd = ['-c ', num2str(2^bestc), ' -g ', num2str(2^bestg) , ' -s 3 -p 0.4 -n 0.1'];
model = svmtrain(y,x,cmd);
% model
% 利用建立的模型看其在訓練集合上的迴歸效果
% 注意libsvm3.2.0的svmpredict函數必須有三個參數輸出
[py,~,~] = svmpredict(y,x,model);
figure;
plot(x,y,'o');
hold on;
plot(x,py,'g+');
%% 
% 進行預測新的x值
%-- 產生[-1 1]的隨機數
testx = -2+(2-(-2))*rand(10,1);
testy = zeros(10,1);% 理論y值無所謂
[ptesty,~,~] = svmpredict(testy,testx,model);
hold on;
plot(testx,ptesty,'r*');
legend('原始數據','迴歸數據','新數據');
grid on;
% title('t=0:線性核')
% title('t=1:多項式核')
% title('t=2:徑向基函數(高斯)')
title('t=3:sigmod核函數')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

這裏我隨機生成一個3次函數的隨機數據,測試了幾種不同svm裏面的核函數:
這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述

因爲我們的數據是由三次函數模擬生成的,所以可以看到,在這種情況下使用線性核t=0時候效果更好,然而實際情況下一般我們也不知道數據的分佈函數,所以在選擇核函數的時候還是需要多實驗,找到最適合自己數據的核函數。

這裏採用了交叉驗證的方式自適應選擇模型中重要的兩個參數,需要注意的是參數的範圍,不要太大,步長可能也需要控制,否則在數據量很大的時候需要運行很久。

(function () { ('pre.prettyprint code').each(function () { var lines = (this).text().split(\n).length;var numbering = $('
    ').addClass('pre-numbering').hide(); (this).addClass(hasnumbering).parent().append( numbering); for (i = 1; i
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章