SVM多分類問題 libsvm在matlab中的應用

對於支持向量機,其是一個二類分類器,但是對於多分類,SVM也可以實現。主要方法就是訓練多個二類分類器。
一、多分類方式
1、一對所有(One-Versus-All OVA)
給定m個類,需要訓練m個二類分類器。其中的分類器 i 是將 i 類數據設置爲類1(正類),其它所有m-1個i類以外的類共同設置爲類2(負類),這樣,針對每一個類都需要訓練一個二類分類器,最後,我們一共有 m 個分類器。對於一個需要分類的數據 x,將使用投票的方式來確定x的類別。比如分類器 i 對數據 x 進行預測,如果獲得的是正類結果,就說明用分類器 i 對 x 進行分類的結果是: x 屬於 i 類,那麼,類i獲得一票。如果獲得的是負類結果,那說明 x 屬於 i 類以外的其他類,那麼,除 i 以外的每個類都獲得一票。最後統計得票最多的類,將是x的類屬性。
2、所有對所有(All-Versus-All AVA)
給定m個類,對m個類中的每兩個類都訓練一個分類器,總共的二類分類器個數爲 m(m-1)/2 .比如有三個類,1,2,3,那麼需要有三個分類器,分別是針對:1和2類,1和3類,2和3類。對於一個需要分類的數據x,它需要經過所有分類器的預測,也同樣使用投票的方式來決定x最終的類屬性。但是,此方法與”一對所有”方法相比,需要的分類器較多,並且因爲在分類預測時,可能存在多個類票數相同的情況,從而使得數據x屬於多個類別,影響分類精度。
對於多分類在matlab中的實現來說,matlab自帶的svm分類函數只能使用函數實現二分類,多分類問題不能直接解決,需要根據上面提到的多分類的方法,自己實現。雖然matlab自帶的函數不能直接解決多酚類問題,但是我們可以應用libsvm工具包。libsvm工具包採用第二種“多對多”的方法來直接實現多分類,可以解決的分類問題(包括C- SVC、n - SVC )、迴歸問題(包括e - SVR、n - SVR )以及分佈估計(one-class-SVM )等,並提供了線性、多項式、徑向基和S形函數四種常用的核函數供選擇。

