支持向量机(Support Vector Machine, SVM)是一类按监督学习(supervised learning)方式对数据进行二元分类的广义线性分类器(generalized linear classifier)
支持向量机(Support Vector Machine)。支持向量机既可以解决分类问题,也可以解决回归问题。
在之前的逻辑回归中,对于数据的分类,我们可以找到一条决策边界对数据进行分类
但其实这个决策边界并不唯一,可以看到下面两条线都可以作为决策边界,这种问题一般称作不适定问题。
在逻辑回归中我们解决不适定问题的方法主要是通过概率函数-sgmoid函数,根据这个概率函数进行建模,形成损失函数,通过最小化损失函数的方式,形成一条决策边界。
对于以下这个决策边界来说,很显然这个决策边界是可以将目前已有的样本点很好的分类,但是他的泛化能力其实并不好。对于没有看见的样本是不是一个好的决策边界我们并不知道。
下面我们增加一个数据样本点
根据这个新增的数据样本点来说,根据我们当前的决策边界来看,这个数据样本点应该是被划分到蓝色的分类当中。但是我们从主观来分析,其实这个样本点将它分到红色样本点来说,是更加合理的。
也就是说我们通过之前的样本点求出的决策边界泛化能力不够好,早上上述情况的原因是我们的决策边界剧烈红色的分类点距离太近了,这就导致当我们增加样本的时候,很多距离红色样本点很近的样本本身应该被分类成红色样本的一类,却被误分到了蓝色的一类。
针对上面的情况,当我们的决策边界如下图所示的时候,他的泛化能力应该是比较好的
在上图,距离决策边界最近的点有三个,我们领这三个点距离决策边界尽可能的远,换句话说,我们期望决策边界既离红色的点尽可能远,又离蓝色的点尽可能远,同时还希望它能很好的分别红色和蓝色两个类别的数据点,于是我们得到了上面的决策边界 。
我们找到了一条决策边界,不仅能将现有的样本点进行很好的分类,同时还考虑到了未来,它期望这条决策边界的泛化能力尽可能的好
这里,SVM的思想对于对未来的泛化能力尽可能好的这种考量没有记希望于数据的预处理阶段,或者找到模型后进行正则化的方式,而是将对泛化能力的考量放在了算法内部,也就是我们要找到一条决策边界,这个决策边界离分类样本都要尽可能的远,我们直观的来看的话,这样的泛化能力就是更好的。
上面说到我们期望划分的这条决策边界离两个类比的数据样本点都尽可能远,意思就是:在这两个类别中,离决策边界最近的那些点,到决策边界的距离尽可能的远。
这些特殊的数据点(离决策边界最近的数据样本点)又定义出了两根直线。
这两条直线和我们通过svm得到的决策边界是平行的,这两根直线相当于定义了一个区域,在这两根直线之间将不会有任何的数据点,而我们svm得到最终的决策边界就相当于我们这个区域最中间的那个线,在这两根线上的数据样本点则成为支撑向量。换句话说,我们的支撑向量定义了一个区域,而最终最优的决策边界是根据这个区域所决定的(位于这个区域最中间的那根线),或者说我们最终找到的这个最优的决策边界是由支撑向量定义的
支撑向量是整个算法中非常重要的元素,整个算法也是用支撑向量命名的,这也是SVM的由来。
在下图中,三根直线间的距离我们记为d(蓝色的样本点距离决策边界最近的点到决策边界的距离与红色的点距离决策边界最近的点到决策边界的距离是相等的,都是d),而界定决策边界最外边的两条直线的距离我们记为margin,那么则有margin=2d,而我们svm要做的事情就是最大化margin。
到目前为止,以上所说的都是解决线性可分(存在一根直线或者对于高维空间而言,存在一个超平面,可以将上述的数据样本点划分)的问题。这样的算法通常称之为Hard Margin SVM,我们切实的找到了一个决策边界,这个决策边界将我们的样本点进行了划分,同时最大化了margin的值。
但是在真实情况下,我们的很多数据是线性不可分的,我们可以改进SVM,得到Soft Margin SVM,对线性不可分的数据进行划分。
ps:接下来做具体的实现,提一嘴,我们将把这个支撑向量机的思想转换为一个最优化的问题,也就是参数学习算法的套路——把解决问题的思想转换成最优化的问题,然后最优化目标函数
在之前的分析说,我们最后要做的是求得margin的最大值,由于margin=2d,换句话说,我们要最大化d,也可以求解这个问题。
这里的w(weight,权重)表示真实的特征的系数,b代表截距
对于x向量,如果有n个特征的话,那么theta中有n+1个元素(theta0是截距),w向量中有n个元素(w的n个元素和b一个元素组合起来构成了theta向量),这里采用把系数和截距分开的原因是因为,在一维平面中求距离的时候,分母的A2 +B2 都是系数,与截距C无关。扩展到n维空间后,我们更方便得到距离公式
我们假设最终的决策边界是wT +b=0,离决策边界最近的点到决策边界的距离为d,换句话说,所有样本点到决策边界的距离是大于等于d的。于是我们可以得到下面的公式
我们对于这两类来讲,一类称为1,另一类称为-1(为了方便后续计算,具体取值是不影响了,只要取得值能把这两类区分开来即可,例如我们之前在逻辑回归当中一类取1,一类取0)
上述的公司拆掉绝对值后可以按照分类(1,-1两类),写成两个式子
(1)对于属于1的这一类的样本点,相当于对于第i个样本对于的分类是1的话,相应的点到决策边界的距离的式子要大于等于d
(2)对于属于-1的这一类的样本点,相当于对于第i个样本对于的分类是-1的话,相应的点到决策边界的距离的式子要小于等于-d
将上述两个式子进行变形(同时除以d)
在分母当中,w是一个一维向量,但是w的模是一个标量,d也是一个标量,那么整个分母都是一个标量。那么以上的式子,对于分子来说,我们可以把w向量中的每一个元素都除以这个标量,对于b这个截距也可以除以这个标量。这样我们可以进一步化简这个式子。
对应我们可以得到决策边界旁边的两根直线的方程
这里的wd与w,bd与b直接的关系只相差一个||w||d,决策边界的方程是wT +b=0,所以针对决策边界的方程,我们也可以同时除以一个||w||d,统一化三个方程的表示。最后整理出来,所有的方程都可以通过wd 和bd 表示
最后,我们再次整体替换一次,方便计算与书写(此时的w和b与一开始推导的w和b从理论上已经不是一个东西了,他们相差一个||w||d的系数)。
对于右侧两个不等式,我们类比逻辑回归的方式,将两个不等式融合成一个不等式
带入正例1和负例-1,不等式依旧成立,这样我们把上述两个式子表示成了一个式子。
回到最初的问题,我们要最大化d,根据前面已经提到的公司,我们最大化d,即最大化下面的式子
对于支撑向量而言(在决策边界两边直线上的样本点),|wT +b|的值一定是1,那么我们进一步转化求解,就是求
接下来进一步转化成
通常我们在求解的时候,我们写成
这样的原因是方便我们求导。
所以加上限定条件,整理一下上面的式子
求解
在之前学习过程中求解最优化问题,其实都是全局最优化问题,是没有限定条件的(全局求导,导数等于0,求出极值点,相应极值点就是取最大值或者最小值的位置)。但是在这个问题当中,是有条件的最优化问题,这个求解方式要采用拉普拉斯算子(拉格朗日乘子算法)。
在Hard Margin SVM中,我们可以求出具体的w、b进而求出决策边界方程。
但是如果我们将右下方的一个蓝色的样本点移到了上方,那么我们求出来的决策边界很有可能是下图
对于这样的一条直线,尽管他可以将我们的训练数据集的数据很好的分类了,但是我们会对其泛化能力产生怀疑,这个决策边界显然受到了这一个蓝色点的影响,但很有可能这个蓝色的点是一个错误的点或者是一个极度特殊的点,这个点并不能代表一般情况,往往如下图所示才是一个更好的决策边界
这个决策边界虽然将其中的一个蓝色的点进行了错误的分类,但很有可能在真实情况下进行实际预测的时候,这个决策边界比之前将所有训练样本集都进行正确分类的决策边界的效果更好(泛化能力更好),对于这个机制来说,SVM要有一定的容错能力,在一些情况下他可以考虑到我们将一些点进行错误的分类,最终达到的结果希望泛化能力尽可能的高。
接下来如果我们继续移动这个蓝色的样本点
此时我们的数据已经是线性不可分的了,没有任何一条直线能够正确的将现在的数据分成两类,在这种情况下Hard Margin SVM算法已经不是泛化能力强不强的问题了,而是根本无法应用,我们根本不能得到结果,所以我们需要作出一个拥有容错能力的SVM,这种SVM就是Soft Margin SVM。
对比Hard Margin SVM
宽松量ξi
我们此时增加一个宽松量ξi,把条件中的1改成1-ξi
我们允许有一些数据点在最外侧的直线与虚线的范围内,这也就打破了我们的Hard Margin SVM的限制,也就是说可以犯一些错误,这里的条件也要增加宽松量ξi大于0的限制
还有一点要注意,对于我们的宽松量ξi 不是一个固定的数值,而是对于每一个样本数据i都有一个相应的ξi ,对于每一个数据点我们都要求出一个相应的容错空间。
对于这个宽松量ξ,我们希望他大于零,但是同时也希望这个容错空间不能太大,所以我们在求最小值的时候加上一项 ξi 的求和
这样一来我们最小化的式子同时顾及了前半部分Hard Margin SVM最优化的内容,实现了SVM的思想,同时在后半部分算上了容错空间,使我们的算法可以容忍一定的错误,但是这个容忍的程度要尽可能的小,这二者直接应该取得一个平衡
但是对于上述式子最小化的部分,这样写相当于式子的两部分占比是1:1的,他们的占比是同样重要的,而实际上他们的占比不一定一样,同正则化类似,所以我们可以进一步对这个式子进行改写,在对ξi 的求和前加上一个超参数C来平衡这两部分所占的比例,如果C=1,则两个部分占比相同;如果C在(0,1),那么整个式子将以优化前面一部分为主;C>1的话,整个式子优化的目标主要是后半部分,我们可以通过网格搜索这样的策略,找到我们所需要的数据集最好的C
另外一点要注意的是,通常我们这样来写,又称为在Soft Margin SVM中加入了L1正则的方式,换句话说我们可以理解成我们加入的这个ξ本身是一个正则化项,它在避免我们训练出来的模型向一个极端方向发展。(其实在线性回归或者逻辑回归当中加入正则化项的本质也是让我们的模型针对训练数据集有更高的容错能力,当我们有这种容错能力之后,使得我们模型本身对训练数据集中的极端数据点不那么敏感,用这种方式提高泛化能力,当我们面对未知的数据时,预测能力可以有所提升)。以上用的是L1正则,与此相关的还有L2正则
区别只在于对于后面对ξi 求和的部分变成了对ξi 2 求和(在线性回归当中,L1正则是对|ξi|求和,这里的ξi限制了大于零,所以直接对ξi求和即可)。
其实这一块在表达形式上,和线性回归或者逻辑回归的正则化表达式的形式是一样的,只不过在具体的意思上ξi 表示的几何意义有区别。
超参数c
另外关于超参数C这一块,在SVM当中这个超参数C是放在正则项前面的,但是对于线性回归来说,超参数C是放在MSE损失函数前面的,虽然这个C所放的位置变了,但是这个表义是一致的,都是C越大,相应的容错空间越小(在SVM当中,如果C取正无穷,则意味着我们逼迫着ξi都必须等于0,那么此时Soft Margin SVM就变成了Hard Margin SVM,也就是容错空间越小。在线性回归当中,超参数C是在MSE前面的,C越大,也就是逼迫着我们更多的顾忌MSE部分,而不去顾忌正则化的部分,也是容错空间越小。相应的C越小,意味着我们可以有更大的容错空间)。
C的位置不同,但是表义一致
求解
同理这个求解过程要用到拉格朗日乘子算法,这一块直接上结果,后面在代码用sklearn是给我封装好了的,我们直接调用即可
核函数(KernelFunction)
回忆一下SVM的本质其实就是求解最优化的过程,是一个有条件的最优化问题。
为了求解的方便,会将上述问题进行一个转换(之前直接把求解结果放在了上面)(转变过程太复杂了,略去)
转变后,上面的式子xixj表示对样本数据集当中任意两个向量都要做一个点乘,如果想使用多项式特征的话,我们之前的方式是对于本来的样本数据xi添加一个多项式特征,变成xi‘,对另一个样本数据xj添加一个多项式特征,变成xj‘,我们相当于引入了两个新的特征
对于核函数来说,我们的想法是有没有可能先不将xi和xj两个特征转变成xi‘和xj‘,在做点乘的操作,而是设置一个函数,这个函数传入两个参数xi和xj,直接计算出xi点乘xj
如果有这样的函数K的话,上面的式子可以进一步转化
这个K函数取不同的函数就相当于现在原始的样本上进行了一个变化,之后对变化后的样本进行点乘的操作,K函数直接算出了这个过程的结果,这里的K函数就是核函数。
这里只是一个简单的例子,引入核函数优点主要在于比较复杂的变形,使用核函数的话可以减少计算量和减少了存储空间(一般对原来的样本进行变形,通常是把低维的样本变成更加高维的数据,存储高维的数据会花更多的空间,但是使用核函数的话就不用管我们把原来的样本变成了什么样子,因为我们不需要存储变化后的结果,直接使用核函数的方式可以直接计算出点乘之后的结果)。
另外核函数本身不是SVM算法特有的技巧,事实上,只要算法转换成最优化的问题,在求解这个最优化的问题当中存在xi点乘xj 这样的式子或者类似这样的式子,我们都可以应用核函数的技巧,只是核函数更多的在SVM中使用
(1)多项式核函数
为了数据计算方便,只展示了二次多项式的核函数(其实可以拓展到任意次项)
首先把核函数右侧展开
可以理解成原来的x先变成了x’
y也可以根据相应的规则变成对应的y’
然后将变化后的x’,y’带入计算,发现x’,y’点乘的结果就是这个核函数的运算结果
这里的x’其实就相当于对原来的式子添加上二次项之后得到的结果。
所以这里我们其实可以不用把添加了二次项后的x’,y’表示出来,然后在带入计算展开后这么复杂的式子。
我们可以直接用原来的样本数据x点乘y加上一之后平方一下,和我们先把数据变成x’,y’再进行点乘的结果是一致的
多项式核函数不仅能制造二次方的多项式特征,而是对任意degree都能计算多项式特征,所以这里的多项式核函数表示成以下的方式
核函数的本质其实就是替换原本的x点乘y的操作,所以由此我们也能拓展到线性SVM的核函数就是原本的x点乘y
当我们知道核函数的概念之后,可以引入很多不同的核函数,他们对应不同的对原本的数据样本点相应的转换
高斯核函数是SVM中用的最多的核函数,k函数表示的就是我们重新定义的x’,y’的点乘
对于高斯核函数来说
对于高斯核函数来说,仅有一个超参数γ。
对比一下这个式子γ代替了高斯函数中的-1/2*(1/σ)2
高斯核函数也成为镜像基函数(RBF核)
在之前的多项式核函数来说,本质是将所有的数据点添加了多项式项,然后将这些有了多项式项的新的数据特征进行点乘,就形成了多项式核函数。
对于高斯核函数而言,也是将我们原本的数据点映射成了一种新的特征向量,然后将新的特征向量进行点乘(我们也不需要了解这个新的样本点是什么样,我们直接关注映射后点乘的结果即可)。只是这个高斯核函数表示出来的数据映射非常复杂
对比多项式特征,我们所做的是依靠升维,将原本线性不可分的数据变成了线性可分(比如原本的数据特征只有x,添加了x2 的数据使数据变得线性可分)
比如这个一维数据,我们不能通过添加一条数据的方式使这些数据分成两类。
如果我们给他们升维,第二个维度给成x2 ,那么数据就变成了以下的样子
x的取值不变,第二个维度的取值变成了x2 ,现在对这些数据点我们很容易找到一条直线对他们进行分类
这就是升维的意义,我们依靠升维,将原本线性不可分的数据变成了线性可分
其实高斯核所做的事情本质上也是这样的事情。
首先我们改变一下高斯核函数,y取值两个固定点l1、l2(landmark:地标)
高斯核函数的升维过程就是将原本的每一个x值,如果有两个地标的话,就把它们升为2维的样本点,样本点的取值如下
这样我们就把原本是一维的样本点映射到了二维的空间
这里也是附上代码形式直观理解高斯核函数
(1)生成样本
'''
直观理解高斯核函数
'''
import numpy as np
import matplotlib.pyplot as plt
# 每个样本只有一个特征,并且线性不可分
x = np.arange(-4, 5, 1) # 前4后5.步长为1,对于x而言只有一个特征
y = np.array((x >= -2) & (x <= 2), dtype='int')# 线性不可分的分类数据(x>=-2并且x<=2区间的点,值等于1,其他等于0)
# 绘制样本
plt.scatter(x[y == 0], [0]*len(x[y==0]))
plt.scatter(x[y == 1], [0]*len(x[y==1]))
plt.show()
这显然是线性不可分的数据。接下来通过高斯核的方式将一维数据映射到二维空间
(2)映射到二维空间
'''
将一维数据映射到二维
l:landmark地标
'''
def gaussian(x, l):
gamma = 1.0
return np.exp(-gamma * (x - l) ** 2) # 这里x和l都是一维数据,他们的模直接用x-l
l1, l2 = -1, 1
# 存储新的二维数据
X_new = np.empty((len(x), 2))
for i, data in enumerate(x):
X_new[i, 0] = gaussian(data, l1) # 第0个特征
X_new[i, 1] = gaussian(data, l2) # 第1个特征
# 可视化结果
plt.scatter(X_new[y == 0, 0], X_new[y == 0, 1])
plt.scatter(X_new[y == 1, 0], X_new[y == 1, 1])
plt.show()
对于这样的二维数据,我们可以看到这显然是线性可分的
这样一来,线性不可分的一维数据,在映射之后,在二维数据变得线性可分。
上面我们所做的事情相当于是固定了两个地标l1,l2,但是在高斯核函数中相当于对每一个数据都是地标点,对于每一个样本x都要尝试对于每一个样本y进行核函数的计算,成为新的高维数据对应的某一个维度的元素。
这里高斯核函数的升维是将mn维的数据映射成了mm的数据,如果样本点有无穷多个,那么映射之后就是无穷维的(所以当m
这个正态分布的表达式中,有两个参数μ和σ,μ是均值(决定高斯函数中心轴的位置),σ是标准差(用来描述样本数据的分布情况,σ越小,整个函数的分布越窄,越集中;σ越大,整个函数更平缓,展示出来的越“胖”)。在上图中,μ是一样的等于0,改变σ的值,发现整个函数的分布会随σ的变化而变化。
在高斯核函数当中整个1/2*(1/σ)2 变成了γ这一项,所以在高斯核函数当中函数随伽马的变化趋势和正态分布中函数随σ变化的趋势是相反的