支持向量机将向量映射到一个更高维的空间里,在这个空间里建立有一个最大间隔超平面。在分开数据的超平面的两边建有两个互相平行的超平面,分隔超平面使两个平行超平面的距离最大化。假定平行超平面间的距离或差距越大,分类器的总误差越小。

SVM1.png

在上面的图中,a和b都可以作为分类超平面,但最优超平面只有一个,最优分类平面使间隔最大化。那是不是某条直线比其他的更加合适呢?我们可以凭直觉来定义一条评价直线好坏的标准:距离样本太近的直线不是最优的,因为这样的直线对噪声敏感度高,泛化性较差。因此我们的目标是找到一条直线(图中的最优超平面),离所有点的距离最远。由此,SVM算法的实质是找出一个能够将某个值最大化的超平面,这个值就是超平面离所有训练样本的最小距离。这个最小距离用SVM术语来说叫做间隔(margin)。
支持向量机 - 图2
线性分类器的目标是要在n维的数据空间中找到一个超平面(hyper plane),将x的数据点分成两类,且超平面距离两边的数据的间隔最大。
参考:1.SVM原理详细图文教程来了!一行代码自动选择核函数,还有模型实用工具

线性可分支持向量机与硬间隔最大化

线性可分支持向量机

给定训练样本集支持向量机 - 图3,分类学习最基本的想法就是基于训练集支持向量机 - 图4在样本空间中找到一个划分超平面,将不同类别的样本分开。但能将训练样本分开的划分超平面可能有很多
SVM2.png
直观上看,应该去找位于两类训练样本“正中间”的划分超平面,即上图橘色那个,因为该划分超平面对训练样本局部扰动的“容忍”性最好。例如,由于训练集的局限性或噪声的因素,训练集外的样本可能比上图中的训练样本更接近两个类的分隔界,这将使许多划分超平面出现错误,而橘色的超平面受影响最小。换言之,这个超平面所产生的分类结果是最鲁棒的,对未见示例的泛化能力最强。

在样本空间中,划分超平面可通过如下线性方程来描述:

支持向量机 - 图6

以及相应的分类决策函数:

支持向量机 - 图7

