标签:
这篇文章详细地介绍了SVM背后的原理,它为什么是大间距分类器?分类器的参数C为什么影响着分类器的行为?核函数背后采用了什么样的技术,看过这篇文章以后,相信你能很好地理解这些问题。最后,我用scikit-learn来分别来拟合线性和非线性的SVM,让大家对SVM分类器有更加深刻的理解。
相信所有用过SVM的人都知道它是一个大间距分类器。但是,它的原理是什么?它为什么可以最大化决策边界与样本之间的距离?下面我将一步一步的揭开它神秘的面纱。
从上图中我们可以看到,SVM会最大化间距,也就是那个
这里我给你一个例子,应用一下这个公式,让你更好地理解它。我相信大家很早就知道
我们可以把
PS:你可以把这两个式子写成
如果你想要了解得到
http://www.svm-tutorial.com/2014/11/svm-understanding-math-part-1/
http://www.svm-tutorial.com/2014/11/svm-understanding-math-part-2/
http://www.svm-tutorial.com/2015/06/svm-understanding-math-part-3/
现在,我们已经得到了间距
上面公式中的
现在,我们可以总结一下SVM最优化目标了:
看到此情此景,我们是否想起了什么呢?Yeah,就是拉格朗日乘子(Lagrangemultiplier),它可以搞定这个有约束的最优化条件。
为了让大家更好地理解拉格朗日乘子法,现在我用一个实例一步一步地来讲解这个知识点。
假设,我现在有个想要最大化的函数为:
现在,我们有个约束为:
从上图我们可以看出,当
函数
因此,通过上面我们得出的结论,可以求解我们最初提出的带约束的最优化问题。解题过程如下:
我们上面的2个函数可写成如下形式:
现在,我们分别求出2个函数的梯度如下:f(x,y)=2x+yg(x,y)=x2+y2?1
?f(x,y)=???????x(2x+y)??y(2x+y)?????=[21]
?g(x,y)=???????x(x2+y2?1)??y(x2+y2?1)?????=[2x2y]
[21]=λ0[2x02y0]
下面的过程我就不写了,3个方程,3个未知数你一定可以解出结果。
下面我要引入拉格朗日函数(Lagrangian function),它以一种更为紧凑的方式来描述我上面的过程,它的公式如下:
针对我上面提出的例子来说,其中的
现在,我要对拉格朗日函数的三个变量分别求导,看看会有什么奇迹发生!!!
现在,我们让上面的三个等式分别等于0,得到如下结果:
如果我们把上面的第2个等式和第3个等式合在一起,就得到了
现在,你已经体会到拉格朗日函数的伟大了吧。它以一种更为紧凑的方式诠释了我们那个例子中的条件。
现在,你已经了解了拉格朗日函数这个强大的数学工具了。现在我们就用这个强大的数学工具来解决SVM的最优化问题吧。
在解决这个问题之前,大家可能已经注意到了两个问题。1、因为我们有很多个训练样本,所以SVM的最优化问题有很多约束?2、我们那个例子中的约束条件是等式,而这个约束条件是不等式?
其实解决这2个问题很简单,只要稍微对拉格朗日函数做一些调整就行了。改动如下:
1、只要我们在每个约束前面都乖上一个
2、拉格朗日乘子(Lagrange multiplier),也就是
我们的优化目标如下:
拉格朗日函数如下:
现在,我们要把拉格朗日函数对
现在,我把上式中的
提示:对于原式中的
现在,我们涉及到了对偶问题(Dual Problem)。如果我们求得了
如果你不明白什么是对偶问题也是没什么关系的。你只要知道我们最初的优化问题称为primal problem,而上面我们代入
这是一个二次规划(quadratic programming)问题,因此我们总能找到使全局最大化的
先让我们看看下面这幅图片,我对照这个图片给大家解释一些概念。
上图中的
上图中,非0
对于一些非线性可分的数据集,我们可以用松弛变量这个技巧来解决问题,你可以把它看成是放宽约束,允许一些并没有正确分类的样本存在。如下图:
上图中的
明确了优化目标和约束条件,像上面的例子一样,用拉格朗日函数就能解决这个问题了,这我就不再重复这个过程了。
相信使用SVM分类器的朋友都知道优化目标中的C吧,它完全可以影响分类器的行为。既然已经学到了现在,我们就再多介绍一下这个C吧!!!
如果可以用一句话概括C的话,它就是权衡误差和间距的参数。如果你的C很小,它会给你一个大间距,但是作为牺牲,我们必须要忽视一些错误分类的样本;反之,如果你的C很大,你会尽量正确地分类样本,但是这样做的代价会导致你有很小的间距。如下图:
你现在可能会问,C大一点好,还是小一点好呢?实际上,这没有什么标准的答案,这完全取决于你的训练集是什么样的。看看下面的两个例子:
通过我们上面的最小化函数我们也可以看出:如果C值很大,我们的松弛变量
因此,在SVM算法的训练上,我们可以通过减小C值来避免overfitting的发生。
对于一些非线性可分的训练集,上面我引入了slack变量来解决这个问题。但是,对于一些训练集来说,用slack变量并不是一个好的选择。看看下图:
无论我们怎么调节参数C都不可能拟合出这样一个决策边界,因此slack变量不能很好地解决这个问题。Oh Yeah,核函数闪亮登场!!!下面,让我给大家一下核函数的本质。
现在,如果我把训练集的数据映射到高维空间看看会发生什么的结果呢?如下图:
Oh Yeah,现在线性可分了。但是,这样的方法也伴随着一个问题的出现,为了使我们的训练集线性可分,我们需要引入更多的特征,计算更多的权重系数,甚至这样的特征空间有可能是无限维的,这样的结果会导致我们无法计算。但是一个kernel技巧可以解决这样的问题,下面,让我们看看它是怎么办到的吧!
现在,你回去看看我们那个dual problem的最大化目标函数,训练集中的数据样本仅仅是计算两点之间的内积(
我们最初样本的输入空间为:
用映射函数
现在,我们随机挑选出2个映射以后的样本做内积:
最后,如果我们定义一个核函数K(如下),我们就不需要显示地映射样本数据:
当然了,核函数有很多种,相信用过SVM的人都知道有什么样的核函数,这里我就不去介绍不同的核函数了。
假定你现在选择了一个合适的核函数
现在,我挑选出一个测试集中的样本
在实际应用中,我建议大家先试试低阶多项式核或者RBF核,这两个核都 是很好的选择。
把文章读到现在的朋友,我相信你已经对SVM有个很深入的了解。接下来,让我们拿起手中理论的武器征战实际中的问题吧。
如果你对scikit-learn和Iris数据集不算很了解,先看看这篇文章吧:http://blog.csdn.net/xlinsist/article/details/51289825
下面,我就直接上代码了!!!
from sklearn import datasets
import numpy as np
from sklearn.cross_validation import train_test_split
iris = datasets.load_iris() # 由于Iris是很有名的数据集,scikit-learn已经原生自带了。
X = iris.data[:, [2, 3]]
y = iris.target # 标签已经转换成0,1,2了
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0) # 为了看模型在没有见过数据集上的表现,随机拿出数据集中30%的部分做测试
# 为了追求机器学习和最优化算法的最佳性能,我们将特征缩放
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
sc.fit(X_train) # 估算每个特征的平均值和标准差
sc.mean_ # 查看特征的平均值,由于Iris我们只用了两个特征,所以结果是array([ 3.82857143, 1.22666667])
sc.scale_ # 查看特征的标准差,这个结果是array([ 1.79595918, 0.77769705])
X_train_std = sc.transform(X_train)
# 注意:这里我们要用同样的参数来标准化测试集,使得测试集和训练集之间有可比性
X_test_std = sc.transform(X_test)
X_combined_std = np.vstack((X_train_std, X_test_std))
y_combined = np.hstack((y_train, y_test))
# 导入SVC
from sklearn.svm import SVC
svm = SVC(kernel=‘linear‘, C=1.0, random_state=0) # 用线性核,你也可以通过kernel参数指定其它的核。
svm.fit(X_train_std, y_train)
# 打印决策边界,这个函数是我自己写的,如果你想要的话,我发给你
plot_decision_regions(X_combined_std, y_combined, classifier=svm, test_idx=range(105,150))
plt.xlabel(‘petal length [standardized]‘)
plt.ylabel(‘petal width [standardized]‘)
plt.legend(loc=‘upper left‘)
plt.show()
从上图中我们看到我们的线性SVM分类器干的还算不错。下图是不同的核分类的效果,链接中有详细的代码我就不在这重复了。
http://scikit-learn.org/stable/auto_examples/svm/plot_iris.html
SVM分类器中还有很多有用的参数,具体请参考官方文档:http://scikit-learn.org/stable/modules/svm.html#svm
上面我已经介绍了核的概念,它的基本思想就是:通过映射函数
在用scikit-learn实现算法之前,我先介绍一下高斯核的定义,它的公式如下:
上面的
svm = SVC(kernel=‘rbf‘, random_state=0, gamma=x, C=1.0) # 令gamma参数中的x分别等于0.2和100.0
svm.fit(X_train_std, y_train) # 这两个参数和上面代码中的训练集一样
plot_decision_regions(X_combined_std, y_combined, classifier=svm, test_idx=range(105,150))
plt.xlabel(‘petal length [standardized]‘)
plt.ylabel(‘petal width [standardized]‘)
plt.legend(loc=‘upper left‘)
plt.show()
用上面的两个
我们看到当gamma = 100.0时,它非常好地拟合了训练数据,但是它在测试集上的表现会非常糟糕,因此产生了过拟合现象。
有时候,我们的数据集太大而不能全部放到计算机内存中,因此scikit-learn提供了一个解决方案,SGDClassifier中的partial_fit方法允许你在线学习(或minibatch learning),这个就是在随机梯度下降中的意思。
svm = SGDClassifier(loss=‘hinge‘) # 指定为线性SVM
这个类中有很多方法和参数,具体参考官方文档:http://scikit-learn.org/stable/modules/generated/sklearn.linear_model.SGDClassifier.html
这篇文章大约花费了我3天时间写的,为了让大家能更好地且准确地理解文章,其中有不确定的概念我参考了很多的资料才写在文章中,但谁能无错,希望有不好的地方大家能给指出来,小编在此谢过了。
http://www.cise.ufl.edu/class/cis4930sp11dtm/notes/intro_svm_new.pdf
http://pages.cs.wisc.edu/~jerryzhu/cs540/handouts/svm.pdf
SVM详解(包含它的参数C为什么影响着分类器行为)-scikit-learn拟合线性和非线性的SVM
标签:
原文地址:http://blog.csdn.net/xlinsist/article/details/51311755