二、用libsvm在matlab中實現多分類(訓練函數svmtrain+預測函數svmpredict)
對於libsvm中訓練模型的函數svmtrain來說,model = svmtrain(訓練數據類別, 訓練數據, ‘一系列參數’);其中參數的形式如‘-c 2 -g 0.02’在這當中,參數主要包括以下幾個方面:
(1) -s —— 其表示SVM的類型,包括上面提到的(默認值爲0):
0 —— C-SVC
1—— v-SVC
2 —— 一類SVM
3 —— e -SVR
4 —— v-SVR
(2)-t—— 其表示核函數類型(默認值爲2)
0 – 線性:u’v
1 – 多項式:(r*u’v + coef0)^degree
2 – RBF函數:exp(-gamma|u-v|^2)
3 –sigmoid:tanh(r*u’v + coef0)
(3)核函數參數設置
-d ——核函數中的degree設置(針對多項式核函數)(默認3)
-g ——核函數中的gamma函數設置(針對多項式/rbf/sigmoid 核函數)(默認1/ k,k爲特徵值個數)
-r ——核函數中的coef0設置(針對多項式/sigmoid核函數)((默認0)
-c ——設置C-SVC,e -SVR和v-SVR的參數(損失函數)(默認1)
-n——設置nu-SVC,一類SVM和nu- SVR的參數(默認0.5)
-p ——設置e -SVR 中損失函數p的值(默認0.1)
-m ——設置cache內存大小,以MB爲單位(默認40)
-e ——設置允許的終止判據(默認0.001)
-h ——是否使用啓發式,0或1(默認1)
-b ——是否訓練一個SVC或者SVR模型,0或1(默認0)
-wi ——設置第i類的參數C爲weight*C(C-SVC中的C)(默認1)
-v——n-fold交互檢驗模式,n爲fold的個數,必須大於等於2(訓練中使用了-v參數進行交叉驗證時,返回的不是一個模型,而是交叉驗證的分類的正確率或者回歸的均方根誤差)

使用函數svmtrain訓練分類模型後,會返回一個結構體,其中包括數據:
(1) parameters(一個5*1的數組)
第一個元素:-s,SVM的類型(int默認爲0)
第二個元素:-t,核函數類型(默認爲2)
第三個元素:-d,核函數中的degree設置(針對多項式核函數)(默認3);
     第四個元素:-g,核函數中的r(gamma)函數設置(針對多項式/rbf/sigmoid核函數) (默認爲類別數目的倒數);
第五個元素:-r 核函數中的coef0設置(針對多項式/sigmoid核函數)((默認0)
(2)-nr_class: 表示數據集中有多少個類(int)
(3)-totalSV: 表示支持向量的總數。(int)
(4)-rho: 決策函數wx+b中的常數偏置的相反數(-b)。
(5)-Label: 表示數據集中類別的標籤
(6)ProbA: 使用-b參數時用於概率估計的數值,否則爲空。
ProbB: 使用-b參數時用於概率估計的數值,否則爲空。
(7)-nSV: 表示每類樣本的支持向量的數目,和Label的類別標籤對應。
(8)-sv_coef: 表示每個支持向量在決策函數中的係數。
(9)-SVs: 表示所有的支持向量,如果特徵是n維的,支持向量一共有m個,則爲m x n的稀疏矩陣。
(10)nu: -n參數的顯示
(11)iter: 迭代次數
(12)obj: 表示SVM文件轉換的二次規劃求解的最小值

svmpredict函數根據測試數據類屬性,測試數據,以及通過svmtrain函數獲得的模型來進行分類預測並計算分類精度,[predict_label, accuracy, dec_values]=svmpredict(測試數據類屬性,測試數據,分類模型),返回值介紹如下:
(1)predicted_label:存儲着分類後樣本所對應的類屬性。
(2)accuracy:一個3 * 1的數組,依次爲:分類的正確率、迴歸的均方根誤差、迴歸的平方相關係數。
(3)decision_values/prob_estimates:是一個表示概率的數組,對於一個m個數據,n個類的情況,如果指定“-b 1”參數(使用,則n x k的矩陣,每一行表示這個樣本分別屬於每一個類別的概率;如果沒有指定“-b 1”參數,則爲n * n×(n-1)/2的矩陣,每一行表示n(n-1)/2個二分類SVM的預測結果。

三、 使用libsvm進行分類的步驟
(1) 對數據做歸一化(simple scaling)
對數據進行簡單的縮放處理(scaling),縮放的最主要優點是能夠避免大數值區間的屬性過分支配了小數值區間的屬性。另一個優點能避免計算過程中數值複雜度。(在試驗中發現,歸一化過程,分別對訓練數據和測試數據進行歸一化處理,比對訓練數據和測試數據整體進行歸一化處理獲得的分類精度要高)
(2) 應用 RBF kernel
(3) 選擇得到最優的c和g
c是懲罰因子,是一個在訓練模型前需要自己設置的一個數值,它表示我們對類中的離羣數據的重視程度,c的數值越大,表明我們越重視,越不想丟掉這些離羣的數據;g是核函數中的gamma函數設置(針對多項式/rbf/sigmoid 核函數)(默認1/ k,k爲特徵值個數) 。c和g的選擇對分類精度影響很大,在本文的試驗中,用函數SVMcgForClass選擇完成c和g的選擇。
(4) 用得到的最優c和g訓練分類模型
使用libsvm中的svmtrain函數來訓練多分類模型
(5)測試
使用libsvm中的svmpredict函數來測試分類精度

四、實驗
使用libsvm提供的數據進行多分類實驗,下載的wine數據,是關於葡萄酒種類,下載的數據包括這裏寫圖片描述三部分,分別是類數3,178個酒數據的13個屬性列表,178個酒數據對應的類屬性列表。代碼如下:

function [ classfication ] = test( train,test )

load chapter12_wine.mat                       %下載數據

train=[wine(1:30,:);wine(60:95,:);wine(131:153,:)]; %選取訓練數據
train_group=[wine_labels(1:30);wine_labels(60:95); wine_labels(131:153)];%選取訓練數據類別標識
test=[wine(31:59,:);wine(96:130,:);wine(154:178,:)];%選取測試數據
test_group=[wine_labels(31:59);wine_labels(96:130); wine_labels(154:178)]; %選取測試數據類別標識

%數據預處理,用matlab自帶的mapminmax將訓練集和測試集歸一化處理[0,1]之間
%訓練數據處理
[train,pstrain] = mapminmax(train');
% 將映射函數的範圍參數分別置爲0和1
pstrain.ymin = 0;
pstrain.ymax = 1;
% 對訓練集進行[0,1]歸一化
[train,pstrain] = mapminmax(train,pstrain);
% 測試數據處理
[test,pstest] = mapminmax(test');
% 將映射函數的範圍參數分別置爲01
pstest.ymin = 0;
pstest.ymax = 1;
% 對測試集進行[0,1]歸一化
[test,pstest] = mapminmax(test,pstest);
% 對訓練集和測試集進行轉置,以符合libsvm工具箱的數據格式要求
train = train';
test = test';

%尋找最優c和g
%粗略選擇:c&g 的變化範圍是 2^(-10),2^(-9),...,2^(10)
[bestacc,bestc,bestg] = SVMcgForClass(train_group,train,-10,10,-10,10);
%精細選擇:c 的變化範圍是 2^(-2),2^(-1.5),...,2^(4), g 的變化範圍是 2^(-4),2^(-3.5),...,2^(4)
[bestacc,bestc,bestg] = SVMcgForClass(train_group,train,-2,4,-4,4,3,0.5,0.5,0.9);

%訓練模型
cmd = ['-c ',num2str(bestc),' -g ',num2str(bestg)];
model=svmtrain(train_group,train,cmd);
disp(cmd);

%測試分類
[predict_label, accuracy, dec_values]=svmpredict(test_group,test,model);

%打印測試分類結果
figure;
hold on;
plot(test_group,'o');
plot(predict_label,'r*');
legend('實際測試集分類','預測測試集分類');
title('測試集的實際分類和預測分類圖','FontSize',10);
end


  • 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
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

五、實驗結果

這裏寫圖片描述

這裏寫圖片描述

六、問題
疑惑(1)!!!!!!!!!!!!!!!!!!!!!!!!!!!!
上面的實驗是參照libsvm 中的示例寫的,最開始按照示例思路,但是在歸一化時,自己是將訓練數據和測試數據一起歸一化的, 獲得的精度只有61%,後來改爲示例中的分別對訓練數據和測試數據進行歸一化後,精度就到了現在的88%,但是不理解造成此差異的原因,希望知道原因的朋友多多指教(代碼如下(1)和(2))

1、訓練數據和測試數據分別歸一化到[0,1]代碼(獲得分類精度88%):

%訓練數據處理
[train,pstrain] = mapminmax(train');
% 將映射函數的範圍參數分別置爲0和1
pstrain.ymin = 0;
pstrain.ymax = 1;
% 對訓練集進行[0,1]歸一化
[train,pstrain] = mapminmax(train,pstrain);

% 測試數據處理
[test,pstest] = mapminmax(test');
% 將映射函數的範圍參數分別置爲0和1
pstest.ymin = 0;
pstest.ymax = 1;
% 對測試集進行[0,1]歸一化
[test,pstest] = mapminmax(test,pstest);
% 對訓練集和測試集進行轉置,以符合libsvm工具箱的數據格式要求
train = train';
test = test';
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

2、訓練數據和測試數據整體歸一化到[0,1]代碼(獲得分類精度61%):

[mtrain,ntrain]=size(train);
[mtest,ntest]=size(test);
dataset=[train;test];
[dataset_scale,ps]=mapminmax(dataset',0,1);
dataset_scale=dataset_scale';
train=dataset_scale(1:mtrain,:);
test=dataset_scale((mtrain+1):(mtrain+mtest),:);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

疑惑(2)!!!!!!!!!!!!!!!!!!!!!!!!!!!!
再有就是,對於c和g這兩個數值有函數可以自動調優,但是在歸一化時,如下面我要是把對訓練數據和測試數據分別歸一化的範圍從[0,1]變成[0,4],獲得的分類精度就從88%提高到了96%,這種歸一化的範圍又該怎麼確定呢?

訓練數據和測試數據分別歸一化到[0,4]代碼(獲得分類精度96%):

%訓練數據處理
[train,pstrain] = mapminmax(train');
% 將映射函數的範圍參數分別置爲0和4
pstrain.ymin = 0;
pstrain.ymax = 4;
% 對訓練集進行[0,4]歸一化
[train,pstrain] = mapminmax(train,pstrain);

% 測試數據處理
[test,pstest] = mapminmax(test');
% 將映射函數的範圍參數分別置爲0和4
pstest.ymin = 0;
pstest.ymax = 4;
% 對測試集進行[0,4]歸一化
[test,pstest] = mapminmax(test,pstest);
% 對訓練集和測試集進行轉置,以符合libsvm工具箱的數據格式要求
train = train';
test = test';

文章轉自:http://blog.csdn.net/lwwangfang/article/details/52355062
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章