加载中…
正文 字体大小:

LibSVM学习3:一个实例搞定libsvm分类

(2011-08-06 09:32:02)
标签:

杂谈

分类: SVM学习

转自:【by faruto】

http://www.matlabsky.com/thread-18521-1-1.html

 

视频的帖子地址:

http://player.youku.com/player.php/sid/XMjg0NzgxMDk2/v.swf

 

 

本讲视频相关帖子:
【1】如何使用libsvm进行分类

http://www.matlabsky.com/thread-12379-1-1.html
【2】利用libsvm-mat建立分类模型model参数解密

http://www.matlabsky.com/thread-12649-1-1.html
【3】Matlab中使用libsvm进行分类预测时的标签问题再次说明
http://www.matlabsky.com/thread-12396-1-1.html

【1】如何使用libsvm进行分类

这帖子就是初步教教刚接触libsvm(svm)的同学如何利用libsvm进行分类预测,关于参数寻优的问题在这里姑且不谈,另有帖子详述。

其实使用libsvm进行分类很简单,只需要有属性矩阵和标签,然后就可以建立分类模型(model),然后利用得到的这个model进行分类预测了。

那神马是属性矩阵?神马又是标签呢?我举一个直白的不能在直白的例子:
说一个班级里面有两个男生(男生1、男生2),两个女生(女生1、女生2),其中

男生1 身高:176cm 体重:70kg;
男生2 身高:180cm 体重:80kg;

女生1 身高:161cm 体重:45kg;
女生2 身高:163cm 体重:47kg;


如果我们将男生定义为1,女生定义为-1,并将上面的数据放入矩阵data中,即

  1. data = [176 70;
  2. 180 80;
  3. 161 45;
  4. 163 47];
复制代码

在label中存入男女生类别标签(1、-1),即

  1. label = [1;1;-1;-1];
复制代码

这样上面的data矩阵就是一个属性矩阵,行数4代表有4个样本,列数2表示属性有两个,label就是标签(1、-1表示有两个类别:男生、女生)。

Remark:这里有一点废话一些(因为我看到不止一个朋友问我这个相关的问题):
上面我们将男生定义为1,女生定义为-1,那定义成别的有影响吗?
这个肯定没有影响啊!(
用脚趾头都能想出来,我不知道为什么也会有人问),这里面的标签定义就是区分开男生和女生,怎么定义都可以的,只要定义成数值型的就可以。
比如我可将将男生定义为2,女生定义为5;后面的label相应为label=[2;2;5;5];
比如我可将将男生定义为18,女生定义为22;后面的label相应为label=[18;18;22;22];

为什么我说这个用脚趾头都能想怎么定义都可以呢?学过数学的应该都会明白,将男生定义为1,女生定义为-1和将男生定义为2,女生定义为5本质是一样的,应为可以找到一个映射将(2,5)转换成(1,-1),so所以本质都是一样的,后面的18、22本质也是一样的。
这里要多说一些,如果你原本的数据集合的标签不是数值型的(比如a、b、c)那么你完全可以通过某种转换映射将不是数值型的标签转换成数值型的。



现在回归正题,有了上面的属性矩阵data,和标签label就可以利用libsvm建立分类模型了,简要代码如下:

  1. model = svmtrain(label,data);
复制代码

有了model我们就可以做分类预测,比如此时该班级又转来一个新学生,其
身高190cm,体重85kg
我们想通过上面这些信息就给出其标签(想知道其是男【1】还是女【-1】)
比如 令 testdata = [190 85]; 由于其标签我们不知道,我们假设其标签为-1(也可以假设为1)

Remark:这里又有一点废话一些(因为我看到不止一个朋友问我这个相关的问题):
如果测试集合的标签没有怎么办?测试集合的标签就应该没有,否则测试集合的标签都有了,还预测你妹啊!?没有是正确的,就像上面一样,新来的学生其标签咱不应知道,就想通过其属性矩阵来预测其标签,这才是预测分类的真正目的。
之所以平时做测试时,测试集合的标签一般都有,那是因为一般人们想要看看自己的分类器的效果如何,效果的评价指标之一就是分类预测的准确率,这就需要有测试集的本来的真实的标签来进行分类预测准确率的计算。



