支持向量机

来源:互联网 发布:linux vim安装包下载 编辑:程序博客网 时间:2024/05/31 19:22

本文将尝试对 SVMs 的工作方式进行更高层次的理解。我将更专注于培养直觉理解而不是严密性。这意味着会尽可能跳过数学细节而建立其工作方式的理论的直观理解。

自从Statsbot团队发表了关于time series anomaly detection, (时间序列的异常检测)的文章之后,很多读者要求我们介绍支持向量机方法。是时候满足你们的要求了,我将在不使用高深数学的前提下向你们介绍 SVM,分享有用的程序库和资源帮助你们入门。

如果你曾经使用机器学习进行分类,应该会听说支持向量机(SVM)。这个算法的历史已经有五十出头,它们随着时间不断在进化,并适应于各种其它问题比如回归,离群值分析和排序。

在很多深度学习开发者的武器库中,SVMs 都是他们的至爱。在 [24]7,我们也将使用它们解决多个问题。我将更专注于培养直觉理解而不是严密性。这意味着我们会尽可能跳过数学细节而建立其工作方式的理论的直观理解。

分类问题

假设你们的大学开设了一项机器学习课程,课程的讲师发现那些擅长数学或者统计学的学生往往表现的最好。课程结束之后,他们记录了注册课程的学生的分数。他们对每一个学生根据其在机器学习课程上的表现加上了一个标签:「好」或者「坏」。

现在,他们想要确定数学和统计学的得分与机器学习课程表现的关系。或许,根据他们的统计结果,他们会在学生注册课程时加上一个前提条件限制。

他们会怎么做呢?首先把他们的数据表示出来,我们可以画一个二维图,一个坐标轴表示数学成绩,另一个表示统计学成绩。每个学生的具体成绩作为一个点在图中表示。

点的颜色(绿色或者红色)表示学生在机器学习课程中的表现:「好」或者「坏」。将图画出来的话应该是这样的:

当一个学生要求注册课程的时候,讲师将会要求她提供数学和统计学的成绩。根据他们已有的数据,他们将对她在机器学习课程上的表现作出合理的猜测。我们真正想要的是一类以「分数多元组」的形式馈送(math_score,stats_score)的算法。这个算法能告诉你一个学生在图中是以一个红点还是一个绿点表示(红/绿可理解为类别或者标记)。当然,这个算法已经以某种方式包含了训练数据的特征。

在这个案例中,一个好的算法将能寻找在红色和绿色群集之间的分界线,然后确定一个分数多元组将依赖于哪一侧。我们选择绿色方或者红色方的其中一侧作为她在这项课程中最可能的表现水平的标志。

这条线称为分界线(因为它将不同标记的群集分离开来)或者分类器(我们用它来将点集分类)。图中展示了这个问题中可能的两个分类器。

好分类器 vs 坏分类器

有一个很有趣的问题:以上两条线都将红色和绿色的点群集分离开来。有什么合理依据能让我们选择其中一个而舍弃另一个吗?

要注意一个分类器的价值并不在于它能将训练数据分离的多好。我们最终是希望它能将尚未见过的数据分离(即测试数据)。因此我们需要选择能捕捉训练数据的普遍模式的那条线,而这条线更可能在测试数据中表现的更好。

以上所示的第一条线看起来有些许偏差,其下半部分看起来过于接近红点群集,其上半部分过于接近绿点群集。当然它确实很完美的将训练数据分离开来,但是如果在测试数据中遇到了有一个点离群集稍远的情况,它很有可能会将其加上错误的标记。

而第二的点就没有这样的问题。例如,下图中用两个分类器分离方块点群集的表现的结果展示。

第二条线在正确分离训练数据的同时也尽可能的远离两个群集。处于两个群集的正中间位置能降低犯错的风险,可以说,这给了每一个类的数据分布更多的摆动空间,因此它能更好的泛化到测试数据中。

SVMs 试图寻找第二类分界线。原来我们只是通过目测选择更好的分类器,但实际上为了在一般案例中应用,我们需要将其隐含原理定义的更加精确。以下将简要说明 SVMs 是如何工作的:

1. 寻找能准确分离训练数据的分界线;

2. 在所有这些分界线中选择能最大化与最近邻点的距离的分界线。

那些定义了这条分界线的最近邻点被称作支持向量。而分界线周围的区域被定义为边缘。

下图展示了支持向量和对应的第二条分界线:黑色边界的点(有两个)和边缘(阴影区域)。

支持向量机提供了一个方法在多个分类器中寻找能更准确的分离测试数据的分类器。

虽然上图中的分界线和数据是处于二维空间的,但是必须注意 SVMs 实际上能在任何维度的数据中工作,在这些维度中,它们寻找的是二维空间分界线的类似结构。

比如,在三维空间中它们寻找的是一个分界面(后面将简要提到),在更高维空间中它们寻找的是一个分界超平面-即将二维分界线和三维分界面推广到任意维度的结构。

一个可以被分界线(或者在普遍意义上,一个分界超平面)被称作线性可分数据。分界超平面被称作线性分类器。

