SVM学习笔记(1):Win下LibSVM在Matlab中的安装及使用

1 LibSVM工具包简介

LIBSVM是台湾大学林智仁(Lin Chih-Jen)教授于2001年开发设计,可在 http://www.csie.ntu.edu.tw/~cjlin/libsvm/ 或 https://github.com/cjlin1/libsvm/releases 免费获得。
下载后解压,主要有6个文件夹和一些源码文件:

  • Java: 主要是应用于java平台;
  • matlab: windows下64位matlab平台;
  • python: 是用来参数优选的工具, 稍后介绍;
  • svm-toy: 一个可视化的工具, 用来展示训练数据和分类界面, 里面是源码, 其编译后的程序在windows文件夹下;
  • tools: 主要包含四个python文件, 用来数据集抽样(subset), 参数优选(grid), 集成测试(easy), 数据检查(checkdata);
  • windows: 包含libSVM四个exe程序包, 我们所用的库就是他们.

2 Win下LIBSVM在Matlab2016b中的安装使用

  1. 将下载的LIBSVM压缩包libsvm-3.23.zip(2018年8月时最新版本)解压,把解压出的文件夹libsvm-3.23复制到Matlab的安装路径下...\MATLAB\R2016b\toolbox
  2. ...\MATLAB\R2016b\toolbox\libsvm-3.23添加到Matlab的搜索路径(添加并包含子文件夹)

注:
因为使用的是64位的操作系统和matlab,而...\MATLAB\R2016b\toolbox\libsvm-3.23\windows下包含了matlab可执行的64位二进制文件libsvmread.mexw64/libsvmwrite.mexw64/svmpredict.mexw64/svmtrain.mexw64,故无需自己编译。
假设你使用的是32位操作系统和matlab,则需要自己编译相应的二进制文件:在matlab命令窗口输入mex –setup,这时matlab会提示你选择编译mex文件的c/c++编译器。选择一个你电脑上安装的c/c++编译器,例如Microsoft Visual C++ 2010,将matlab当前目录设置为:‘…\MATLAB\R2016b\toolbox\libsvm-3.23\matlab’,输入命令make,这时你会看到当前目录生成了二进制文件libsvmread.mexw32/libsvmwrite.mexw32/svmpredict.mexw32/svmtrain.mexw32。将当前目录添加到matlab路径中即可。

  1. 把当前目录设置为...\MATLAB\R2016b\toolbox\libsvm-3.23,输入如下测试代码:
[heart_scale_label,heart_scale_inst]=libsvmread('heart_scale');
model = svmtrain(heart_scale_label, heart_scale_inst, '-c 1 -g 0.07');
[predict_label, accuracy, dec_values] =svmpredict(heart_scale_label, heart_scale_inst, model); % test the traindata

得到如下结果,说明安装成功:

*
optimization finished, #iter = 134
nu = 0.433785
obj = -101.855060, rho = 0.426412
nSV = 130, nBSV = 107
Total nSV = 130
Accuracy = 86.6667% (234/270) (classification)

参考:SVM学习笔记(1)LIBSVM在matlab下的使用安装

3 LIBSVM相关函数说明

3.1 libsvmread主要用于读取数据

这里的数据是非matlab下的.mat数据,比如说是.txt,.data等等,这个时候需要使用libsvmread函数进行转化为matlab可识别数据,比如自带的数据是heart_scale数据,那么导入到matlab有两种方式,
一种使用libsvmread函数,在matlab下直接libsvmread(heart_scale);
第二种方式为点击matlab的‘导入数据’按钮,然后导向heart_scale所在位置,直接选择就可以了。因为有的数据libsvmread读取不管用,但是‘导入数据’后就可以变成matlab下数据。

3.2 libsvmwrite写函数,就是把已知数据存起来

使用方式为:libsvmwrite(‘filename’,label_vector, instance_matrix);
label_vector是标签,instance_matrix为数据矩阵(注意这个数据必须是稀疏矩阵,就是里面的数据不包含没用的数据(比如很多0),有这样的数据应该去掉再存)。

