MATLAB實現SVM多分類(one-vs-rest),利用自帶函數fitcsvm
- SVM多分類
- 一對一(one-vs-one)
- 一對多(one-vs-rest)
- fitcsvm簡單介紹
- 代碼
- 實驗結果圖
SVM多分類
SVM也叫支持向量機,其是一個二類分類器,但是對于多分類,SVM也可以實現。主要方法就是訓練多個二類分類器。常見的有以下兩種方式:
一對一(one-vs-one)
給定m個類,對m個類中的每兩個類都訓練一個分類器,總共的二類分類器個數為 m(m-1)/2 .比如有三個類,1,2,3,那么需要有三個分類器,分別是針對:1和2類,1和3類,2和3類。對于一個需要分類的數據x,它需要經過所有分類器的預測,最后使用投票的方式來決定x最終的類屬性。
一對多(one-vs-rest)
給定m個類,需要訓練m個二類分類器。其中的分類器 i 是將 i 類數據設置為類1(正類),其它所有m-1個i類以外的類共同設置為類2(負類),這樣,針對每一個類都需要訓練一個二類分類器,最后,我們一共有 m 個分類器。對于一個需要分類的數據 x,通常選擇置信度最大的類別標記為分類結果。
fitcsvm簡單介紹
在新版本中svmtrain和svmclassify函數提示已經被移除,所以我們應該跟上潮流學習使用fitcsvm。
SVMModel
= fitcsvm(X,Y,'ClassNames',{'negClass','posClass'},'Standardize',true,...'KernelFunction','rbf','BoxConstraint',1);
簡單說一下參數:
X是訓練樣本,nxm的矩陣,n是樣本數,m是特征維數;
Y是樣本標簽,nx1的矩陣,n是樣本數;
‘ClassNames’,{‘negClass’,‘posClass’} 為鍵值對參數,指定正負類別,負類名在前,正類名在后,與樣本標簽Y中的元素對應;
‘Standardize’,true 為鍵值對參數,指示軟件是否應在訓練分類器之前使預測期標準化!
‘KernelFunction’,‘rbf’ 為鍵值對參數,有3種 ‘linear’(默認), ‘gaussian’ (or ‘rbf’), ‘polynomial’
‘BoxConstraint’,1 為鍵值對參數,直觀上可以理解為一個懲罰因子(或者說正則參數),這個參數和svmtrain里的-c是一個道理。其實際上涉及到軟間隔SVM的間隔(Margin)大小。
基本思想如下:當原始數據未能呈現出較好的可分性時,算法允許其在訓練集上呈現出一些誤分類,matlab默認的BoxConstraint為1。框約束的數值越大,意味著懲罰力度越小,最后得到的分類超平面的間隔越小,支持向量數越多,模型越復雜。這也就是很多機器學習理論書中一開始推導的硬間隔支持向量機(Hard-Margin SVM)。因為該參數默認為1,所以使用默認參數訓練時,我們采用的是軟間隔SVM。
更詳細的大家可以參考官方說明文檔 [https://ww2.mathworks.cn/help/stats/fitcsvm.html].
代碼
說一下思路:
1.我自己造的數據不用太關心,訓練數據是60x2,60是樣本數,2是特征數;測試數據是20x2的。
2.目標是分5類,一對多的方式,就要分別訓練5個SVM模型;每個模型都是一個二分類,所以需要正、負樣本的劃分。我是這么做的正樣本全部來自該類別,負樣本從其它4個類別中隨機選擇,但數目與正樣本相同。有了每一類的正、負樣本,這就得到了訓練樣本X;再設定標簽,我設的是+1,-1,這就得到了樣本標簽Y;其它參數均默認不設,這樣就可以為每一類樣本訓練SVM模型了。
3.測試樣本并不需要對每一類劃分正、負樣本,只要知道測試數據和樣本標簽即可。
4.每個測試樣本在5個SVM模型中均得到一個得分score,利用最大得分判定該樣本最終屬于哪一類。
5.這個混淆矩陣函數confusionmat是真的好用,只需要知道真實標簽和預測標簽就能算出查準率(precision)、查全率(recall)和綜合評價指標(F-measure)。
如圖:
類別1的查準率 =a/(a+d+g)=a/(a+d+g)=a/(a+d+g)
類別1的查全率 =a/(a+b+c)=a/(a+b+c)=a/(a+b+c)
類別2的查準率=e/(b+e+h)=e/(b+e+h)=e/(b+e+h)
類別2的查全率=e/(d+e+f)=e/(d+e+f)=e/(d+e+f)
···
clc
;
clear
;
close all
;
tic
fprintf('-----已開始請等待-----\n\n');
%% 造數據不用關心,直接跳過
% 造數據
20*2
data
= [0.4,0.3;-0.5,0.1;-0.2,-0.3;0.5,-0.3;2.1,1.9;1.8,2.2;1.7,2.5;2.3,1.6;-2.2,1.6;-1.9,2.1;-1.7,2.6;-2.3,2.5;-3.1,-1.9;-2.8,-2.1;-1.9,-2.5;-2.3,-3.2;3.9,-3.5;2.8,-2.2;1.7,-3.1;2.5,-3.4];
data1
= data
+ 2.5*rand(20,2);
data2
= data
+ 2.5*rand(20,2);
data3
= data
+ 2.5*rand(20,2); data1(17:20,:);
% 訓練數據
train_data
= [data1(1:4,:);data2(1:4,:);data3(1:4,:);data1(5:8,:);data2(5:8,:);data3(5:8,:);data1(9:12,:);data2(9:12,:);data3(9:12,:);data1(13:16,:);data2(13:16,:);data3(13:16,:);data1(17:20,:);data2(17:20,:);data3(17:20,:)];% 畫圖顯示
figure
;
% gscatter函數可以按分類或者分組畫離散點
% group為分組向量,對應每一個坐標的類別
group_train
= [1;1;1;1;1;1;1;1;1;1;1;1;2;2;2;2;2;2;2;2;2;2;2;2;3;3;3;3;3;3;3;3;3;3;3;3;4;4;4;4;4;4;4;4;4;4;4;4;5;5;5;5;5;5;5;5;5;5;5;5];
gscatter(train_data(:,1),train_data(:,2),group_train
);title('訓練數據樣本分布');
xlabel('樣本特征1');
ylabel('樣本特征2');
legend('Location','Northwest');
grid on
;%%
% 測試數據
test_data
= data
+ 3.0*rand(20,2);
test_features
= test_data
;
% 測試數據的真實標簽
test_labels
= [1;1;1;1;2;2;2;2;3;3;3;3;4;4;4;4;5;5;5;5];%%
% 訓練數據分為
5類
% 類別i的 正樣本 選擇類別i的全部,負樣本 從其余類別中隨機選擇(個數與正樣本相同)
% 類別
1
class1_p
= train_data(1:12,:);
% randperm(n
,k
)是從
1到n的序號中隨機返回k個
index1
= randperm(48,12);
% 從其余樣本中隨機選擇k個
train_data_c
= train_data
;
train_data_c(1:12,:) = [];
class1_n
= train_data_c(index1
,:);train_features1
= [class1_p
;class1_n
];
% 正類表示為
1,負類表示為
-1
train_labels1
= [ones(12,1);-1*ones(12,1)];% 類別
2
class2_p
= train_data(13:24,:);
% randperm(n
,k
)是從
1到n的序號中隨機返回k個
index1
= randperm(48,12);
% 從其余樣本中隨機選擇k個
train_data_c
= train_data
;
train_data_c(13:24,:) = [];
class2_n
= train_data_c(index1
,:);train_features2
= [class2_p
;class2_n
];
% 正類表示為
1,負類表示為
-1
train_labels2
= [ones(12,1);-1*ones(12,1)];% 類別
3
class3_p
= train_data(25:36,:);
% randperm(n
,k
)是從
1到n的序號中隨機返回k個
index1
= randperm(48,12);
% 從其余樣本中隨機選擇k個
train_data_c
= train_data
;
train_data_c(25:36,:) = [];
class3_n
= train_data_c(index1
,:);train_features3
= [class3_p
;class3_n
];
% 正類表示為
1,負類表示為
-1
train_labels3
= [ones(12,1);-1*ones(12,1)];% 類別
4
class4_p
= train_data(37:48,:);
% randperm(n
,k
)是從
1到n的序號中隨機返回k個
index1
= randperm(48,12);
% 從其余樣本中隨機選擇k個
train_data_c
= train_data
;
train_data_c(37:48,:) = [];
class4_n
= train_data_c(index1
,:);train_features4
= [class4_p
;class4_n
];
% 正類表示為
1,負類表示為
-1
train_labels4
= [ones(12,1);-1*ones(12,1)];% 類別
5
class5_p
= train_data(49:60,:);
% randperm(n
,k
)是從
1到n的序號中隨機返回k個
index1
= randperm(48,12);
% 從其余樣本中隨機選擇k個
train_data_c
= train_data
;
train_data_c(49:60,:) = [];
class5_n
= train_data_c(index1
,:);train_features5
= [class5_p
;class5_n
];
% 正類表示為
1,負類表示為
-1
train_labels5
= [ones(12,1);-1*ones(12,1)];%%
% 分別訓練
5個類別的
SVM模型
model1
= fitcsvm(train_features1
,train_labels1
,'ClassNames',{'-1','1'});
model2
= fitcsvm(train_features2
,train_labels2
,'ClassNames',{'-1','1'});
model3
= fitcsvm(train_features3
,train_labels3
,'ClassNames',{'-1','1'});
model4
= fitcsvm(train_features4
,train_labels4
,'ClassNames',{'-1','1'});
model5
= fitcsvm(train_features5
,train_labels5
,'ClassNames',{'-1','1'});
fprintf('-----模型訓練完畢-----\n\n');
%%
% label是n
*1的矩陣,每一行是對應測試樣本的預測標簽;
% score是n
*2的矩陣,第一列為預測為“負”的得分,第二列為預測為“正”的得分。
% 用訓練好的
5個
SVM模型分別對測試樣本進行預測分類,得到
5個預測標簽
[label1
,score1
] = predict(model1
,test_features
);
[label2
,score2
] = predict(model2
,test_features
);
[label3
,score3
] = predict(model3
,test_features
);
[label4
,score4
] = predict(model4
,test_features
);
[label5
,score5
] = predict(model5
,test_features
);
% 求出測試樣本在
5個模型中預測為“正”得分的最大值,作為該測試樣本的最終預測標簽
score
= [score1(:,2),score2(:,2),score3(:,2),score4(:,2),score5(:,2)];
% 最終預測標簽為k
*1矩陣
,k為預測樣本的個數
final_labels
= zeros(20,1);
for i
= 1:size(final_labels
,1)% 返回每一行的最大值和其位置
[m
,p
] = max(score(i
,:));% 位置即為標簽
final_labels(i
,:) = p
;
end
fprintf('-----樣本預測完畢-----\n\n');
% 分類評價指標group
= test_labels
; % 真實標簽
grouphat
= final_labels
; % 預測標簽
[C,order
] = confusionmat(group
,grouphat
,'Order',[1;2;3;4;5]); % 'Order'指定類別的順序
c1_p
= C(1,1) / sum(C(:,1));
c1_r
= C(1,1) / sum(C(1,:));
c1_F
= 2*c1_p
*c1_r
/ (c1_p
+ c1_r
);
fprintf('c1類的查準率為%f,查全率為%f,F測度為%f\n\n',c1_p
,c1_r
,c1_F
);c2_p
= C(2,2) / sum(C(:,2));
c2_r
= C(2,2) / sum(C(2,:));
c2_F
= 2*c2_p
*c2_r
/ (c2_p
+ c2_r
);
fprintf('c2類的查準率為%f,查全率為%f,F測度為%f\n\n',c2_p
,c2_r
,c2_F
);c3_p
= C(3,3) / sum(C(:,3));
c3_r
= C(3,3) / sum(C(3,:));
c3_F
= 2*c3_p
*c3_r
/ (c3_p
+ c3_r
);
fprintf('c3類的查準率為%f,查全率為%f,F測度為%f\n\n',c3_p
,c3_r
,c3_F
);c4_p
= C(4,4) / sum(C(:,4));
c4_r
= C(4,4) / sum(C(4,:));
c4_F
= 2*c4_p
*c4_r
/ (c4_p
+ c4_r
);
fprintf('c4類的查準率為%f,查全率為%f,F測度為%f\n\n',c4_p
,c4_r
,c4_F
);c5_p
= C(5,5) / sum(C(:,5));
c5_r
= C(5,5) / sum(C(5,:));
c5_F
= 2*c5_p
*c5_r
/ (c5_p
+ c5_r
);
fprintf('c5類的查準率為%f,查全率為%f,F測度為%f\n\n',c5_p
,c5_r
,c5_F
); figure
;
subplot(121);
% gscatter函數可以按分類或者分組畫離散點
% group為分組向量,對應每一個坐標的類別
group_test
= test_labels
;
gscatter(test_data(:,1),test_data(:,2),group_test
);title('測試數據樣本真實分布');
xlabel('樣本特征1');
ylabel('樣本特征2');
legend('Location','Northwest');
grid on
;subplot(122);
% gscatter函數可以按分類或者分組畫離散點
% group為分組向量,對應每一個坐標的類別
group_test
= final_labels
;
gscatter(test_data(:,1),test_data(:,2),group_test
);title('測試數據樣本預測分布');
xlabel('樣本特征1');
ylabel('樣本特征2');
legend('Location','Northwest');
grid on
;
實驗結果圖
-----已開始請等待
----------模型訓練完畢
----------樣本預測完畢
-----c1類的查準率為
0.375000,查全率為
0.750000,F測度為
0.500000c2類的查準率為
0.800000,查全率為
1.000000,F測度為
0.888889c3類的查準率為
1.000000,查全率為
0.750000,F測度為
0.857143c4類的查準率為
1.000000,查全率為
0.250000,F測度為
0.400000c5類的查準率為
1.000000,查全率為
0.750000,F測度為
0.857143
第一次寫博客,還請大家多多包涵,歡迎指教!
參考資料:
[https://www.cnblogs.com/litthorse/p/9303711.html].
[https://blog.csdn.net/qq_39328617/article/details/95207473].
[https://baijiahao.baidu.com/s?id=1619821729031070174&wfr=spider&for=pc].
總結
以上是生活随笔為你收集整理的MATLAB实现SVM多分类(one-vs-rest),利用自带函数fitcsvm的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。