话归正传,即
testdatalabel = -1;

然后利用libsvm来预测这个新来的学生是男生还是女生,代码如下:

  1. [predictlabel,accuracy] = svmpredict(testdatalabel,testdata,model)
复制代码

下面我们整体运行一下上面这段恶 搞[e gao]的背景数据和代码(你别笑,这个是真能运行的,也有结果的):

  1. data = [176 70;
  2. 180 80;
  3. 161 45;
  4. 163 47];
  5. label = [1;1;-1;-1];

  6. model = svmtrain(label,data);

  7. testdata = [190 85];
  8. testdatalabel = -1;

  9. [predictlabel,accuracy] = svmpredict(testdatalabel,testdata,model);
  10. predictlabel
复制代码

运行结果如下:

  1. Accuracy = 0% (0/1) (classification)
  2. predictlabel =
  3.      1
复制代码

哎,我们看到,通过预测我们得知这个新来的学生的标签是1(男生),由于原本我们假设其标签为-1,假设错误,所以分类准确率为0%。


好,通过上面的讲解,不知道诸位看官对于利用libsvm进行分类是否有了一定了解【谁要是这么通俗的例子还搞不清楚怎么使用libsvm进行分类,那我真无语啦】,下面使用libsvm工具箱本身带的测试数据heart_scale来实际进行一下测试:

  1. %% HowToClassifyUsingLibsvm
  2. % by faruto @ faruto's Studio~
  3. % http://blog.sina.com.cn/faruto
  4. % Email:faruto@163.com
  5. % http://www.matlabsky.com
  6. % http://www.mfun.la
  7. % http://video.ourmatlab.com
  8. % last modified by 2010.12.27
  9. %% a litte clean work
  10. tic;
  11. close all;
  12. clear;
  13. clc;
  14. format compact;
  15. %%

  16. % 首先载入数据
  17. load heart_scale;
  18. data = heart_scale_inst;
  19. label = heart_scale_label;

  20. % 选取前200个数据作为训练集合,后70个数据作为测试集合
  21. ind = 200;
  22. traindata = data(1:ind,:);
  23. trainlabel = label(1:ind,:);
  24. testdata = data(ind+1:end,:);
  25. testlabel = label(ind+1:end,:);

  26. % 利用训练集合建立分类模型
  27. model = svmtrain(trainlabel,traindata,'-s 0 -t 2 -c 1.2 -g 2.8');

  28. % 分类模型model解密
  29. model
  30. Parameters = model.Parameters
  31. Label = model.Label
  32. nr_class = model.nr_class
  33. totalSV = model.totalSV
  34. nSV = model.nSV

  35. % 利用建立的模型看其在训练集合上的分类效果
  36. [ptrain,acctrain] = svmpredict(trainlabel,traindata,model);

  37. % 预测测试集合标签
  38. [ptest,acctest] = svmpredict(testlabel,testdata,model);

  39. %%
  40. toc;
复制代码

运行结果:

  1. model =
  2.     Parameters: [5x1 double]
  3.       nr_class: 2
  4.        totalSV: 197
  5.            rho: 0.0583
  6.          Label: [2x1 double]
  7.          ProbA: []
  8.          ProbB: []
  9.            nSV: [2x1 double]
  10.        sv_coef: [197x1 double]
  11.            SVs: [197x13 double]
  12. Parameters =
  13.          0
  14.     2.0000
  15.     3.0000
  16.     2.8000
  17.          0
  18. Label =
  19.      1
  20.     -1
  21. nr_class =
  22.      2
  23. totalSV =
  24.    197
  25. nSV =
  26.     89
  27.    108
  28. Accuracy = 99.5% (199/200) (classification)
  29. Accuracy = 68.5714% (48/70) (classification)
  30. Elapsed time is 0.040873 seconds.
  31. >>
复制代码