3.3 svmtrain训练函数,训练数据产生模型的

Options:可用的选项即表示的涵义如下
  -s svm类型:SVM设置类型(默认0)
  0 – C-SVC
  1 --v-SVC
  2 – 一类SVM
  3 – e-SVR
  4 – v-SVR
  (分类问题主要使用0 – C-SVC,回归问题主要使用3 – e-SVR)
  -t 核函数类型:核函数设置类型(默认2)
  0 – 线性:u’v
  1 – 多项式:(ru’v + coef0)^degree(关联参数:-g -r -d)
  2 – RBF函数:exp(-gamma|u-v|^2)(关联参数:-g)
  3 –sigmoid:tanh(r
u’v + coef0)(关联参数:-g -r)
  (一般使用RBF核函数)
  -d degree:核函数中的degree设置(针对多项式核函数)(默认3)
  -g r(gamma):核函数中的gamma函数设置(针对多项式/rbf/sigmoid核函数)(默认1/ num_features,即属性数目的倒数)
  -r coef0:核函数中的coef0设置(针对多项式/sigmoid核函数)((默认0)
  -c cost:设置C-SVC,e -SVR和v-SVR的参数(损失函数)(范围(0,+∞),默认1)
  -n nu:设置v-SVC,一类SVM和v- SVR的参数(范围(0,1],默认0.5)
  -p p:设置e -SVR 中损失函数p的值(范围(0,+∞),默认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
  
其中
  SVM学习笔记(1):Win下LibSVM在Matlab中的安装及使用_第1张图片
  SVM学习笔记(1):Win下LibSVM在Matlab中的安装及使用_第2张图片
  以上这些参数设置可以按照SVM的类型和核函数所支持的参数进行任意组合。如果设置的参数在函数或SVM类型中没有也不会产生影响,程序不会接受该参数;如果应有的参数设置不正确,参数将采用默认值。

附:利用libsvm-mat建立分类模型model参数解密

4 LIBSVM实际应用方法

4.1 获取原始数据(LIBSVM格式)

function write4libsvm 
% 为了使得数据满足libsvm的格式要求而进行的数据格式转换 注意原始格式是mat的数据格式,转化成txt或者dat都可以。
% 原始数据保存格式为: 
%             [标签 第一个属性值 第二个属性值...] 
% 转换后文件格式为满足libsvm的格式要求,即: 
%             [标签 1:第一个属性值 2:第二个属性值 3:第三个属性值 ...] 
% Genial@ustc 
% 2004.6.16 
[filename, pathname] = uigetfile( {'*.mat', ... 
       '数据文件(*.mat)'; ... 
       '*.*',                   '所有文件 (*.*)'}, ... 
   '选择数据文件'); 
try 
   S=load([pathname filename]); 
   fieldName = fieldnames(S); 
   str = cell2mat(fieldName); 
   B = getfield(S,str); 
   [m,n] = size(B); 
   [filename, pathname] = uiputfile({'*.txt;*.dat' ,'数据文件(*.txt;*.dat)';'*.*','所有文件 (*.*)'},'保存数据文件'); 
   fid = fopen([pathname filename],'w'); 
   if(fid~=-1) 
       for k=1:m 
           fprintf(fid,'%3d',B(k,1)); 
           for kk = 2:n 
               fprintf(fid,'\t%d',(kk-1)); 
               fprintf(fid,':'); 
               fprintf(fid,'%d',B(k,kk)); 
           end 
           k; 
           fprintf(fid,'\n'); 
       end 
       fclose(fid); 
   else 
       msgbox('无法保存文件!'); 
   end 
catch 
end

参考:
如何转成libsvm支持的数据格式并做回归分析

4.2 数据预处理(归一化)

先归一化再划分训练集、测试集

% 数据集归一化
dataset_c21_label = dataset_c21(:,1);dataset_c21_inst = dataset_c21(:,2:136);
[dataset_c21_scale_T,PS] = mapminmax(dataset_c21_inst'); dataset_c21_scale = dataset_c21_scale_T';

% Matlab中的mapminmax用法
% [inputtrain,setting] = mapminmax(input_train');
% inputtest = mapminmax('apply',input_test',setting);

4.3 划分训练集、测试集

% 随机划分训练集、测试集,训练集:测试集=6:4,使用函数split_train_test.m,ratio=0.6
[X_train, y_train,  X_test, y_test] = split_train_test(dataset_c21_scale(:,1:5*i), dataset_c21_label, 2, 0.6);
function [X_train, y_train,  X_test, y_test] = split_train_test(X, y, k, ratio)
%SPLIT_TRAIN_TEST 分割训练集和测试集
%  参数X是数据矩阵 y是对应类标签 k是类别个数 ratio是训练集的比例
%  返回训练集X_train和对应的类标签y_train 测试集X_test和对应的类标签y_test

m = size(X, 1);
y_labels = unique(y); % 去重,k应该等于length(y_labels) 
d = [1:m]';

X_train_0 = [];y_train_0= [];
for i = 1:k
    comm_i = find(y == y_labels(i));
    if isempty(comm_i) % 如果该类别在数据集中不存在
        continue;
    end
    size_comm_i = length(comm_i);
    rp = randperm(size_comm_i); % random permutation
    rp_ratio = rp(1:floor(size_comm_i * ratio));
    ind = comm_i(rp_ratio);
    X_train_0 = [X_train_0; X(ind, :)];
    y_train_0 = [y_train_0; y(ind, :)];
    d = setdiff(d, ind);
end
X_test = X(d, :);y_test = y(d, :);
% famirtse增加:打乱训练集的顺序,日期:20180901
Xy_train_0 = [y_train_0,X_train_0];
rowrank = randperm(size(Xy_train_0, 1));Xy_train = Xy_train_0(rowrank, :); % 随机打乱矩阵的行数
X_train = Xy_train(:,2:end);y_train = Xy_train(:,1);
end

参考:再议归一化问题
归一化函数mapminmax的讨论
归一化问题
Matlab实现 把数据集X分割成训练集和测试集
Matlab划分测试集和训练集

4.4 采取交叉验证选择最佳c,g

 % 参数(c,g)寻优,使用函数SVMcg.m
[bestacc,bestc,bestg] = SVMcg(y_train,X_train,-8,8,-8,8,10,0.5,0.5,0.9);
cmd = ['-c',num2str(bestc),'-g',num2str(bestg),'-w1 2 -w0 0.5'];
function [bestacc,bestc,bestg] = SVMcg(train_label,train,cmin,cmax,gmin,gmax,v,cstep,gstep,accstep)
%SVMcg cross validation by faruto
%Email:[email protected] QQ:516667408 http://blog.sina.com.cn/faruto BNU
%last modified 2009.8.23
%Super Moderator @ www.ilovematlab.cn
%% 参数说明:
% train_label:训练集标签.要求与libsvm工具箱中要求一致.
% train:训练集.要求与libsvm工具箱中要求一致.
% cmin:惩罚参数c的变化范围的最小值(取以2为底的对数后),即 c_min = 2^(cmin).默认为 -5
% cmax:惩罚参数c的变化范围的最大值(取以2为底的对数后),即 c_max = 2^(cmax).默认为 5
% gmin:参数g的变化范围的最小值(取以2为底的对数后),即 g_min = 2^(gmin).默认为 -5
% gmax:参数g的变化范围的最小值(取以2为底的对数后),即 g_min = 2^(gmax).默认为 5
% v:cross validation的参数,即给测试集分为几部分进行cross validation.默认为 3
% cstep:参数c步进的大小.默认为 1
% gstep:参数g步进的大小.默认为 1
% accstep:最后显示准确率图时的步进大小. 默认为 1.5
%% about the parameters of SVMcg 
if nargin < 10
    accstep = 1.5;
end
if nargin < 8
    accstep = 1.5;
    cstep = 1;
    gstep = 1;
end
if nargin < 7
    accstep = 1.5;
    v = 3;
    cstep = 1;
    gstep = 1;
end
if nargin < 6
    accstep = 1.5;
    v = 3;
    cstep = 1;
    gstep = 1;
    gmax = 5;
end
if nargin < 5
    accstep = 1.5;
    v = 3;
    cstep = 1;
    gstep = 1;
    gmax = 5;
    gmin = -5;
end
if nargin < 4
    accstep = 1.5;
    v = 3;
    cstep = 1;
    gstep = 1;
    gmax = 5;
    gmin = -5;
    cmax = 5;
end
if nargin < 3
    accstep = 1.5;
    v = 3;
    cstep = 1;
    gstep = 1;
    gmax = 5;
    gmin = -5;
    cmax = 5;
    cmin = -5;
end
%% X:c Y:g cg:acc
[X,Y] = meshgrid(cmin:cstep:cmax,gmin:gstep:gmax);
[m,n] = size(X);
cg = zeros(m,n);
%% record acc with different c & g,and find the bestacc with the smallest c
bestc = 0;
bestg = 0;
bestacc = 0;
basenum = 2;
for i = 1:m
    for j = 1:n
        cmd = ['-v ',num2str(v),' -c ',num2str( basenum^X(i,j) ),' -g ',num2str( basenum^Y(i,j) )];
        cg(i,j) = svmtrain(train_label, train, cmd);

        if cg(i,j) > bestacc
            bestacc = cg(i,j);
            bestc = basenum^X(i,j);
            bestg = basenum^Y(i,j);
        end
        if ( cg(i,j) == bestacc && bestc > basenum^X(i,j) )
            bestacc = cg(i,j);
            bestc = basenum^X(i,j);
            bestg = basenum^Y(i,j);
        end
    end
end
%% to draw the acc with different c & g
[C,h] = contour(X,Y,cg,60:accstep:100);
clabel(C,h,'FontSize',10,'Color','r');
xlabel('log2c','FontSize',10);
ylabel('log2g','FontSize',10);
grid on;

参考:
关于SVM参数c&g选取的总结帖[matlab-libsvm]

4.5 训练、测试、预测

% 训练
model = svmtrain(y_train, X_train, cmd);
% 测试/预测
[predict_label, accuracy, dec_values] = svmpredict(y_test, X_test, model);
acc = accuracy(1);

4.6 评估

% 计算敏感性和特异性
sens = sum(predict_label==1&y_test==1)/sum(y_test==1)*100;
spec = sum(predict_label==0&y_test==0)/sum(y_test==0)*100;

5 其他一些问题

5.1 Matlab中使用libsvm进行分类预测时的标签问题

首先用svm(libsvm,lssvm、hssvm)等等进行分类预测,要进行三个步骤1、训练 2、测试 3、预测
1、训练——大家都知道,就是用训练数据集,不管你采用那种寻优方式,得到相对的最优参数,训练模型。

2、测试——就是用刚刚得到的模型,对测试数据进行测试,此时测试数据集的label是已知的,这主要是用来对刚刚的模型的检测,或者是对参数的检测、或者是对模型的泛化能力的检测。此时会得到一个准确率,这时的准确率是有用的,是有实际意义的,因为原来的label是已知的。

3、预测——预测就是对未知类别的样本在测试确定了模型有好的泛化能力的情况下的预测分类,这步才是真的预测能力功能的实现。此时数据的label随便给了,这样是为了满足libsvm对数据格式的要求。此时也会得到一个准确率,但是这个是没有实际意义的,因为原始的label是随便给的,没有意义,我们只是关心的是最后得到的类别号——达到分类的目的。

5.2 交叉验证(CrossValidation)方法思想简介

以下简称交叉验证(Cross Validation)为CV.CV是用来验证分类器的性能一种统计分析方法,基本思想是把在某种意义下将原始数据(dataset)进行分组,一部分做为训练集(train set),另一部分做为验证集(validation set),首先用训练集对分类器进行训练,在利用验证集来测试训练得到的模型(model),以此来做为评价分类器的性能指标.常见CV的方法如下:

1).Hold-Out Method
将原始数据随机分为两组,一组做为训练集,一组做为验证集,利用训练集训练分类器,然后利用验证集验证模型,记录最后的分类准确率为此Hold-OutMethod下分类器的性能指标.此种方法的好处的处理简单,只需随机把原始数据分为两组即可,其实严格意义来说Hold-Out Method并不能算是CV,因为这种方法没有达到交叉的思想,由于是随机的将原始数据分组,所以最后验证集分类准确率的高低与原始数据的分组有很大的关系,所以这种方法得到的结果其实并不具有说服性.

2).K-fold Cross Validation(记为K-CV)
将原始数据分成K组(一般是均分),将每个子集数据分别做一次验证集,其余的K-1组子集数据作为训练集,这样会得到K个模型,用这K个模型最终的验证集的分类准确率的平均数作为此K-CV下分类器的性能指标.K一般大于等于2,实际操作时一般从3开始取,只有在原始数据集合数据量小的时候才会尝试取2.K-CV可以有效的避免过学习以及欠学习状态的发生,最后得到的结果也比较具有说服性.

3).Leave-One-Out Cross Validation(记为LOO-CV)
如果设原始数据有N个样本,那么LOO-CV就是N-CV,即每个样本单独作为验证集,其余的N-1个样本作为训练集,所以LOO-CV会得到N个模型,用这N个模型最终的验证集的分类准确率的平均数作为此下LOO-CV分类器的性能指标.相比于前面的K-CV,LOO-CV有两个明显的优点:
①a.每一回合中几乎所有的样本皆用于训练模型,因此最接近原始样本的分布,这样评估所得的结果比较可靠。
②b.实验过程中没有随机因素会影响实验数据,确保实验过程是可以被复制的。

但LOO-CV的缺点则是计算成本高,因为需要建立的模型数量与原始数据样本数量相同,当原始数据样本数量相当多时,LOO-CV在实作上便有困难几乎就是不显示,除非每次训练分类器得到模型的速度很快,或是可以用并行化计算减少计算所需的时间.

参考:交叉验证(CrossValidation)方法思想简介

5.3 关于SVM参数c&g选取的总结

选取SVM中参数 c和g的最佳值
寻找最佳c和g的思想仍然是让c和g在一定的范围里跑(比如 c = 2(-5),2(-4),…,2^(5),g = 2(-5),2(-4),…,2^(5)),然后用cross validation的想法找到是的准确率最高的c和g,在这里做了一点修改是: 因为会有不同的c和g都对应最高的的准确率,我把具有最小c的那组c和g认为是最佳的c和g,因为惩罚参数不能设置 太高,很高的惩罚参数能使得validation数据的准确率提高,但过高的惩罚参数c会造成过学习状态,往往都是惩罚参数c过高会导致最终测试集合的准确率并不是很理想 。

先大范围粗糙的找 比较理想的c和g,然后再细范围找更加理想的c和g.
比如首先让 c = 2(-5),2(-4),…,2^(5),g = 2(-5),2(-4),…,2^(5)在这个范围找比较理想的c和g。
此时bestc = 0.5,bestg=1,bestacc = 98.8764[cross validation 的准确率]
最终测试集合的准确率 Accuracy = 96.6292% (86/89) (classification)

6 Libsvm-Faruto Ultimate工具箱

下载:
libsvm-3.1-FarutoUltimate3.1Mcode,faruto最新加强工具箱
参考:
Libsvm-Faruto Ultimate工具箱学习笔记
libsvm-3.1-[FarutoUltimate3.1Mcode]——辅助函数简介(修改

参考:
学习SVM
SVM学习笔记(1)LIBSVM在matlab下的使用安装
【svm】使用libsvm分类的一般操作步骤

你可能感兴趣的:(ML,ML,SVM,LIBSVM)