其中支持向量机 - 图8为法向量,决定了超平面的方向;支持向量机 - 图9为位移项,决定了超平面与原点间的距离。显然,划分超平面可被法向量支持向量机 - 图10和位移支持向量机 - 图11确定,下面我们将其记为支持向量机 - 图12。样本空间中任意点支持向量机 - 图13到超平面支持向量机 - 图14的距离可写为:支持向量机 - 图15。(点到直线距离:支持向量机 - 图16

函数间隔和几何间隔

函数间隔(Functional margin)

一般来说,一个点距离分离超平面的远近可以表示分类预测的确信程度。在超平面支持向量机 - 图17确定的情况下,支持向量机 - 图18能够相对地表示点支持向量机 - 图19距离超平面的远近。而支持向量机 - 图20的符号标记与类标记支持向量机 - 图21是否一致能够表示分类是否正确。所以可用量支持向量机 - 图22来表示分类的正确性及确信度,这就是函数间隔。

定义:对于给定的训练数据集支持向量机 - 图23和超平面支持向量机 - 图24,定义超平面支持向量机 - 图25关于样本点支持向量机 - 图26的函数间隔为:支持向量机 - 图27;超平面支持向量机 - 图28关于训练数据集支持向量机 - 图29的函数间隔为超平面关于支持向量机 - 图30中所有样本点支持向量机 - 图31的函数间隔之最小值(离超平面最近的点都分对了,其他的点肯定也对),即支持向量机 - 图32

几何间隔(Geometric margin)

函数间隔可以表示分类预测的正确性及确信度,但是选择分离超平面时,只有函数间隔还不够。因为只要成比例地改变支持向量机 - 图33支持向量机 - 图34,例如将它们改为支持向量机 - 图35支持向量机 - 图36,超平面并没有改变,但函数间隔却成为原来的2倍。这一事实启示我们,可以对分离超平面法向量支持向量机 - 图37加某些约束,如规范化,支持向量机 - 图38,使间隔是确定的,这时函数间隔称为几何间隔。

下图给出了超平面支持向量机 - 图39及其法向量支持向量机 - 图40。点支持向量机 - 图41表示某一实例支持向量机 - 图42,其类标记为支持向量机 - 图43。点支持向量机 - 图44与超平面支持向量机 - 图45的距离由线段支持向量机 - 图46给出,记作支持向量机 - 图47

支持向量机 - 图48

其中,支持向量机 - 图49支持向量机 - 图50支持向量机 - 图51范数。这是点支持向量机 - 图52在超平面正的的一侧的情形。如果点支持向量机 - 图53在超平面负的一侧,即支持向量机 - 图54,那么点与超平面的距离为(因为我们的超平面在两类的“正中央”,即距离相同):

支持向量机 - 图55

一般地,当样本点支持向量机 - 图56被超平面支持向量机 - 图57正确分类时,点支持向量机 - 图58与超平面的距离是:

支持向量机 - 图59

SVM3.png

定义:对于给定的训练数据集支持向量机 - 图61和超平面支持向量机 - 图62,定义超平面关于样本点支持向量机 - 图63的几何间隔为:支持向量机 - 图64;超平面支持向量机 - 图65关于训练数据集支持向量机 - 图66的几何间隔为超平面关于支持向量机 - 图67中所有样本点支持向量机 - 图68的函数间隔之最小值(离超平面最近的点都分对了,其他的点肯定也对),即支持向量机 - 图69

两间隔关系

超平面支持向量机 - 图70关于样本点支持向量机 - 图71的几何间隔一般是实例点到超平面的带符号的距离(signed distance),当样本点被超平面正确分类时就是实例点到超平面的距离。从函数距离和几何距离的定义可知两者的关系(支持向量机 - 图72为函数距离,支持向量机 - 图73为几何距离):

支持向量机 - 图74

如果支持向量机 - 图75,那么函数间隔和几何间隔相等。如果超平面参数支持向量机 - 图76支持向量机 - 图77成比例地改变(超平面没有改变),函数间隔也按此比例改变,而几何间隔不变。

间隔最大化

支持向量机学习的基本想法是求解能够正确划分训练数据集并且几何间隔最大的分离超平面。对线性可分的训练数据集而言,线性可分分离超平面有无穷多个(等价于感知机),但是几何间隔最大的分离超平面是唯一的。这里的间隔最大化又称为硬间隔最大化(与将要讨论的训练数据集近似线性可分时的软间隔最大化相对应)。

最大间隔分离超平面

如何求得一个几何间隔最大的分离超平面,即最大间隔分离超平面。具体地,这个问题可以表示为下面的约束最优化问题:

支持向量机 - 图78

我们希望最大化超平面支持向量机 - 图79关于训练数据集的几何间隔支持向量机 - 图80,约束条件表示的是超平面关于每个训练样本点的几何间隔至少是支持向量机 - 图81,结合几何间隔与函数间隔的关系式,可将上式改写为:

支持向量机 - 图82

函数间隔支持向量机 - 图83的取值并不影响最优化问题的解。实际上,假设将支持向量机 - 图84支持向量机 - 图85按比例改变为支持向量机 - 图86支持向量机 - 图87,这时函数间隔成为支持向量机 - 图88。函数间隔的这一改变对上面最优化问题的不等式约束并没产生影响,对目标函数的优化也没有影响,也就是说,它产生一个等价的优化问题。这样,就可以取支持向量机 - 图89。将支持向量机 - 图90代入上面的最优化问题,就是最大化支持向量机 - 图91,为方便计算,我们转化为最小化支持向量机 - 图92(两者等价,因为求最大化支持向量机 - 图93即最小化支持向量机 - 图94,即支持向量机 - 图95),于是就得到下面的线性可分支持向量机学习的最优化问题:

支持向量机 - 图96

所以求解出最优解支持向量机 - 图97支持向量机 - 图98就可以得到分离超平面

支持向量机 - 图99

从而得到分类决策函数

支持向量机 - 图100

对偶问题

我们希望求解支持向量机 - 图101来得到最大间隔超平面所对应的模型。对其使用拉格朗日乘子法可得其“对偶问题”。具体来说,对上式的每条约束添加拉格朗日乘子支持向量机 - 图102,则该问题的拉格朗日函数可写为

支持向量机 - 图103

其中支持向量机 - 图104。令支持向量机 - 图105支持向量机 - 图106支持向量机 - 图107的偏导为零可得

支持向量机 - 图108 支持向量机 - 图109

支持向量机 - 图110代入拉格朗日函数,再考虑约束支持向量机 - 图111,就得到原问题

支持向量机 - 图112

的对偶问题

支持向量机 - 图113

解出支持向量机 - 图114后,求出支持向量机 - 图115支持向量机 - 图116即可得到模型

支持向量机 - 图117

从对偶问题解出的支持向量机 - 图118是拉格朗日函数中的拉格朗日乘子,它恰对应着训练样本支持向量机 - 图119。原问题中有不等式约束支持向量机 - 图120,因此上述过程需满足KKT条件,即要求

支持向量机 - 图121

于是,对任意训练样本支持向量机 - 图122,总有支持向量机 - 图123支持向量机 - 图124(即需要满足最上面最后一个等式约束)。若支持向量机 - 图125,则该样本将不会在支持向量机 - 图126的求和中出现,也就不会对支持向量机 - 图127有任何影响;若支持向量机 - 图128,则必有支持向量机 - 图129,所对应的样本点位于最大间隔边界上,是一个支持向量。这显示出支持向量的一个重要性质:训练完成后,大部分的训练样本都不需要保留,最终模型仅与支持向量有关。

那么,如何求解支持向量机 - 图130呢?不难发现,这是一个二次规划问题,可使用通用的二次规划算法来求解;然而,该问题的规模正比于训练样本数,这会在实际任务中造成很大的开销。为了避免这个障碍,人们提出利用问题本身的特性,提出了很多高效的算法,SMO(Sequential Minimal Optimization)是其中一个著名的代表。

线性支持向量机与软间隔最大化

线性支持向量机

线性可分问题的支持向量机学习方法对线性不可分训练数据是不适用的,因为这时上述方法中的不等式约束不能成立。为了扩展到线性不可分问题,就需要修改硬间隔最大化,使其成为软间隔最大化。

线性不可分意味着某些样本点支持向量机 - 图131不能满足函数间隔大于等于1的约束条件。为了解决这个问题,可以对每个样本点引进一个松弛变量支持向量机 - 图132,使函数间隔加上松弛变量大于等于1这样,约束条件变为:

支持向量机 - 图133

同时,对每个松弛变量支持向量机 - 图134,支付一个代价支持向量机 - 图135。目标函数由原来的支持向量机 - 图136变成

支持向量机 - 图137

这里,支持向量机 - 图138称为惩罚参数,一般由应用问题决定,支持向量机 - 图139值大时对误分类的惩罚增大,支持向量机 - 图140值小时对误分类的惩罚减小。最小化目标函数包含两层含义:使支持向量机 - 图141尽量小即间隔尽量大,同时使误分类点的个数尽量小,支持向量机 - 图142是调和两者的系数。

有了上面的思路,可以和训练数据集线性可分时一样来考虑训练数据集线性不可分时的线性支持向量机学习问题。相应于硬间隔最大化,它成为软间隔最大化。线性不可分的线性支持向量机的学习问题变成如下凸二次规划问题:

支持向量机 - 图143

问题是一个凸二次规划问题,因而关于支持向量机 - 图144的解是存在的。可以证明支持向量机 - 图145的解是唯一的,但支持向量机 - 图146的解可能不唯一,而是存在于一个区间。设问题的解是支持向量机 - 图147支持向量机 - 图148。于是可以得到分离超平面支持向量机 - 图149及分类决策函数支持向量机 - 图150,称这样的模型为训练样本线性不可分时的线性支持向量机,简称线性支持向量机。显然,线性支持向量机包含线性可分支持向量机。由于现实中训练数据集往往是线性不可分的,线性支持向量即具有更广的适用性。优化目标函数可写为

支持向量机 - 图151

其中支持向量机 - 图152是一个常数,支持向量机 - 图153是“0/1损失函数”

支持向量机 - 图154

显然,支持向量机 - 图155为无穷大时,优化目标函数迫使所有样本均满足约束支持向量机 - 图156;当支持向量机 - 图157取有限值时,优化目标函数允许一些样本不满足约束。然而,支持向量机 - 图158非凸、非连续,数学性质不太好,使得优化目标函数不易直接求解。于是,通常用其他一些函数来代替支持向量机 - 图159称为“替代损失”。替代损失函数一般具有较好的数学性质,如通常它们是凸的连续函数且是支持向量机 - 图160的上界。常用三种替代损失函数:

  1. hinge损失:支持向量机 - 图161
  2. 指数损失:支持向量机 - 图162
  3. 对率损失:支持向量机 - 图163

SVM4.png

对偶问题

每个样本都有一个对应的松弛变量,用以表征该样本不满足约束的程度。但是仍是一个二次规划问题.于是,通过拉格朗日乘子法可得到拉格朗日函数

支持向量机 - 图165

其中支持向量机 - 图166支持向量机 - 图167是拉格朗日乘子

支持向量机 - 图168支持向量机 - 图169的偏导为零可得

支持向量机 - 图170

将上面三式代入拉格朗日函数即可得对偶问题

支持向量机 - 图171

可以看出软间隔和硬间隔唯一的差别就在于对偶变量的约束不同:前者是支持向量机 - 图172,后者是支持向量机 - 图173。于是,可采用同样的算法求解上式。对软间隔支持向量机,KKT条件要求

支持向量机 - 图174

于是,对任意训练样本支持向量机 - 图175,总有支持向量机 - 图176支持向量机 - 图177,且支持向量机 - 图178所以参数含义:

  1. 支持向量机 - 图179,则该样本不会对支持向量机 - 图180有任何影响。
  2. 支持向量机 - 图181,则必有支持向量机 - 图182,即该样本是支持向量。
  3. 支持向量机 - 图183,则支持向量机 - 图184,进而有支持向量机 - 图185,即该样本恰在最大间隔边上。
  4. 支持向量机 - 图186,则支持向量机 - 图187,此时若支持向量机 - 图188,即该样本落在最大间隔内部。
  5. 支持向量机 - 图189,则该样本被错误分类。

由此可看出,软间隔支持向量机的最终模型仅与支持向量有关,即通过采用hinge损失函数仍保持了稀疏性

非线性支持向量机与核函数

对解线性分类问题,线性支持向量机是一种非常有效的方法。但是,有时分类问题是非线性的,这时可以使用非线性支持向量机。本节叙述非线性支持向量机,其主要特点是利用核技巧。

核技巧

非线性分类问题是指通过利用非线性模型才能很好地进行分类的问题。比如下图

核技巧.png

非线性问题往往不好求解,所采取的方法是进行一个非线性变换,将非线性问题变换为线性问题,通过解变换后的线性问题的方法求解原来的非线性问题。用线性分类方法求解非线性分类问题分为两步:

  1. 1、首先使用一个变换将原空间的数据映射到新空间
  2. 2、然后在新空间里用线性分类学习方法从训练数据中学习分类模型

核技巧应用到支持向量机,其基本想法就是通过一个非线性变换将空间(欧氏空间或离散集合)对应于一个特征空间(希尔伯特空间),使得在输入空间中的超曲面模型对应特征空间中的超平面模型。这样,分类问题的学习任务通过在特征空间中求解线性支持向量机就可以完成。

核函数的作用

下面这张图位于第一、二象限内。我们关注红色的门,以及“北京四合院”这几个字下面的紫色的字母。我们把红色的门上的点看成是“+”数据,紫色字母上的点看成是“-”数据,它们的横、纵坐标是两个特征。显然,在这个二维空间内,“+”“-”两类数据不是线性可分的。

支持向量机 - 图191

我们现在考虑核函数支持向量机 - 图192,即“内积平方”。这里面支持向量机 - 图193是二维空间中的两个点。

这个核函数对应着二维到三维空间的映射,它的表达式是:支持向量机 - 图194,可以验证:

支持向量机 - 图195
支持向量机 - 图196

在P这个映射下,原来二维空间中的图在三维空间中的像是这个样子:支持向量机 - 图197

支持向量机 - 图198

注意到绿色的平面可以完美地分割红色和紫色,也就是说,两类数据在三维空间中变成线性可分的了。

而三维中的这个判决边界,再映射回二维空间中是这样的:
支持向量机 - 图199

这是一条双曲线,它不是线性的。核函数的作用就是隐含着一个从低维空间到高维空间的映射,而这个映射可以把低维空间中线性不可分的两类点变成线性可分的。它们映射到的高维空间的维数也比例子(三维)高得多,甚至是无穷维的。这样,就可以期待原来并不线性可分的两类点变成线性可分的了。

在机器学习中常用的核函数,一般有这么几类,也就是LibSVM中自带的这几类:

  1. 线性:支持向量机 - 图200
  2. 多项式:支持向量机 - 图201
  3. Radial basis function:支持向量机 - 图202
  4. Sigmoid:支持向量机 - 图203

上面的例子是2.多项式核函数中支持向量机 - 图204的情况。

核函数要满足的条件称为Mercer’s condition。在实用中,基本是试验各种核函数,并扫描其中的参数,选择效果最好的。所以说,至于什么样的核函数适用于什么样的问题还有待讨论。

核技巧在支持向量机中的应用

我们注意到在线性支持向量机的对偶问题中,无论是目标函数还是决策函数(分离超平面)都只涉及输入实例与实例之间的内积。在对偶问题的目标函数中的内积支持向量机 - 图205可以用核函数支持向量机 - 图206来代替。此时对偶问题的目标函数称为

支持向量机 - 图207

同样,分类决策函数中的内积也可以用核函数代替,而分类决策函数式成为

支持向量机 - 图208

这等价于经过映射函数支持向量机 - 图209将原来的输入空间变换到一个新的特征空间,将输入空间中的内积支持向量机 - 图210变换为特征空间中的内积支持向量机 - 图211,在新的特征空间里从训练样本中学习线性支持向量机。当映射函数是非线性函数时,学习到的含有核函数的支持向量机是非线性分类模型。

也就是说,在核函数支持向量机 - 图212给定的条件下,可以利用解线性分类问题的方法求解非线性分类问题的支持向量机。学习是隐式地在特征空间进行的,不需要显式地定义特征空间和映射函数。这样的技巧称为核技巧,它是巧妙地利用线性分类学习方法与核函数解决非线性问题的技术。在实际应用中,往往依赖领域知识直接选择核函数,核函数选择的有效性需要通过实验验证。

非线性支持向量分类机

如上所述,利用核技巧,可以将线性分类的学习方法应用到非线性分类问题中去。将线性支持向量机扩展到非线性支持向量机,只需将线性支持向量机对偶形式中的内积换成核函数。

从非线性分类训练集,通过核函数与软间隔最大化,或凸二次规划,学习得到的分类决策函数

支持向量机 - 图213

称为非线性支持向量,支持向量机 - 图214是正定核函数。

具体算法如下

输入:支持向量机 - 图215,其中支持向量机 - 图216支持向量机 - 图217支持向量机 - 图218
输出:分类决策函数

  1. 选取适当的核函数支持向量机 - 图219和适合的参数支持向量机 - 图220,构造并求解最优化问题支持向量机 - 图221

得到最优解支持向量机 - 图222

  1. 选择支持向量机 - 图223的一个正分量支持向量机 - 图224,计算支持向量机 - 图225
  2. 构造决策函数支持向量机 - 图226

序列最小最优化算法(SMO)

支持向量机的学习问题可以形式化求解凸二次规划问题。这样的凸二次规划问题具有全局最优解,并且有许多最优化算法可以用于这一问题的求解。但是当训练样本容量很大时,这些算法往往变得非常低效,以致无法使用。序列最小最优化算法(Sequential Minimal Optimization, SMO)为高效地实现支持向量机学习提供一个解决途径。

SMO算法要解如下凸二次规划的对偶问题:

支持向量机 - 图227

在这个问题中,变量是拉格朗日乘子,一个变量支持向量机 - 图228对应于一个样本点支持向量机 - 图229;变量的总数等于训练样本总量支持向量机 - 图230

SMO算法是一种启发式算法,其基本思路是:如果所有变量的解都满足此最优化问题的KKT条件,那么这个最优化问题的解就得到了。因为KKT条件是该优化问题的充分必要条件。否则,选择两个变量,固定其他变量,针对这两个变量构建一个二次规划问题。这个二次规划问题关于这两个变量的解应该更接近原始二次规划问题的解,因为这会使得原始二次规划问题的目标函数值变得更小。重要的是,这时子问题可以通过解析方法求解,这样就可以大大提高整个算法的计算速度。子问题有两个变量,一个是违反KKT条件最严重的那一个,另一个由约束条件自动确定。如此,SMO算法将原问题不断分解成子问题并对子问题求解,进而达到求解原问题的目的。

注意,子问题的两个变量中只有一个是自由变量。假设支持向量机 - 图231支持向量机 - 图232为两个变量,支持向量机 - 图233固定,那么由等式约束支持向量机 - 图234可知

支持向量机 - 图235

如果支持向量机 - 图236确定,那么支持向量机 - 图237也随之确定。所以子问题中同时更新两个变量。

整个SMO算法包括两个部分:求解两个变量二次规划的解析方法和选择变量的启发式方法。

两个变量二次规划的求解方法

SMO算法之所以高效,恰由于在固定其他参数后,仅优化两个参数的过程能做到非常高效。具体来说,仅考虑支持向量机 - 图238支持向量机 - 图239时,约束支持向量机 - 图240可重写为

支持向量机 - 图241

支持向量机 - 图242,就变成了

支持向量机 - 图243

代入对偶问题支持向量机 - 图244中消去变量支持向量机 - 图245,则得到一个关于支持向量机 - 图246的单变量二次规划问题,仅有的约束是支持向量机 - 图247。不难发现,这样的二次规划问题具有闭式解,于是不必调用数值优化算法即可高效地计算出更新后的支持向量机 - 图248支持向量机 - 图249

如何确定偏移项支持向量机 - 图250呢?注意到对任意支持向量支持向量机 - 图251都有支持向量机 - 图252,即

支持向量机 - 图253

其中支持向量机 - 图254为所有支持向量的下标集。理论上,可选任意支持向量并通过求解上式获得支持向量机 - 图255,但现实任务中常采用一种更鲁棒的做法:使用所有支持向量求解平均值

支持向量机 - 图256

变量的选择方法

注意到只需选取的支持向量机 - 图257支持向量机 - 图258中有一个不满足KKT条件,目标函数就会在迭代后增大。直观来看,KKT条件违背的程度越大,则变量更新后可能导致的目标函数值增幅越大。于是,SMO先选取违背KKT条件程度最大的变量。第二个变量应选择一个使目标函数值增长最快的变量,但由于比较各变量所对应的目标函数值增幅的复杂度过高,因此SMO采用了一个启发式:使选取的两变量所对应样本之间的间隔最大。一种直观的解释是,这样的两个变量有很大的差别,与对两个相似的变量进行更新相比,对它们进行更新会带给目标函数值更大的变化。

支持向量回归

传统回归模型通常直接基于模型输出支持向量机 - 图259与真实输出支持向量机 - 图260之间的差别来计算损失,当且仅当支持向量机 - 图261支持向量机 - 图262完全相同时,损失才是令零。与此不同,支持向量回归(Support Vector Regression, SVR)假设我们能容忍支持向量机 - 图263支持向量机 - 图264之间最多有支持向量机 - 图265的偏差,即仅当支持向量机 - 图266支持向量机 - 图267之间的差别绝对值大于支持向量机 - 图268时才计算损失。如下图所示,这相当于以支持向量机 - 图269为中心,构建了一个宽度为支持向量机 - 图270的隔离带,若训练样本落入此间隔带,则认为是被预测正确的

SVM5.png

于是,SVR问题可形式化为

支持向量机 - 图272

其中支持向量机 - 图273为正则化常数,支持向量机 - 图274是上图所示不敏感损失函数

支持向量机 - 图275

SVM6.png

引入松弛变量支持向量机 - 图277支持向量机 - 图278,可将问题重写为

支持向量机 - 图279
支持向量机 - 图280

引入拉格朗日乘子支持向量机 - 图281,由拉格朗日乘子法可得到拉格朗日函数

支持向量机 - 图282
支持向量机 - 图283

支持向量机 - 图284代入,再令支持向量机 - 图285支持向量机 - 图286的偏导为零

支持向量机 - 图287 支持向量机 - 图288 支持向量机 - 图289 支持向量机 - 图290

代入拉格朗日函数,即可得到SVR的对偶问题

支持向量机 - 图291
支持向量机 - 图292

上述过程中需满足KKT条件,即要求

支持向量机 - 图293

可以看出,当且仅当支持向量机 - 图294支持向量机 - 图295能取非零值,当且仅当支持向量机 - 图296支持向量机 - 图297能取非零值。换言之,仅当样本不落入支持向量机 - 图298区间隔带中,相应的支持向量机 - 图299支持向量机 - 图300才能取非零值。此外,约束支持向量机 - 图301支持向量机 - 图302不能同时成立,因此支持向量机 - 图303支持向量机 - 图304中至少有一个为零。SVR的解形如

支持向量机 - 图305

能使上式中的支持向量机 - 图306的样本即为SVR的支持向量,它们必落在支持向量机 - 图307间隔带之外。显然,SVR的支持向量仅是训练样本的一部分,即其解仍具有稀疏性。

由KKT条件可看出,对每个样本都有支持向量机 - 图308支持向量机 - 图309。于是,在得到支持向量机 - 图310后,若支持向量机 - 图311,则必有支持向量机 - 图312,进而有

支持向量机 - 图313

因此,在求解式子得到支持向量机 - 图314后,理论上来说,可任意选取满足支持向量机 - 图315的样本通过上式求得支持向量机 - 图316。实践中常采用一种更鲁棒的方法:选取多个(或所有)满足条件支持向量机 - 图317的样本求解支持向量机 - 图318后取均值。

若考虑特征映射形式,则式形如支持向量机 - 图319,则SVR可表示为支持向量机 - 图320,其中支持向量机 - 图321为核函数。

Code实现

数据

  1. import numpy as np
  2. import pandas as pd
  3. from sklearn.datasets import load_iris
  4. from sklearn.model_selection import train_test_split
  5. import matplotlib.pyplot as plt
  6. %matplotlib inline
  7. # data
  8. def create_data():
  9. iris = load_iris()
  10. df = pd.DataFrame(iris.data, columns=iris.feature_names)
  11. df['label'] = iris.target
  12. df.columns = ['sepal length', 'sepal width', 'petal length', 'petal width', 'label']
  13. data = np.array(df.iloc[:100, [0, 1, -1]])
  14. for i in range(len(data)):
  15. if data[i,-1] == 0:
  16. data[i,-1] = -1
  17. # print(data)
  18. return data[:,:2], data[:,-1]
  19. X, y = create_data()
  20. X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25)
  21. plt.scatter(X[:50,0],X[:50,1], label='0')
  22. plt.scatter(X[50:,0],X[50:,1], label='1')
  23. plt.legend()