容错性

我们在最后一节来看一个完美线性可分数据的简单例子,虽然现实中的数据通常是很凌乱的。你也很可能经常遇到一些不能正确线性分类的例子。

这里展示了一个这样的例子:

很显然,使用一个线性分类器通常都无法完美的将标签分离,但我们也不想将其完全抛弃不用,毕竟除了几个错点它基本上能很好的解决问题。那么 SVMs 会如何处理这个问题呢?SVMs 允许你明确规定允许多少个错点出现。你可以在 SVM 中设定一个参数「C」;从而你可以在两种结果中权衡:

1. 拥有很宽的边缘;

2. 精确分离训练数据;

C 的值越大,意味着在训练数据中允许的错点越少。

必需强调一下这是一个权衡的过程。如果想要更好的分类训练数据,那么代价就是边缘会更宽。以下几个图展示了在不同的 C 值中分类器和边缘的变化(未显示支持向量)。

注意分界线随 C 值增大而倾斜的方式。在更大的 C 值中,它尝试将右下角的红点尽可能的分离出来。但也许我们并不希望在测试数据中也这么做。第一张图中 C=0.01,看起来更好的抓住了普遍的趋势,虽然跟更大的 C 值相比,它牺牲了精确性。

考虑到这是一个权衡方法,需要注意边缘如何随着 C 值的增大而缩小。

在之前的例子中,边缘内是不允许任何错点的存在的。在这里我们看到,同时拥有好的分离边界和没有错点的边缘是基本不可能的。

由于现实世界中的数据几乎不可能精确的分离,确定一个合适的 C 值很重要且很有实际意义,经常出现这样的需求。我们往往使用交叉验证选择合适的 C 值。

非线性可分数据

我们已经介绍过支持向量机如何处理完美或者接近完美线性可分数据,那对于那些明确的非线性可分数据,SVMs 又是怎么处理的呢?毕竟有很多现实世界的数据都是这一类型的。当然,寻找一个分界超平面已经行不通了,这反而突出了 SVMs 对这种任务有多擅长。

这里有一个关于非线性可分数据的例子(这是著名的 XOR dataset 的变体),图中展示了线性分类器 SVMs 的结果:

这样的结果并不怎么样,在训练数据中只能得到 75% 的准确率,这是使用分界线能得到的最好结果。此外,分界线和一些数据点过于接近,甚至将一些点分割开来。

我们需要做的更好。

现在轮到我最喜欢的 SVMs 的部分登场了。我们目前拥有:一项擅长寻找分界超平面的技术,以及无法线性分离的数据。那么怎么办?

当然是,将数据投射到另一个空间中使其线性可分然后寻找分界超平面!

我会一步一步的详细介绍这个想法。

仍然从上图中的数据集为例,然后将其投射到三维空间中,其中新的坐标为:

下图中展示了投射数据的表示,你发现了能塞进一个平面的地方了吗?

让我们开始在上面运行 SVMs:

Bingo!标签分离很完美,接下来将平面投射回初始的二维空间中看看分离界面是什么样子的:

在训练数据中得到了 100% 的准确率,而且分离边界并不会过于接近数据点,太棒了!

初始空间中的分离边界的形状依赖于投射的形式。在投射空间中,分离边界通常是一个超平面。

要记住,投射数据的最主要的目的是为了使用 SVMs 寻找分界超平面的超能力。

当将分界超平面映射回初始空间时,分离边界不再是一条线了,边缘和支持向量也变得不同。根据视觉直觉,它们在投射空间的形态是很好理解的。

看看它们在投射空间中的样子,再看看在初始空间。3D 边缘(为了避免视觉混乱,没有加上阴影)是分界超平面之间的区域。

在投射空间中有 4 个支持向量,这很合理,它们分布在两个平面上以确定边缘。在初始空间中,它们依然在边缘上,但是看起来数量并不足以确定边缘。

让我们回过头分析一下:

1. 如何确定要将数据投射到什么样的空间?

我之前已经很明确的提过-在某个地方出现了根号 2!

在这个例子中,我想展示一下向高维空间投射的过程,因此我选了一个很具体的投射。一般而言,这是很难确定的。不过,多亏了 over』s theorem,我们能确定的是通过将数据投射到高维空间确实更可能使数据线性可分。

2. 所以我要做的就是投射数据然后运行 SVM?

不是。为了使上述例子更好理解,我解释的好像我们需要先将数据投射。如果你自行将数据投射,你要怎么表征无穷维空间呢?看起来 SVMs 很擅长这个,是时候看看算法的内核了。

内核

最终还是这个独家秘方才使得 SVMs 有了打标签的能力。在这里我们需要讨论一些数学。

让我们盘查一下目前我们所见过的:

1. 对于线性可分数据 SVMs 工作的非常出色。

2. 对于几乎线性可分数据,只要只用正确的 C 值,SVMs 仍然可以工作的很好。

3. 对于非线性可分数据,可以将数据投射到另一个空间使数据变得完美或者几乎完美线性可分,将问题回归到了 1 或者 2。

