大橙子网站建设,新征程启航
为企业提供网站建设、域名注册、服务器等服务
我先直观地阐述我对SVM的理解,这其中不会涉及数学公式,然后给出Python代码。
成都创新互联10多年成都企业网站定制服务;为您提供网站建设,网站制作,网页设计及高端网站定制服务,成都企业网站定制及推广,对成都隧道混凝土搅拌车等多个方面拥有多年的网站推广经验的网站建设公司。
SVM是一种二分类模型,处理的数据可以分为三类:
线性可分,通过硬间隔最大化,学习线性分类器
近似线性可分,通过软间隔最大化,学习线性分类器
线性不可分,通过核函数以及软间隔最大化,学习非线性分类器
线性分类器,在平面上对应直线;非线性分类器,在平面上对应曲线。
硬间隔对应于线性可分数据集,可以将所有样本正确分类,也正因为如此,受噪声样本影响很大,不推荐。
软间隔对应于通常情况下的数据集(近似线性可分或线性不可分),允许一些超平面附近的样本被错误分类,从而提升了泛化性能。
如下图:
实线是由硬间隔最大化得到的,预测能力显然不及由软间隔最大化得到的虚线。
对于线性不可分的数据集,如下图:
我们直观上觉得这时线性分类器,也就是直线,不能很好的分开红点和蓝点。
但是可以用一个介于红点与蓝点之间的类似圆的曲线将二者分开,如下图:
我们假设这个黄色的曲线就是圆,不妨设其方程为x^2+y^2=1,那么核函数是干什么的呢?
我们将x^2映射为X,y^2映射为Y,那么超平面变成了X+Y=1。
那么原空间的线性不可分问题,就变成了新空间的(近似)线性可分问题。
此时就可以运用处理(近似)线性可分问题的方法去解决线性不可分数据集的分类问题。
---------------------------------------------------------------------------------------------------------------------------
以上我用最简单的语言粗略地解释了SVM,没有用到任何数学知识。但是没有数学,就体会不到SVM的精髓。因此接下来我会用尽量简洁的语言叙述SVM的数学思想,如果没有看过SVM推导过程的朋友完全可以跳过下面这段。
对于求解(近似)线性可分问题:
由最大间隔法,得到凸二次规划问题,这类问题是有最优解的(理论上可以直接调用二次规划计算包,得出最优解)
我们得到以上凸优化问题的对偶问题,一是因为对偶问题更容易求解,二是引入核函数,推广到非线性问题。
求解对偶问题得到原始问题的解,进而确定分离超平面和分类决策函数。由于对偶问题里目标函数和分类决策函数只涉及实例与实例之间的内积,即xi,xj。我们引入核函数的概念。
拓展到求解线性不可分问题:
如之前的例子,对于线性不可分的数据集的任意两个实例:xi,xj。当我们取某个特定映射f之后,f(xi)与f(xj)在高维空间中线性可分,运用上述的求解(近似)线性可分问题的方法,我们看到目标函数和分类决策函数只涉及内积f(xi),f(xj)。由于高维空间中的内积计算非常复杂,我们可以引入核函数K(xi,xj)=f(xi),f(xj),因此内积问题变成了求函数值问题。最有趣的是,我们根本不需要知道映射f。精彩!
我不准备在这里放推导过程,因为已经有很多非常好的学习资料,如果有兴趣,可以看:CS229 Lecture notes
最后就是SMO算法求解SVM问题,有兴趣的话直接看作者论文:Sequential Minimal Optimization:A Fast Algorithm for Training Support Vector Machines
我直接给出代码:SMO+SVM
在线性可分数据集上运行结果:
图中标出了支持向量这个非常完美,支持向量都在超平面附近。
在线性不可分数据集上运行结果(200个样本):
核函数用了高斯核,取了不同的sigma
sigma=1,有189个支持向量,相当于用整个数据集进行分类。
sigma=10,有20个支持向量,边界曲线能较好的拟合数据集特点。
我们可以看到,当支持向量太少,可能会得到很差的决策边界。如果支持向量太多,就相当于每次都利用整个数据集进行分类,类似KNN。
一:libsvm包下载与使用:
LIBSVM是台湾大学林智仁(Lin Chih-Jen)副教授等开发设计的一个简单、易于使用和快速有效的SVM模式识别与回归的软件包,他不但提供了编译好的可在Windows系列系统的执行文件,还提供了源代码,方便改进.
把包解压在C盘之中,如:C:\libsvm-3.18
2.
因为要用libsvm自带的脚本grid.py和easy.py,需要去官网下载绘图工具gnuplot,解压到c盘
3.
进入c:\libsvm\tools目录下,用文本编辑器(记事本,edit都可以)修改grid.py和easy.py两个文件,找到其中关于gnuplot路径的那项,根据实际路径进行修改,并保存
4python与libsvm的连接(参考SVM学习笔记(2)LIBSVM在python下的使用 )
a.打开IDLE(python GUI),输入
import sys
sys.version
如果你的python是32位,将出现如下字符:
‘2.7.3 (default, Apr 10 2012, 23:31:26) [MSC v.1500 32 bit (Intel)]’
这个时候LIBSVM的python接口设置将非常简单。在libsvm-3.16文件夹下的windows文件夹中找到动态链接库libsvm.dll,将其添加到系统目录,如`C:\WINDOWS\system32\’,即可在python中使用libsvm
b.如果你是64位的请参考文献,请参考上述连接。
5.执行一个小例子
import os
os.chdir('C:\libsvm-3.18\python')#请根据实际路径修改
from svmutil import *
y, x = svm_read_problem('../heart_scale')#读取自带数据
m = svm_train(y[:200], x[:200], '-c 4')
p_label, p_acc, p_val = svm_predict(y[200:], x[200:], m)
##出现如下结果,应该是正确安装了
optimization finished, #iter = 257
nu = 0.351161
obj = -225.628984, rho = 0.636110
nSV = 91, nBSV = 49
Total nSV = 91
Accuracy = 84.2857% (59/70) (classification)
二几个简单的例子
从下载实验数据集。并且将数据集拷贝到C:\libsvm-3.18\windows下(因为之后我们需要利用该文件夹下的其他文件,这样比较方便,当然之后你用绝对地址也可以了)
建立一个py文件,写下如下代码:
例1:
import os
os.chdir('C:\libsvm-3.18\windows')#设定路径
from svmutil import *
y, x = svm_read_problem('train.1.txt')#读入训练数据
yt, xt = svm_read_problem('test.1.txt')#训练测试数据
m = svm_train(y, x )#训练
svm_predict(yt,xt,m)#测试
执行上述代码,精度为:Accuracy = 66.925% (2677/4000) (classification)
常用接口
svm_train() : train an SVM model#训练
svm_predict() : predict testing data#预测
svm_read_problem() : read the data from a LIBSVM-format file.#读取libsvm格式的数据
svm_load_model() : load a LIBSVM model.
svm_save_model() : save model to a file.
evaluations() : evaluate prediction results.
- Function: svm_train#三种训练写法
There are three ways to call svm_train()
model = svm_train(y, x [, 'training_options'])
model = svm_train(prob [, 'training_options'])
model = svm_train(prob, param)
有关参数的设置(read me 文件夹中有详细说明):
Usage: svm-train [options] training_set_file [model_file]
options:
-s svm_type : set type of SVM (default 0)#选择哪一种svm
0 -- C-SVC (multi-class classification)
1 -- nu-SVC (multi-class classification)
2 -- one-class SVM
3 -- epsilon-SVR (regression)
4 -- nu-SVR (regression)
-t kernel_type : set type of kernel function (default 2)#是否用kernel trick
0 -- linear: u'*v
1 -- polynomial: (gamma*u'*v + coef0)^degree
2 -- radial basis function: exp(-gamma*|u-v|^2)
3 -- sigmoid: tanh(gamma*u'*v + coef0)
4 -- precomputed kernel (kernel values in training_set_file)
-d degree : set degree in kernel function (default 3)
-g gamma : set gamma in kernel function (default 1/num_features)
-r coef0 : set coef0 in kernel function (default 0)
-c cost : set the parameter C of C-SVC, epsilon-SVR, and nu-SVR (default 1)
-n nu : set the parameter nu of nu-SVC, one-class SVM, and nu-SVR (default 0.5)
-p epsilon : set the epsilon in loss function of epsilon-SVR (default 0.1)
-m cachesize : set cache memory size in MB (default 100)
-e epsilon : set tolerance of termination criterion (default 0.001)
-h shrinking : whether to use the shrinking heuristics, 0 or 1 (default 1)
-b probability_estimates : whether to train a SVC or SVR model for probability estimates, 0 or 1 (default 0)
-wi weight : set the parameter C of class i to weight*C, for C-SVC (default 1)
-v n: n-fold cross validation mode
-q : quiet mode (no outputs)
三提高预测的准确率:
通过一定的过程,可以提高预测的准确率(在文献2中有详细介绍):
a.转换数据为libsvm可用形式.(可以通过下载的数据了解格式)
b.进行一个简单的尺度变换
c.利用RBF kernel,利用cross-validation来查找最佳的参数 C 和 r
d.利用最佳参数C 和 r ,来训练整个数据集
e.测试
再看例子1:
1.进入cmd模式下,输入如下代码,将现有数据进行适度变换,生成变换后的数据文件train.1.scale.txt
参数说明:
-l 变换后的下限
-u 变换后的上限
-s 参考上文
2执行以下代码
import os
os.chdir('C:\libsvm-3.18\windows')#设定路径
from svmutil import *
y, x = svm_read_problem('train.1.scale.txt')#读入训练数据
yt, xt = svm_read_problem('test.1.scale.txt')#训练测试数据
m = svm_train(y, x )#训练
svm_predict(yt,xt,m)#测试
精确度为Accuracy = 95.6% (3824/4000) (classification)。
可见我们只是做了简单的尺度变换后,预测的正确率大大提升了。
3通过选择最优参数,再次提高预测的准确率:(需要把tools文件下的grid.py拷贝到'C:\libsvm-3.18\windows'下)
import os
os.chdir('C:\libsvm-3.18\windows')#设定路径
from svmutil import *
from grid import *
rate, param = find_parameters('train.1.scale.txt', '-log2c -3,3,1 -log2g -3,3,1')
y, x = svm_read_problem('train.1.scale.txt')#读入训练数据
yt, xt = svm_read_problem('test.1.scale.txt')#训练测试数据
m = svm_train(y, x ,'-c 2 -g 4')#训练
p_label,p_acc,p_vals=svm_predict(yt,xt,m)#测试
执行上面的程序,find_parmaters函数,可以找到对应训练数据较好的参数。后面的log2c,log2g分别设置C和r的搜索范围。搜索机制是以2为底指数搜索,如 –log2c –3 , 3,1 就是参数C,从2^-3,2^-2,2^-1…搜索到2^3.
搜索到较好参数后,在训练的时候加上参数的设置。
另外,读者可以自己试试数据集2,3.
毋庸置疑,LibSVM是台湾牛人为世界机器学习的卓越贡献之一。一般都是基于Matlab的,其实LibSVM也可以用Python跑。
第一步,确定本机Python的版本:
32位的最易配置,哈哈,我的机器就是这么的古董。64位的童鞋请Google。
第二步,到官网,来下载LibSVM软件包,我选择的是zip包。
第三步,将zip包解压到一个特定位置,我放到了C:盘根目录,当然也可以放到program files中。
第四步,就可以测试一下LibSVM是否可用了,打开Python IDE,输入以下代码:
能够看到输出,84%的分类准确性。
第五步,使用我的个人数据
libsvm的数据格式如下:
第一列代表标签,第二列是第一个特征值,第三列是第二个特征值。所以,先要把数据按规定格式整理好。然后开始训练。
import os
import sys
os.chdir('C:\libsvm-3.17\python')
from svmutil import *
y, x = svm_read_problem('../lkagain.txt')
m = svm_train(y[:275], x[:275], '-c 5')
y, x = svm_read_problem('../lk2.txt')
p_label, p_acc, p_val = svm_predict(y[0:], x[0:], m)
print p_label
print p_acc
print p_val
第六步,Python接口
在libsvm-3.16的python文件夹下主要包括了两个文件svm.py和svmutil.py。
svmutil.py接口主要包括了high-level的函数,这些函数的使用和LIBSVM的MATLAB接口大体类似
svmutil中主要包含了以下几个函数:
svm_train() : train an SVM model
svm_predict() : predict testing data
svm_read_problem() : read the data from a LIBSVM-format file.
svm_load_model() : load a LIBSVM model.
svm_save_model() : save model to a file.
evaluations() : evaluate prediction results.
支持向量机SVM(Support Vector Machine)是有监督的分类预测模型,本篇文章使用机器学习库scikit-learn中的手写数字数据集介绍使用Python对SVM模型进行训练并对手写数字进行识别的过程。
准备工作
手写数字识别的原理是将数字的图片分割为8X8的灰度值矩阵,将这64个灰度值作为每个数字的训练集对模型进行训练。手写数字所对应的真实数字作为分类结果。在机器学习sklearn库中已经包含了不同数字的8X8灰度值矩阵,因此我们首先导入sklearn库自带的datasets数据集。然后是交叉验证库,SVM分类算法库,绘制图表库等。
12345678910
#导入自带数据集from sklearn import datasets#导入交叉验证库from sklearn import cross_validation#导入SVM分类算法库from sklearn import svm#导入图表库import matplotlib.pyplot as plt#生成预测结果准确率的混淆矩阵from sklearn import metrics
读取并查看数字矩阵
从sklearn库自带的datasets数据集中读取数字的8X8矩阵信息并赋值给digits。
12
#读取自带数据集并赋值给digitsdigits = datasets.load_digits()
查看其中的数字9可以发现,手写的数字9以64个灰度值保存。从下面的8×8矩阵中很难看出这是数字9。
12
#查看数据集中数字9的矩阵digits.data[9]
以灰度值的方式输出手写数字9的图像,可以看出个大概轮廓。这就是经过切割并以灰度保存的手写数字9。它所对应的64个灰度值就是模型的训练集,而真实的数字9是目标分类。我们的模型所要做的就是在已知64个灰度值与每个数字对应关系的情况下,通过对模型进行训练来对新的手写数字对应的真实数字进行分类。
1234
#绘制图表查看数据集中数字9的图像plt.imshow(digits.images[9], cmap=plt.cm.gray_r, interpolation='nearest')plt.title('digits.target[9]')plt.show()
设置模型的特征X和预测目标Y
查看数据集中的分类目标,可以看到一共有10个分类,分布为0-9。我们将这个分类目标赋值给Y,作为模型的预测目标。
12
#数据集中的目标分类digits.target
12
#将数据集中的目标赋给YY=digits.target
手写数字的64个灰度值作为特征赋值给X,这里需要说明的是64个灰度值是以8×8矩阵的形式保持的,因此我们需要使用reshape函数重新调整矩阵的行列数。这里也就是将8×8的两维数据转换为64×1的一维数据。
123
#使用reshape函数对矩阵进行转换,并赋值给Xn_samples = len(digits.images)X = digits.images.reshape((n_samples, 64))
查看特征值X和预测目标Y的行数,共有1797行,也就是说数据集中共有1797个手写数字的图像,64列是经过我们转化后的灰度值。
12
#查看X和Y的行数X.shape,Y.shape
将数据分割为训练集和测试集
将1797个手写数字的灰度值采用随机抽样的方法分割为训练集和测试集,其中训练集为60%,测试集为40%。
12
#随机抽取生成训练集和测试集,其中训练集的比例为60%,测试集40%X_train, X_test, y_train, y_test = cross_validation.train_test_split(X, Y, test_size=0.4, random_state=0)
查看分割后的测试集数据,共有1078条数据。这些数据将用来训练SVM模型。
12
#查看训练集的行数X_train.shape,y_train.shape
对SVM模型进行训练
将训练集数据X_train和y_train代入到SVM模型中,对模型进行训练。下面是具体的代码和结果。
12
#生成SVM分类模型clf = svm.SVC(gamma=0.001)
12
#使用训练集对svm分类模型进行训练clf.fit(X_train, y_train)
使用测试集测对模型进行测试
使用测试集数据X_test和y_test对训练后的SVM模型进行检验,模型对手写数字分类的准确率为99.3%。这是非常高的准确率。那么是否真的这么靠谱吗?下面我们来单独测试下。
12
#使用测试集衡量分类模型准确率clf.score(X_test, y_test)
我们使用测试集的特征X,也就是每个手写数字的64个灰度值代入到模型中,让SVM模型进行分类。
12
#对测试集数据进行预测predicted=clf.predict(X_test)
然后查看前20个手写数字的分类结果,也就是手写数字所对应的真实数字。下面是具体的分类结果。
12
#查看前20个测试集的预测结果predicted[:20]
再查看训练集中前20个分类结果,也就是真实数字的情况,并将之前的分类结果与测试集的真实结果进行对比。
12
#查看测试集中的真实结果expected=y_test
以下是测试集中前20个真实数字的结果,与前面SVM模型的分类结果对比,前20个结果是一致的。
12
#查看测试集中前20个真实结果expected[:20]
使用混淆矩阵来看下SVM模型对所有测试集数据的预测与真实结果的准确率情况,下面是一个10X10的矩阵,左上角第一行第一个数字60表示实际为0,SVM模型也预测为0的个数,第一行第二个数字表示实际为0,SVM模型预测为1的数字。第二行第二个数字73表示实际为1,SVM模型也预测为1的个数。
12
#生成准确率的混淆矩阵(Confusion matrix)metrics.confusion_matrix(expected, predicted)
从混淆矩阵中可以看到,大部分的数字SVM的分类和预测都是正确的,但也有个别的数字分类错误,例如真实的数字2,SVM模型有一次错误的分类为1,还有一次错误分类为7。