简单粗暴理解支持向量机(SVM)及其MATLAB实例

目录

SVM概述

SVM的改进:解决回归拟合问题的SVR

多分类的SVM

QP求解

SVM的MATLAB实现:Libsvm

【实例】用SVM分类

【实例】用SVM回归

SVM概述

SVM已经是非常流行、大家都有所耳闻的技术了。网络上也有很多相关的博客,讲解得都非常详细。如果你要从零开始推导一个SVM,细致抠它全程的数学原理,我建议可以阅读此篇文章:Zhang Hao的《从零构建支持向量机》。因此本文就不做过多的枯燥的数学原理的讲解。

下面我们只针对数学基础不一、偏工程应用的同学,用简单的语言描述来帮助理解SVM。

简单粗暴理解支持向量机(SVM)及其MATLAB实例_第1张图片

传统的SVM做的事情其实就是找到一个超平面,实现二分类,一类+1,一类-1。如上所示。它的目的就是使得两类的间隔最大。黑色的块表示距离分割面最近的样本向量,称为支持向量

如果我们在低维空间里找不到一个线性分类面把样本分开,SVM就为我们提供了一个思路:将数据从低维空间映射到高维空间后,就很可能使得这堆数据线性可分。比如说,我们要在猫科动物这个特征很局限的“低维空间”里去分猫和老虎,是比较困难的,因为他们很多特征比较相近。但是,如果我们有了更多的参考依据,从生物界的视角,即一个“高维空间”再去区分猫和老虎,我们就有了更多的理由来做出科学的辨别。至于如何低维映射到高维,就是一门数学上的学问了。

简单粗暴理解支持向量机(SVM)及其MATLAB实例_第2张图片

数据从输入到输出的过程其实和神经网络非常像:

简单粗暴理解支持向量机(SVM)及其MATLAB实例_第3张图片

K就是核函数,做一个内积的运算。SVM中核函数保证了低维空间里的计算量,输出到高维空间里。

K相当于隐含层的神经元。核函数的输出乘上权重,进入激活函数处。

简单粗暴理解支持向量机(SVM)及其MATLAB实例_第4张图片

SVM的改进:解决回归拟合问题的SVR

  • 为了利用SVM解决回归拟合方面的问题,Vapnik等人在SVM分 类的基础上引入了 不敏感损失函数,从而得到了回归型支持向 量机(Support Vector Machine for Regression,SVR)。

  • SVM应用于回归拟合分析时,其基本思想不再是寻找一个最优 分类面使得两类样本分开,而是寻找一个最优分类面使得所有 训练样本离该最优分类面的误差最小

简单粗暴理解支持向量机(SVM)及其MATLAB实例_第5张图片

多分类的SVM

当我们要分多类,而不是简单的二分类(+1,-1)时,怎么破?

解决思路:把多分类转化为二分类问题。具体来看有两个办法:

1. one-against-all

      Classification of new instances for one-against-all case is done by a winner-takes-all strategy, in which the classifier

with the highest output function assigns the class.

比如有一堆样本,打算分成10类。那么我们先取第1类训练标记为【1】。其他9类都是【-1】。这样经过一次SVM就可以得到第1类。

然后我们对【-1】中的9类继续做上述操作,分出第2类。

再以此类对,逐渐把第3、第4类分出来……直至分完。

2. one-against-one

       For the one-against-one approach, classification is done by a max-wins voting strategy, in which every classifier assigns the instance to one of the two classes, then the vote for the assigned class is increased by one vote, and finally the class with most votes determines the instance classification.

比如,一共有10种类别的一堆数据。那么我们就要训练C{2,5}=10(组合数)个SVM分类器。每个SVM分类器都可以区分出两种类别。我们把数据分别输入到这10个SVM分类器中,根据结果进行投票,依据得票数最多来确定它的类别。

QP求解

大致有下面4种方法:

分块算法(Chunking)

Osuna算法