首先,让我们稍微离题一会。

SVMs 的一个非常令人惊喜的方面是,其所有使用的数学机构,如精确的投射,甚至是空间的维度,都没有显式表示出来。你可以根据数据点(以向量表示)的点积将所有的数学写出来。例如 P 维的向量 i 和 j,第一个下标区分数据点,第二个下标表示维度:

点积的定义如下:

如果数据集中有 n 个点,SVM 只需要将所有点两两配对的点积以寻找分类器。仅此而已。当我们需要将数据投射到高维空间的时候也是这样,不需要向 SVM 提供准确的投射,而是提供投射空间中所有点两两配对的点积。

重提一下我们之前做过的投射,看看能不能找到相关的内核。同时我们也会跟踪投射的计算量,然后寻找点积,看看相比之下,内核是怎么工作的。

对于任意一个点 i:

其对应的投射点的坐标为:

我们需要进行以下操作以完成投射:

得到新坐标的第一个维度:1 次乘法

第二个维度:1 次乘法

第三个维度:2 次乘法

加起来总共是 1+1+2=4 次乘法

在新坐标中的点积是:

为了计算两个点 i 和 j 的点积,我们需要先计算它们的投射。因此总共是 4+4=8 次乘法,然后点积的计算包含了 3 次乘法和 2 次加法。

总计为,

乘法:8(投射)+3(点积)=11 次乘法

加法:2 次(点积之间)

总数为 11+2=13 次计算

而以下这个内核函数将给出相同的结果:

首先在初始空间中计算向量的点积,然后将结果进行平方。

把式子展开然后看看是否正确:

确实是这样。这个式子需要多少次计算呢?看看以上式子的第二步。在二维空间中计算点积只需要 2 次乘法和 1 次加法,平方运算是另一次乘法。

因此,总计为:

  • 乘法:2(初始空间的点积)+1(平方运算)=3 次乘法

  • 加法:1(初始空间的点积)

看起来使用内核函数计算所需要的点积会更快。目前看来这似乎并不是什么重要的选择:只不过是 4 次和 13 次的比较,但在输入点处于高维度,而投射空间有更高的维度的情形中,大型数据集的计算所节省的计算量能大大加快训练的速度。因此使用内核函数有相当大的优势。

大部分 SVM 程序库已经经过预包装并包含了一些很受欢迎的内核函数比如多项式,径向基函数(RBF),以及 Sigmoid 函数。当不使用投射的时候(比如文中第一个例子),我们就在初始空间中计算点积,我们之前提过,这叫做线性内核。

很多内核函数能提供额外的手段进一步调整数据。比如,多项式内核:

该多项式允许选择 c 和 d(多项式的度)的值。在上述 3D 投射的例子中,我使用的值为 c=0,d=2。

但是内核函数的优点远远不止于此!

还记得我之前提到向无穷维空间投射的情况吗?只需要知道正确的内核函数就可以了。因此,我们并不需要将输入数据投射,或者困惑无穷维空间的问题。

内核函数就是为了计算当数据确实被投射的时候,内积的形式。

RBF 内核函数通常在一些具体的无穷维投射问题中应用。在这里我们不讨论数学细节,但会在文末提到一些参考文献。

如何在空间维度为无穷的情况计算点积呢?如果你觉得困惑,回想一下无穷序列的加法是如何计算的,相似的道理。虽然在内积中有无穷个项,但是能利用一些公式将它们的和算出来。

这解答了我们前一节中提到的问题。总结一下:

1. 我们通常不会为数据定义一个特定的投射,而是从几个可用的内核函数中选择,在某些例子中需要做一些参数调整,最后选出最适合数据的内核函数。

2. 我们并不需要定义内核函数或者自行将数据投射。

3. 如果有可用的内核函数,使用它将使计算更快。

4.RBF 内核函数可将数据投射到无穷维空间中。

SVM 程序库

你可以在很多 SVM 程序库中选择以开始你的实验:

  • libSVM

  • SVM—Light

  • SVMTorch

很多普适的机器学习程序库比如 scikit-learn 也提供 SVM 模块,通常在专用的 SVM 程序库中封装。我推荐使用经验证测试可行的 libSVM。

libSVM 通常是一个命令行工具,但下载包通常捆绑封装了 Python,Java 和 MATLAB。只要将你的数据文件经 libSVM 格式化后(下载文件中 README 将解释这一部分,以及其它可选项),就可以开始试验了。

实际上,如果你想快速获得不同内核函数,不同 c 值等是如何影响分离边界的理解,试试登陆「Graphical Interface」的 home page。在上面标记几类数据点,选择 SVM 参数,然后运行就可以了。

我很快去尝试了一下:

我给 SVM 出了个难题。

然后我尝试了几个不同的内核函数:

网站界面并没有展示分离边界,但会显示 SVMs 判断分类标签的结果。正如你所见,线性内核函数完全忽略了红点,认为整个空间中只有黄点。而 RBF 内核函数则完整的为红点划出了两个圈
原创粉丝点击