上面的代码基本我不想多说什么。
只是说一下参数输入的意义:

  -s svm类型:SVM设置类型(默认0)
  0 -- C-SVC
  1 --v-SVC
  2 – 一类SVM
  3 -- e -SVR
  4 -- v-SVR
  -t 核函数类型:核函数设置类型(默认2)
  0 – 线性:u'v
  1 – 多项式:(r*u'v + coef0)^degree
  2 – RBF函数:exp(-r|u-v|^2)
  3 –sigmoid:tanh(r*u'v + coef0)

-g r(gama):核函数中的gamma函数设置(针对多项式/rbf/sigmoid核函数)

-c cost:设置C-SVC,e -SVR和v-SVR的参数(损失函数)(默认1)



更多关于libsvm 参数的说明请看
libsvm 参数说明【中英文双语版本】
http://www.matlabsky.com/forum-v ... -fromuid-18677.html

还有关于建立的分类模型model

  1. model =

  2.     Parameters: [5x1 double]

  3.       nr_class: 2

  4.        totalSV: 197

  5.            rho: 0.0583

  6.          Label: [2x1 double]

  7.          ProbA: []

  8.          ProbB: []

  9.            nSV: [2x1 double]

  10.        sv_coef: [197x1 double]

  11.            SVs: [197x13 double]
复制代码

因为好多朋友反映说,比如想得到支持向量,还有model中的一些参看看不懂等等等等一些列问题,会在后面的
分类模型model解密详解中说明

利用libsvm-mat建立分类模型model参数解密【by faruto】

http://www.matlabsky.com/thread-12649-1-1.html

所以也希望诸位看官尤其是对svm感兴趣的朋友多多关注我。O(∩_∩)O~

如果对于标签设置问题您还没有搞懂可以再看看这个:
【转】Matlab中使用libsvm进行分类预测时的标签问题再次说明
http://www.matlabsky.com/forum-v ... -fromuid-18677.html

 

【2】利用libsvm-mat建立分类模型model参数解密

 本帖子主要就是讲解利用libsvm-mat工具箱建立分类(回归模型)后,得到的模型model里面参数的意义都是神马?以及如果通过model得到相应模型的表达式,这里主要以分类问题为例子。

测试数据使用的是libsvm-mat自带的heart_scale.mat数据(270*13的一个属性据矩阵,共有270个样本,每个样本有13个属性),方便大家自己测试学习。

首先上一个简短的测试代码:

  1. %% ModelDecryption
  2. % by faruto @ faruto's Studio~
  3. % http://blog.sina.com.cn/faruto
  4. % Email:faruto@163.com
  5. % http://www.matlabsky.com
  6. % http://www.mfun.la
  7. % http://video.ourmatlab.com
  8. % last modified by 2011.01.06
  9. %% a litte clean work
  10. tic;
  11. close all;
  12. clear;
  13. clc;
  14. format compact;
  15. %%
  16. % 首先载入数据
  17. load heart_scale;
  18. data = heart_scale_inst;
  19. label = heart_scale_label;
  20. % 建立分类模型
  21. model = svmtrain(label,data,'-s 0 -t 2 -c 1.2 -g 2.8');
  22. model
  23. % 利用建立的模型看其在训练集合上的分类效果
  24. [PredictLabel,accuracy] = svmpredict(label,data,model);
  25. accuracy
  26. %%
  27. toc;
复制代码

运行结果:

  1. model =
  2.     Parameters: [5x1 double]
  3.       nr_class: 2
  4.        totalSV: 259
  5.            rho: 0.0514
  6.          Label: [2x1 double]
  7.          ProbA: []
  8.          ProbB: []
  9.            nSV: [2x1 double]
  10.        sv_coef: [259x1 double]
  11.            SVs: [259x13 double]
  12. Accuracy = 99.6296% (269/270) (classification)
  13. accuracy =
  14.    99.6296
  15.     0.0148
  16.     0.9851
  17. Elapsed time is 0.040155 seconds.
复制代码

这里面为了简单起见没有将测试数据进行训练集和测试集的划分,这里仅仅是为了简单明了而已,分类结果估计可以不要管,参数优化也不要管,另有帖子讲解。

下面我们就看看 model这个结构体里面的各种参数的意义都是神马,model如下:

model =
    Parameters: [5x1 double]
      nr_class: 2
       totalSV: 259
           rho: 0.0514
         Label: [2x1 double]
         ProbA: []
         ProbB: []
           nSV: [2x1 double]
       sv_coef: [259x1 double]
           SVs: [259x13 double]



model.Parameters

我们先来看一下model.Parameters里面承装的都是什么:

  1. >> model.Parameters
  2. ans =
  3.          0
  4.     2.0000
  5.     3.0000
  6.     2.8000
  7.          0
复制代码

重要知识点:

model.Parameters参数意义从上到下依次为:
-s svm类型:SVM设置类型(默认0)
-t 核函数类型:核函数设置类型(默认2)
-d degree:核函数中的degree设置(针对多项式核函数)(默认3)
-g r(gama):核函数中的gamma函数设置(针对多项式/rbf/sigmoid核函数) (默认类别数目的倒数)
-r coef0:核函数中的coef0设置(针对多项式/sigmoid核函数)((默认0)



即在本例中通过model.Parameters我们可以得知 –s 参数为0;-t 参数为 2;-d 参数为3;-g 参数为2.8(这也是我们自己的输入);-r 参数为0。

关于libsvm参数的一点小说明:

Libsvm中参数设置可以按照SVM的类型和核函数所支持的参数进行任意组合,如果设置的参数在函数或SVM类型中没有也不会产生影响,程序不会接受该参数;如果应有的参数设置不正确,参数将采用默认值。



model.Label         model.nr_class

  1. >> model.Label
  2. ans =
  3.      1
  4.     -1
  5. >> model.nr_class
  6. ans =
  7.      2
复制代码

重要知识点:

model.Label表示数据集中类别的标签都有什么,这里是 1,-1;
model.nr_class表示数据集中有多少类别,这里是二分类。




model.totalSV                model.nSV

  1. >> model.totalSV
  2. ans =
  3.    259
  4. >> model.nSV
  5. ans =
  6.    118
  7.    141
复制代码

重要知识点:

model.totalSV代表总共的支持向量的数目,这里共有259个支持向量;
model.nSV表示每类样本的支持向量的数目,这里表示标签为1的样本的支持向量有118个,标签为-1的样本的支持向量为141。
注意:这里model.nSV所代表的顺序是和model.Label相对应的。



model.ProbA         model.ProbB

关于这两个参数这里不做介绍,使用-b参数时才能用到,用于概率估计。

-b probability_estimates: whether to train a SVC or SVR model for probability estimates, 0 or 1 (default 0)




model.sv_coef         model.SVs        model.rho

  1.        sv_coef: [259x1 double]
  2.            SVs: [259x13 double]
  3.                 model.rho =  0.0514
复制代码

重要知识点:

model.sv_coef是一个259*1的矩阵,承装的是259个支持向量在决策函数中的系数;
model.SVs是一个259*13的稀疏矩阵,承装的是259个支持向量。
model.rho是决策函数中的常数项的相反数(-b)



在这里首先我们看一下 通过 –s 0 参数(C-SVC模型)得到的最终的分类决策函数的表达式是怎样的?
这里如果有关于C-SVC模型不懂的地方,请看这个pdf文件:

libsvm_library.pdf
附件:
libsvm_library.pdf (316.82 KB, 下载次数: 155)

 

在由于我们使用的是RBF核函数(前面参数设置 –t 2),故这里的决策函数即为:



其中|| x-y ||是二范数距离 ;

这里面的

b就是-model.rho(一个标量数字);
b = -model.rho;
n代表支持向量的个数即 n = model.totalSV(一个标量数字);

对于每一个i:
wi =model.sv_coef(i); 支持向量的系数(一个标量数字)
xi = model.SVs(i,:) 支持向量(1*13的行向量)

x 是待预测标签的样本 (1*13的行向量)
gamma 就是 -g 参数



好的下面我们通过model提供的信息自己建立上面的决策函数如下:

  1. %% DecisionFunction
  2. function plabel = DecisionFunction(x,model)

  3. gamma = model.Parameters(4);
  4. RBF = @(u,v)( exp(-gamma.*sum( (u-v).^2) ) );

  5. len = length(model.sv_coef);
  6. y = 0;

  7. for i = 1:len
  8.     u = model.SVs(i,:);
  9.     y = y + model.sv_coef(i)*RBF(u,x);
  10. end
  11. b = -model.rho;
  12. y = y + b;

  13. if y >= 0
  14.     plabel = 1;
  15. else
  16.     plabel = -1;
  17. end
复制代码

有了这个决策函数,我们就可以自己预测相应样本的标签了:

  1. %%
  2. plable = zeros(270,1);
  3. for i = 1:270
  4.     x = data(i,:);
  5.     plabel(i,1) = DecisionFunction(x,model);
  6. end

  7. %% 验证自己通过决策函数预测的标签和svmpredict给出的标签相同
  8. flag = sum(plabel == PredictLabel)
  9. over = 1;
复制代码

最终可以看到 flag = 270 ,即自己建立的决策函数是正确的,可以得到和svmpredict得到的一样的样本的预测标签,事实上svmpredict底层大体也就是这样实现的。

最后我们来看一下,svmpredict得到的返回参数的意义都是什么

在下面这段代码中 :

  1. %%
  2. % 首先载入数据
  3. load heart_scale;
  4. data = heart_scale_inst;
  5. label = heart_scale_label;
  6. % 建立分类模型
  7. model = svmtrain(label,data,'-s 0 -t 2 -c 1.2 -g 2.8');
  8. model
  9. % 利用建立的模型看其在训练集合上的分类效果
  10. [PredictLabel,accuracy] = svmpredict(label,data,model);
  11. accuracy
复制代码

运行可以看到

  1. model =
  2.     Parameters: [5x1 double]
  3.       nr_class: 2
  4.        totalSV: 259
  5.            rho: 0.0514
  6.          Label: [2x1 double]
  7.          ProbA: []
  8.          ProbB: []
  9.            nSV: [2x1 double]
  10.        sv_coef: [259x1 double]
  11.            SVs: [259x13 double]
  12. Accuracy = 99.6296% (269/270) (classification)
  13. accuracy =
  14.    99.6296
  15.     0.0148
  16.     0.9851
复制代码

这里面要说一下返回参数accuracy的三个参数的意义。

重要的知识点:

返回参数accuracy从上到下依次的意义分别是:
分类准率(分类问题中用到的参数指标)
平均平方误差(MSE (mean squared error)) [回归问题中用到的参数指标]
平方相关系数(r2 (squared correlation coefficient))[回归问题中用到的参数指标]



其中mse 和r2的计算公式分别为:


写在后面的话,至此关于model中相应参数的一些意义,以及到底如果得到决策函数的表达式或者计算方式的就算是说的很明了了。

可能还有的同学会问,如何得到分类决策函数中的那个alpha系数【这个肯定会有人问】,还是再磨叽说一下吧:

上面的wi其实是alpha和支持向量的类别标签(1或-1的乘积),原始决策函数的表达式如下:
插图:


上面的yi是支持向量的类别标签(1或者-1),在libsvm中将yi和alpha的乘积放在一起用model.sv_coef(w)来承装。
都说到这份上,应该能明白了吗?

再说点废话:就是在关于SVM的学习中,我发现很多朋友都不主动思考和尝试,老是在问,这样很不好,这样很被动,上面这些也没有人教我,都是我自己思考出来,然后编程验证,如果出现不合理的地方就再继续思考,反正道理和书籍里面都有讲解,总能洞穿的啊。O(∩_∩)O•



Anyway,有关于SVM的问题还是可以一起探讨的,但您首先要独立思考一下下才好,您说是不是~


PS:预祝大家春节愉快

 

【3】Matlab中使用libsvm进行分类预测时的标签问题再次说明

最近看到论坛中有不少朋友在发帖提问关于libsvm使用时的标签设置问题,我记得我以前是给朋友回复个这个问题,现在就我自己的理解再次说明一下。
首先用svm(libsvm,lssvm、hssvm)等等进行分类预测,要进行三个步骤1、训练 2、测试 3、预测
1、训练——大家都知道,就是用训练数据集,不管你采用那种寻优方式,得到相对的最优参数,训练模型。

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

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

0

阅读 评论 收藏 禁止转载 喜欢 打印举报
  • 评论加载中,请稍候...
发评论

    发评论

    以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

      

    新浪BLOG意见反馈留言板 电话:4006900000 提示音后按1键(按当地市话标准计费) 欢迎批评指正

    新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 会员注册 | 产品答疑

    新浪公司 版权所有