序列最小优化算法(Sequential Minimal Optimization,SMO)

增量学习算法(IncrementalLearning)

数学原理比较难解释清楚,大家可以看Zhang Hao的那篇文章细究。

SVM的MATLAB实现:Libsvm

工具箱下载:https://github.com/cjlin1/libsvm

首先,要给macOS系统的Matlab,配置好xcode支持的编译器:https://blog.csdn.net/lyxleft/article/details/83756592

在MacOS X系统上,为matlab安装libsvm工具箱:https://www.jianshu.com/p/f45e1828ed85

重要函数:

  • meshgrid 交叉验证用

    • –  Generate X and Y arrays for 3-D plots

    • –  [X,Y] = meshgrid(x,y) –

  • svmtrain

    • –  Train support vector machine classifier

    • –  model = svmtrain(train_label,train_matrix,’libsvm_options’);

    • Options:可用的选项即表示的涵义如下:
        -s svm类型:SVM设置类型(默认0)
          0 -- C-SVC
          1 -- nu-SVC
          2 -- one-class SVM
          3 -- epsilon-SVR
          4 -- nu-SVR
        -t 核函数类型:核函数设置类型(默认2)
          0 -- linear: u'*v 线性
          1 -- polynomial: (gamma*u'*v + coef0)^degree   多项式
          2 -- radial basis function: exp(-gamma*|u-v|^2) RBF
          3 -- sigmoid: tanh(gamma*u'*v + coef0)
          4 -- precomputed kernel (kernel values in training_instance_matrix)
        -d degree:核函数中的degree设置(针对多项式核函数)(默认3)
        -g r(gama):核函数中的gamma函数设置(针对多项式/rbf/sigmoid核函数)(默认1/ k)
        -r coef0:核函数中的coef0设置(针对多项式/sigmoid核函数)((默认0)
        -c cost:设置C-SVC,e -SVR和v-SVR的参数(损失函数)(默认1)  惩罚因子
        -n nu:设置v-SVC,一类SVM和v- SVR的参数(默认0.5)
        -p p:设置e -SVR 中损失函数p的值(默认0.1)
        -m cachesize:设置cache内存大小,以MB为单位(默认40)
        -e eps:设置允许的终止判据(默认0.001)
        -h shrinking:是否使用启发式,0或1(默认1)
        -wi weight:设置第几类的参数C为weight*C(C-SVC中的C)(默认1)
        -v n: n-fold交互检验模式,n为fold的个数,必须大于等于2
        其中-g选项中的k是指输入数据中的属性数。option -v 随机地将数据剖分为n部分并计算交互检验准确度和均方根误差。
         以上这些参数设置可以按照SVM的类型和核函数所支持的参数进行任意组合,如果设置的参数在函数或SVM类型中没有也不会产生影响,程序不会接受该参数;如果应有的参数设置不正确,参数将采用默认值。

  • svmpredict

    • –  Predict data using support vector machine

    • –  [predict_label,accuracy] = svmpredict(test_label,test_matrix,model);

下面要用到的数据集在:链接:https://pan.baidu.com/s/1XwhynjKuJOVsa5Nxi9NVaA  密码:d0u7

【实例】用SVM分类

%% I. 清空环境变量
clear all
clc

%% II. 导入数据
load BreastTissue_data.mat

%%
% 1. 随机产生训练集和测试集
n = randperm(size(matrix,1));

%%
% 2. 训练集――80个样本
train_matrix = matrix(n(1:80),:);
train_label = label(n(1:80),:);

%%
% 3. 测试集――26个样本
test_matrix = matrix(n(81:end),:);
test_label = label(n(81:end),:);

%% III. 数据归一化
[Train_matrix,PS] = mapminmax(train_matrix');
Train_matrix = Train_matrix';
Test_matrix = mapminmax('apply',test_matrix',PS);
Test_matrix = Test_matrix';

%% IV. SVM创建/训练(RBF核函数)
%%
% 1. 寻找最佳c/g参数――交叉验证方法
[c,g] = meshgrid(-10:0.2:10,-10:0.2:10);
[m,n] = size(c);
cg = zeros(m,n);
eps = 10^(-4);
v = 5;
bestc = 1;
bestg = 0.1;
bestacc = 0;
for i = 1:m
    for j = 1:n
        cmd = ['-v ',num2str(v),' -t 2',' -c ',num2str(2^c(i,j)),' -g ',num2str(2^g(i,j))];
        cg(i,j) = svmtrain(train_label,Train_matrix,cmd);     
        if cg(i,j) > bestacc
            bestacc = cg(i,j);
            bestc = 2^c(i,j);
            bestg = 2^g(i,j);
        end        
        if abs( cg(i,j)-bestacc )<=eps && bestc > 2^c(i,j) 
            bestacc = cg(i,j);
            bestc = 2^c(i,j);
            bestg = 2^g(i,j);
        end               
    end
end
cmd = [' -t 2',' -c ',num2str(bestc),' -g ',num2str(bestg)];

%%
% 2. 创建/训练SVM模型
model = svmtrain(train_label,Train_matrix,cmd);

%% V. SVM仿真测试
[predict_label_1,accuracy_1] = svmpredict(train_label,Train_matrix,model);
[predict_label_2,accuracy_2] = svmpredict(test_label,Test_matrix,model);
result_1 = [train_label predict_label_1];
result_2 = [test_label predict_label_2];

%% VI. 绘图
figure
plot(1:length(test_label),test_label,'r-*')
hold on
plot(1:length(test_label),predict_label_2,'b:o')
grid on
legend('真实类别','预测类别')
xlabel('测试集样本编号')
ylabel('测试集样本类别')
string = {'测试集SVM预测结果对比(RBF核函数)';
          ['accuracy = ' num2str(accuracy_2(1)) '%']};
title(string)

【实例】用SVM回归

%% I. 清空环境变量
clear all
clc

%% II. 导入数据
load concrete_data.mat

%%
% 1. 随机产生训练集和测试集
n = randperm(size(attributes,2));

%%
% 2. 训练集――80个样本
p_train = attributes(:,n(1:80))';
t_train = strength(:,n(1:80))';

%%
% 3. 测试集――23个样本
p_test = attributes(:,n(81:end))';
t_test = strength(:,n(81:end))';

%% III. 数据归一化
%%
% 1. 训练集
[pn_train,inputps] = mapminmax(p_train');
pn_train = pn_train';
pn_test = mapminmax('apply',p_test',inputps);
pn_test = pn_test';

%%
% 2. 测试集
[tn_train,outputps] = mapminmax(t_train');
tn_train = tn_train';
tn_test = mapminmax('apply',t_test',outputps);
tn_test = tn_test';

%% IV. SVM模型创建/训练
%%
% 1. 寻找最佳c参数/g参数
[c,g] = meshgrid(-10:0.5:10,-10:0.5:10);
[m,n] = size(c);
cg = zeros(m,n);
eps = 10^(-4);
v = 5;
bestc = 0;
bestg = 0;
error = Inf;
for i = 1:m
    for j = 1:n
        cmd = ['-v ',num2str(v),' -t 2',' -c ',num2str(2^c(i,j)),' -g ',num2str(2^g(i,j) ),' -s 3 -p 0.1'];
        cg(i,j) = svmtrain(tn_train,pn_train,cmd);
        if cg(i,j) < error
            error = cg(i,j);
            bestc = 2^c(i,j);
            bestg = 2^g(i,j);
        end
        if abs(cg(i,j) - error) <= eps && bestc > 2^c(i,j)
            error = cg(i,j);
            bestc = 2^c(i,j);
            bestg = 2^g(i,j);
        end
    end
end

%%
% 2. 创建/训练SVM  
cmd = [' -t 2',' -c ',num2str(bestc),' -g ',num2str(bestg),' -s 3 -p 0.01'];
model = svmtrain(tn_train,pn_train,cmd);

%% V. SVM仿真预测
[Predict_1,error_1] = svmpredict(tn_train,pn_train,model);
[Predict_2,error_2] = svmpredict(tn_test,pn_test,model);

%%
% 1. 反归一化
predict_1 = mapminmax('reverse',Predict_1,outputps);
predict_2 = mapminmax('reverse',Predict_2,outputps);

%%
% 2. 结果对比
result_1 = [t_train predict_1];
result_2 = [t_test predict_2];

%% VI. 绘图
figure(1)
plot(1:length(t_train),t_train,'r-*',1:length(t_train),predict_1,'b:o')
grid on
legend('真实值','预测值')
xlabel('样本编号')
ylabel('耐压强度')
string_1 = {'训练集预测结果对比';
           ['mse = ' num2str(error_1(2)) ' R^2 = ' num2str(error_1(3))]};
title(string_1)
figure(2)
plot(1:length(t_test),t_test,'r-*',1:length(t_test),predict_2,'b:o')
grid on
legend('真实值','预测值')
xlabel('样本编号')
ylabel('耐压强度')
string_2 = {'测试集预测结果对比';
           ['mse = ' num2str(error_2(2)) ' R^2 = ' num2str(error_2(3))]};
title(string_2)

%% VII. BP神经网络
%%
% 1. 数据转置
pn_train = pn_train';
tn_train = tn_train';
pn_test = pn_test';
tn_test = tn_test';

%%
% 2. 创建BP神经网络
net = newff(pn_train,tn_train,10);

%%
% 3. 设置训练参数
net.trainParam.epochs = 1000;
net.trainParam.goal = 1e-3;
net.trainParam.show = 10;
net.trainParam.lr = 0.1;

%%
% 4. 训练网络
net = train(net,pn_train,tn_train);

%%
% 5. 仿真测试
tn_sim = sim(net,pn_test);

%%
% 6. 均方误差
E = mse(tn_sim - tn_test);

%%
% 7. 决定系数
N = size(t_test,1);
R2=(N*sum(tn_sim.*tn_test)-sum(tn_sim)*sum(tn_test))^2/((N*sum((tn_sim).^2)-(sum(tn_sim))^2)*(N*sum((tn_test).^2)-(sum(tn_test))^2)); 

%%
% 8. 反归一化
t_sim = mapminmax('reverse',tn_sim,outputps);

%%
% 9. 绘图
figure(3)
plot(1:length(t_test),t_test,'r-*',1:length(t_test),t_sim,'b:o')
grid on
legend('真实值','预测值')
xlabel('样本编号')
ylabel('耐压强度')
string_3 = {'测试集预测结果对比(BP神经网络)';
           ['mse = ' num2str(E) ' R^2 = ' num2str(R2)]};
title(string_3)

更正:

有些同学跑不了我给的程序。引用评论里同学的指导:(最近太忙还没时间细看,先贴在此处给大家参考)

第一个实例:用SVM分类 中,第62 63行代码 [predict_label_1,accuracy_1] = svmpredict(train_label,Train_matrix,model); [predict_label_2,accuracy_2] = svmpredict(test_label,Test_matrix,model); 需要改为: [predict_label_1,accuracy_1,decision_values1] = svmpredict(train_label,Train_matrix,model); [predict_label_2,accuracy_2,decision_values2] = svmpredict(test_label,Test_matrix,model); 第二个实例:用SVM回归 中,第71 72行代码 [Predict_1,error_1] = svmpredict(tn_train,pn_train,model); [Predict_2,error_2] = svmpredict(tn_test,pn_test,model); 需要改为: [Predict_1,error_1,decision_values1] = svmpredict(tn_train,pn_train,model); [Predict_2,error_2,decision_values2] = svmpredict(tn_test,pn_test,model);

你可能感兴趣的:(机器学习算法MATLAB实例)