SVM7.png

手写实现

  1. class SVM:
  2. def __init__(self, max_iter=100, kernel='linear'):
  3. self.max_iter = max_iter
  4. self._kernel = kernel
  5. def init_args(self, features, labels):
  6. self.m, self.n = features.shape
  7. self.X = features
  8. self.Y = labels
  9. self.b = 0.0
  10. # 将Ei保存在一个列表里
  11. self.alpha = np.ones(self.m)
  12. self.E = [self._E(i) for i in range(self.m)]
  13. # 松弛变量
  14. self.C = 1.0
  15. def _KKT(self, i):
  16. y_g = self._g(i)*self.Y[i]
  17. if self.alpha[i] == 0:
  18. return y_g >= 1
  19. elif 0 < self.alpha[i] < self.C:
  20. return y_g == 1
  21. else:
  22. return y_g <= 1
  23. # g(x)预测值,输入xi(X[i])
  24. def _g(self, i):
  25. r = self.b
  26. for j in range(self.m):
  27. r += self.alpha[j]*self.Y[j]*self.kernel(self.X[i], self.X[j])
  28. return r
  29. # 核函数
  30. def kernel(self, x1, x2):
  31. if self._kernel == 'linear':
  32. return sum([x1[k]*x2[k] for k in range(self.n)])
  33. elif self._kernel == 'poly':
  34. return (sum([x1[k]*x2[k] for k in range(self.n)]) + 1)**2
  35. return 0
  36. # E(x)为g(x)对输入x的预测值和y的差
  37. def _E(self, i):
  38. return self._g(i) - self.Y[i]
  39. def _init_alpha(self):
  40. # 外层循环首先遍历所有满足0<a<C的样本点,检验是否满足KKT
  41. index_list = [i for i in range(self.m) if 0 < self.alpha[i] < self.C]
  42. # 否则遍历整个训练集
  43. non_satisfy_list = [i for i in range(self.m) if i not in index_list]
  44. index_list.extend(non_satisfy_list)
  45. for i in index_list:
  46. if self._KKT(i):
  47. continue
  48. E1 = self.E[i]
  49. # 如果E2是+,选择最小的;如果E2是负的,选择最大的
  50. if E1 >= 0:
  51. j = min(range(self.m), key=lambda x: self.E[x])
  52. else:
  53. j = max(range(self.m), key=lambda x: self.E[x])
  54. return i, j
  55. def _compare(self, _alpha, L, H):
  56. if _alpha > H:
  57. return H
  58. elif _alpha < L:
  59. return L
  60. else:
  61. return _alpha
  62. def fit(self, features, labels):
  63. self.init_args(features, labels)
  64. for t in range(self.max_iter):
  65. # train
  66. i1, i2 = self._init_alpha()
  67. # 边界
  68. if self.Y[i1] == self.Y[i2]:
  69. L = max(0, self.alpha[i1]+self.alpha[i2]-self.C)
  70. H = min(self.C, self.alpha[i1]+self.alpha[i2])
  71. else:
  72. L = max(0, self.alpha[i2]-self.alpha[i1])
  73. H = min(self.C, self.C+self.alpha[i2]-self.alpha[i1])
  74. E1 = self.E[i1]
  75. E2 = self.E[i2]
  76. # eta=K11+K22-2K12
  77. eta = self.kernel(self.X[i1], self.X[i1]) + self.kernel(self.X[i2], self.X[i2]) - 2*self.kernel(self.X[i1], self.X[i2])
  78. if eta <= 0:
  79. # print('eta <= 0')
  80. continue
  81. alpha2_new_unc = self.alpha[i2] + self.Y[i2] * (E1 - E2) / eta#此处有修改,根据书上应该是E1 - E2,书上130-131页
  82. alpha2_new = self._compare(alpha2_new_unc, L, H)
  83. alpha1_new = self.alpha[i1] + self.Y[i1] * self.Y[i2] * (self.alpha[i2] - alpha2_new)
  84. b1_new = -E1 - self.Y[i1] * self.kernel(self.X[i1], self.X[i1]) * (alpha1_new-self.alpha[i1]) - self.Y[i2] * self.kernel(self.X[i2], self.X[i1]) * (alpha2_new-self.alpha[i2])+ self.b
  85. b2_new = -E2 - self.Y[i1] * self.kernel(self.X[i1], self.X[i2]) * (alpha1_new-self.alpha[i1]) - self.Y[i2] * self.kernel(self.X[i2], self.X[i2]) * (alpha2_new-self.alpha[i2])+ self.b
  86. if 0 < alpha1_new < self.C:
  87. b_new = b1_new
  88. elif 0 < alpha2_new < self.C:
  89. b_new = b2_new
  90. else:
  91. # 选择中点
  92. b_new = (b1_new + b2_new) / 2
  93. # 更新参数
  94. self.alpha[i1] = alpha1_new
  95. self.alpha[i2] = alpha2_new
  96. self.b = b_new
  97. self.E[i1] = self._E(i1)
  98. self.E[i2] = self._E(i2)
  99. return 'train done!'
  100. def predict(self, data):
  101. r = self.b
  102. for i in range(self.m):
  103. r += self.alpha[i] * self.Y[i] * self.kernel(data, self.X[i])
  104. return 1 if r > 0 else -1
  105. def score(self, X_test, y_test):
  106. right_count = 0
  107. for i in range(len(X_test)):
  108. result = self.predict(X_test[i])
  109. if result == y_test[i]:
  110. right_count += 1
  111. return right_count / len(X_test)
  112. def _weight(self):
  113. # linear model
  114. yx = self.Y.reshape(-1, 1)*self.X
  115. self.w = np.dot(yx.T, self.alpha)
  116. return self.w
  117. svm = SVM(max_iter=200)
  118. svm.fit(X_train, y_train)
  119. svm.score(X_test, y_test)

sklearn实现

https://scikit-learn.org/stable/modules/generated/sklearn.svm.SVC.html

  1. from sklearn.svm import SVC
  2. clf = SVC()
  3. clf.fit(X_train, y_train)
  4. clf.score(X_test, y_test)

Source

https://www.zhihu.com/question/24627666/answer/28440943