SVM算法:
Support Vector Machine (SVM,支持向量机) 是一种监督学习方法,能最小化经验误差和最大化几何边缘,被称为最大间隔分类器,可以用于分类与回归分析。最早的相关论文是美国贝尔实验室的Corinna Cortes和Vladimir Vapnik等人于1995年在Machine Learning杂志上提出的Support Vector Networks,引用次数已超过12600次。
基本原理:SVM是一个机器学习的过程,在高维空间中寻找一个分类超平面,将不同类别的样本点分开,使不同类别的点之间的间隔最大,该分类起平面即为最大间隔超平面对应的分类器,称为最大间隔分类器。对于二分类问题,如下图所示:
关于SVM算法的一个详细介绍,请参考下面的连接,写的非常好:
http://www.voidcn.com/article/p-boprcxjk-dk.html
SVM优点:泛化错误率低,计算开销不大,结果易解释。
SVM缺点:对参数调节和核函数的选择敏感,原始分类器不加修改则仅适用于处理二分类问题。
SVM适用数据类型:数值型和标称型。
SVM算法实现工具有很多,包括SVMlight,LibSVM,还有matlab本身自带的svm工具包等。
SVM实现多分类
虽然SVM本质上是二分类的分类器,但是可以扩展成多分类的分类器,常见的方法有一对多(one-versus-rest)和一对一(one-versus-one)。
常见的方法有one-against-one和one-against-all两种。
a. 一对多法(one-versus-rest,简称OVR SVMs)。训练时依次把某个类别的样本归为一类,其他剩余的样本归为另一类,这样k个类别的样本就构造出了k个SVM。分类时将未知样本分类为具有最大分类函数值的那类。
假如我有四类要划分(也就是4个Label),他们是A、B、C、D。于是我在抽取训练集的时候,分别抽取A所对应的向量作为正集,B,C,D所对应的向量作为负集;B所对应的向量作为正集,A,C,D所对应的向量作为负集;C所对应的向量作为正集, A,B,D所对应的向量作为负集;D所对应的向量作为正集,A,B,C所对应的向量作为负集,对这四个训练集分别进行训练,然后的得到四个训练结果,在测试的时候,把对应的测试向量分别利用这四个训练结果文件进行测试,最后每个测试都有一个结果f1(x),f2(x),f3(x),f4(x).于是最终 的结果便是这四个值中最大的一个。
yode:这种方法有种缺陷,因为训练集是1:M,这种情况下存在biased.因而不是很实用.训练
b. 一对一法(one-versus-one,简称OVOSVMs或者pairwise)。其做法是在任意两类样本之间设计一个SVM,因此k个类别的样本就需要设计k(k-1)/2个SVM。当对一个未知样本进行分类时,最后得票最多的类别即为该未知样本的类别。Libsvm中的多类分类就是根据这个方法实现的。
还是假设有四类A,B,C,D四类。在训练的时候我选择A,B;A,C; A,D; B,C;B,D;C,D所对应的向量作为训练集,然后得到六个训练结果,在测试的时候,把对应的向量分别对六个结果进行测试,然后采取投票形式,最后得到一组结果。
投票是这样的.
A=B=C=D=0;
(A, B)-classifier 如果是A win,则A=A+1;otherwise,B=B+1;
(A,C)-classifer 如果是A win,则A=A+1;otherwise, C=C+1;
…
(C,D)-classifer 如果是A win,则C=C+1;otherwise,D=D+1;
The decision is the Max(A,B,C,D)
yode:这种方法虽然好,但是当类别很多的时候,model的个数是n*(n-1)/2,代价还是相当大的.
c. 层次支持向量机(H-SVMs)。层次分类法首先将所有类别分成两个子类,再将子类进一步划分成两个次级子类,如此循环,直到得到一个单独的类别为止。
对H-SVMs的详细说明可以参考论文《支持向量机在多类分类问题中的推广》(计算机工程与应用。2004)
d.DAG-SVMS是由Platt提出的决策导向的循环图DDAG导出的,是针对“一对一”SVMS存在误分、拒分现象提出的。算法在训练阶段与“一对一”相同,也要构 每两类间的分类面,既有n(n-1)/2个分类器。但在分类阶段,该方法将所有分类器构成一个两向有向环图,包括n(n-1)/2个节点和n个叶。其中每个节点为一个分类器,并与下一层的两个节点(或叶)相连。当对一个未知 本进行分类时,首先从顶部的 节点(包含两类)开始, 据 节点的分类结果用下一层的左节点或右节点继续分类,直到达到底层某个叶为止,该叶所表示类别即为未知 本的类别DAGSVM在训练上同OVOSVM,都需要训练n*(n-1)/2个分类器,但是在分类的时候借助有向环图的结构,可以只利用(n-1)个分类器就可以完成。 而效率上有提升。
初步体验libsvm(matlab下安装使用):
1. 下载libsvm:
在网站http://www.csie.ntu.edu.tw/~cjlin/libsvm/ 下载libsvm最新版本3.20,解压到相应目录(此处解压即安装)。我将其解压后放在D盘,即D:\MATLAB R20103a\toolbox\libsvm-320。
2. 设置matlab搜索工作目录:
打开matlab,file->Set Path->Add with Subfolders,然后定位到D:\MATLAB R20103a\toolbox\libsvm-320,注意这里最好定位到libsvm-3.20,而不要定位到libsvm-3.20子目录,点击Save后单击Close即可。
3. 编译
如果使用的是64位的操作的系统和Matlab,那么不需要进行编译步骤,因为自带软件包中windows文件夹已经包含有64位编译好的版本:libsvmread.mexw64、libsvmwrite.mexw64、svmtrain.mexw64、svmpredict.mexw64。否则,如果是32位系统则需要自己编译二进制文件。
4. 例子测试
注意到libsvm-3.20下有一个数据文件,名称为heart_scale。这是一个libsvm格式的数据文件。
可使用libsvmread函数将其转化为matlab格式,并用以下命令测试:
注意:这里读取数据时不可以用:load heart_scale.mat 命令,会出错,错误为:
Error using load
Number of columns on line 3 of ASCII file D:\matlab2013a\matlab2013a\toolbox\libsvm-3.20\heart_scale must be the same as previous lines.
原因是:有两个数据集,一个是C++的, 一个是matlab的。我们伴随libsvm库中下载的是C++数据,所以matlab中用load加载我们下载的heart_scale是会报错的。
但是我们可以用livsvmread命令将它转换成我们需要的matlab格式!
[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);
如果出现以下内容
:>> Untitled
*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)。就说明成功了。就可以在matlab中使用svm了。
关于LIBSVM在Matlab中的使用,可以参看软件包中matlab目录下的README文件,这里对里面内容做一个翻译和一些细节的讲解。
对libsvm的一些说明:
1. 训练
svmtrain函数用于对训练集的数据进行训练,得到训练好的模型。
model = svmtrain(training_label_vector, training_instance_matrix [,’libsvm_options’]);
model: 是训练得到的模型,是一个结构体(如果参数中用到-v,得到的就不是结构体,对于分类问题,得到的是交叉检验下的平均分类准确率;对于回归问题,得到的是均方误差)。
这个函数有三个参数,其中
-training_label_vector:训练样本的类标,如果有m个样本,就是m x 1的矩阵(类型必须为double)。这里可以是二分类和多分类,类的标识用(-1,1)、(1,2,3)或者其他任意用来表示不同的类别的数字表示,但要转成double类型。
-training_instance_matrix:训练样本的特征,如果有m个样本,每个样本特征是n维,则为m x n的矩阵(类型必须为double)。
-libsvm_options:训练的参数,在第3点详细介绍。
2. 预测
svmpredict函数用于对测试集的数据进行测试,还能对未知样本进行预测。
[predicted_label,accuracy,decision_values/prob_estimates]= svmpredict(testing_label_vector,testing_instance_matrix,model,[‘libsvm_options’]);
这个函数包括四个参数,其中:
-testing_label_vector: 测试样本的类标。
-testing_instance_matrix: 测试样本的特征矩阵。
-model: 即为libsvmtrain的返回值
-libsvm_options: 是需要设置的一系列参数。
-predicted_label: 表示预测得到的标签。
-accuracy/mse: 是一个3*1的列向量,其中第1个数字用于分类问题,表示分类准确率;后两个数字用于回归问题,第2个数字表示mse;第3个数字表示平方相关系数(也就是说,如果是分类问题的话,看第一个数字就可以了;回归的话,看后两个数字)。
decision_values表示决策值(一般好像不怎么用)。
3. 训练的参数
LIBSVM训练时options可以选择的参数很多,包括:Options:可用的选项即表示的涵义如下
**Examples of options: -s 0 -c 10 -t 1 -g 1 -r 1 -d 3
Classify a binary data with polynomial kernel (u’v+1)^3 and C = 10*
-s svm类型:SVM设置类型(默认0)
0 – C-SVC(C-support vector classification)
1 –nu-SVC(nu-support vector classification)
2 – 一类SVM(one-class SVM(distribution estimation))
3 – e -SVR(epsilon-SVR(epsilon-support vector regression))
4 – nu-SVR(nu-support vector regression)
*-t 核函数类型:核函数设置类型(默认2)*
0 – 线性:u’*v
1 – 多项式:(gamma*u’*v + coef0)^degree
2 – RBF函数:exp(-gamma*|u-v|^2)
3 –sigmoid:tanh(gamma*u’*v + coef0)
-d degree:核函数中的degree设置(默认3)
-g r(gama):核函数中的gamma函数设置(默认1/ k)
-r coef0:核函数中的coef0设置(默认0)
-c cost:设置C-SVC,e -SVR和nu-SVR的参数(惩罚系数 默认1)
-n nu:设置v-SVC,一类SVM和nu- SVR中的参数n(默认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类型中没有也不会产生影响,程序不会接受该参数;如果应有的参数设置不正确,参数将采用默认值。
一个写的很好的说明请参考:
http://www.cppblog.com/guijie/archive/2012/03/26/169034.html
4. 读取与保存文件 libsvmread函数可以读取以LIBSVM格式存储的数据文件。 [label_vector, instance_matrix] = libsvmread(‘data.txt’); 这个函数输入的是文件的名字,输出为样本的类标和对应的特征。 libsvmwrite函数可以把Matlab的矩阵存储称为LIBSVM格式的文件。 libsvmwrite(‘data.txt’, label_vector, instance_matrix] 这个函数有三个输入,分别为保存的文件名、样本的类标和对应的特征(必须为double类型的稀疏矩阵)。