添加 SVM 的通俗理解

This commit is contained in:
chenyyx
2017-08-09 16:48:40 +08:00
parent 1403f6f8f0
commit aa987f9eb3

View File

@@ -44,13 +44,13 @@ support vector (支持向量)的意思就是 <b>数据集中的某些点</b>
<b>不通俗的理解</b>
在 maximum margin (最大间隔)上的这些点就叫 “支持向量”,我想补充的是为啥这些点就叫 “支持向量” ,因为最后的 classification machine (分类器)的表达式里只含用这些 “支持向量” 的信息,而与其他数据点无关:
![支持向量机公式](/images/SVM/supportVector公式.jpg "supportVector公式")
![支持向量机公式](/images/6.SVM/supportVector公式.jpg "supportVector公式")
在这个表达式中,只有支持向量的系数 ![alphai](/images/SVM/alpha.png "alphai") 不等于 0 。
在这个表达式中,只有支持向量的系数 ![alphai](/images/6.SVM/alpha.png "alphai") 不等于 0 。
如果还是不怎么理解,不要紧,看下图:
![supportVector](/images/SVM/supportVector.png "supportVector")
![supportVector](/images/6.SVM/supportVector.png "supportVector")
“支持向量” 就是图中用紫色框框圈出来的点...
@@ -59,7 +59,7 @@ support vector (支持向量)的意思就是 <b>数据集中的某些点</b>
我们先看一张图
![supportVectorMachine](/images/SVM/svm_2.png "supportVectorMachine")
![supportVectorMachine](/images/6.SVM/svm_2.png "supportVectorMachine")
`linearly separable (线性可分)`: 如上图中的两组数据,它们之间已经分的足够开了,因此很容易就可以在图中画出一条直线将两组数据点分开。在这种情况下,这组数据就被称为<b>线性可分数据</b>。
@@ -87,35 +87,35 @@ support vector (支持向量)的意思就是 <b>数据集中的某些点</b>
魔鬼在桌子上似乎有规律放了两种颜色的球,说:“你用一根棍分开它们?要求:尽量在放更多球之后,仍然适用。”
![story_1](/images/SVM/story_1.png "story_1")
![story_1](/images/6.SVM/story_1.png "story_1")
于是大侠这样放,干的不错?
![story_2](/images/SVM/story_2.png "story_2")
![story_2](/images/6.SVM/story_2.png "story_2")
然后魔鬼,又在桌上放了更多的球,似乎有一个球站错了阵营。
![story_3](/images/SVM/story_3.png "story_3")
![story_3](/images/6.SVM/story_3.png "story_3")
SVM 就是试图把棍放在最佳位置,好让在棍的两边有尽可能大的间隙。
![story_4](/images/SVM/story_4.png "story_4")
![story_4](/images/6.SVM/story_4.png "story_4")
现在即使魔鬼放了更多的球,棍仍然是一个好的分界线。
![story_5](/images/SVM/story_5.png "story_5")
![story_5](/images/6.SVM/story_5.png "story_5")
然后,在 SVM 工具箱中有另一个更加重要的 trick。 魔鬼看到大侠已经学会了一个 trick ,于是魔鬼给了大侠一个新的挑战。
![story_6](/images/SVM/story_6.png "story_6")
![story_6](/images/6.SVM/story_6.png "story_6")
现在,大侠没有棍可以很好帮他分开两种球了,现在怎么办呢?当然像所有武侠片中一样大侠桌子一拍,球飞到空中。然后,凭借大侠的轻功,大侠抓起一张纸,插到了两种球的中间。
![story_7](/images/SVM/story_7.png "story_7")
![story_7](/images/6.SVM/story_7.png "story_7")
现在,从魔鬼的角度看这些球,这些球看起来像是被一条曲线分开了。
![story_8](/images/SVM/story_8.png "story_8")
![story_8](/images/6.SVM/story_8.png "story_8")
再之后,无聊的大人们,把这些球叫做 <b>「data」</b>,把棍子叫做 <b>「classifier」</b>, 最大间隙 trick 叫做<b>「optimization」</b> 拍桌子叫做<b>「kernelling」</b>, 那张纸叫做<b>「hyperplane」</b> 。
@@ -162,11 +162,11 @@ d<D,米粒
如图的例子训练集红色点是我们已知的分类1训练集蓝色点是已知的分类2我们想寻找一个分界超平面图中绿线因为示例是二维数据点所以只是一条线如果数据是三维的就是平面如果是三维以上就是超平面把这两类完全分开这样的话再来一个样本点需要我们预测的话我们就可以根据这个分界超平面预测出分类结果。
![hu_1](/images/SVM/hu_1.jpg "hu_1")
![hu_1](/images/6.SVM/hu_1.jpg "hu_1")
那我们如何选择这个分类超平面呢?从数学上说,超平面的公式是,也就是说如何选取这个 ![w](/images/SVM/w.png "w")(是个向量)。
那我们如何选择这个分类超平面呢?从数学上说,超平面的公式是,也就是说如何选取这个 ![w](/images/6.SVM/w.png "w")(是个向量)。
传统方法是根据最小二乘错误法least squared error首先随便定选取一个随机平面也就是随机选取 ![w](/images/SVM/w.png "w") 和 ![b](/images/SVM/b.png "b"),然后想必会在训练集中产生大量的错误分类,也就是说,![wtx+b](/images/SVM/hu_5.png "wtx+b") 结果应该大于 0 的时候小于 0 ,应该小于 0 的时候大于 0 。这时候有一个错误损失也就是说对于所有错误的分类他们的平方和least squared error 为: ![平方和](/images/SVM/hu_8.png "平方和") , 最小二乘法的目标就是让这个值趋于最小,对 ![w](/images/SVM/w.png "w") 求导取 0 ,采用梯度下降算法,可以求出错误平方和的极值,求出最优的 ![w](/images/SVM/w.png "w") ,也就是求出最优的超平面。(可以证明,如果基函数是指数族函数,求出的超平面是全局最优的)。
传统方法是根据最小二乘错误法least squared error首先随便定选取一个随机平面也就是随机选取 ![w](/images/6.SVM/w.png "w") 和 ![b](/images/6.SVM/b.png "b"),然后想必会在训练集中产生大量的错误分类,也就是说,![wtx+b](/images/6.SVM/hu_5.png "wtx+b") 结果应该大于 0 的时候小于 0 ,应该小于 0 的时候大于 0 。这时候有一个错误损失也就是说对于所有错误的分类他们的平方和least squared error 为: ![平方和](/images/6.SVM/hu_8.png "平方和") , 最小二乘法的目标就是让这个值趋于最小,对 ![w](/images/6.SVM/w.png "w") 求导取 0 ,采用梯度下降算法,可以求出错误平方和的极值,求出最优的 ![w](/images/6.SVM/w.png "w") ,也就是求出最优的超平面。(可以证明,如果基函数是指数族函数,求出的超平面是全局最优的)。
那我们 SVM 算法的思路是怎样的呢?
@@ -174,7 +174,7 @@ d<D,米粒
第一,它 “夹” 在两类样本点之间;第二,它离两类样本点中所有 “离它最近的点” ,都离它尽可能的远。如图所示:
![hu_2](/images/SVM/hu_2.jpg "hu_2")
![hu_2](/images/6.SVM/hu_2.jpg "hu_2")
在虚线上的点就是我们所找到的离分解超平面最近的样本点X 类中找到了一个O 类找到了两个。我们需要分类超平面离这三个样本点都尽可能的远,也就是说,它处在两条虚线的中间。这就是我们找到的分界超平面。
@@ -184,13 +184,13 @@ d<D,米粒
首先我们需要把刚刚说的最大间隔分类器的思想用数学公式表达出来。先定义几何间隔的概念,几何间隔就是在多维空间中一个多维点到一个超平面的距离,根据向量的知识可以算出来:
![hu_3](/images/SVM/hu_3.png "hu_3")
![hu_3](/images/6.SVM/hu_3.png "hu_3")
然后对于所有的支持向量,使他们到超平面 ![hu_5](/images/SVM/hu_5.png "hu_5") 的距离最大,也就是
然后对于所有的支持向量,使他们到超平面 ![hu_5](/images/6.SVM/hu_5.png "hu_5") 的距离最大,也就是
![hu_4](/images/SVM/hu_4.png "hu_4")
![hu_4](/images/6.SVM/hu_4.png "hu_4")
因为对于所有支持向量,他们 ![hu_5](/images/SVM/hu_5.png "hu_5") 的值都是一定的,我们假设恒等于 1 ,那么上式变成了 ![hu_6](/images/SVM/hu_6.png "hu_6") ,并且对于所有的样本点,满足 ![hu_10](/images/SVM/hu_10.png "hu_10") 的约束,因此,可以利用拉格朗日乘数法计算出它的极值。也就是求出这个超平面。
因为对于所有支持向量,他们 ![hu_5](/images/6.SVM/hu_5.png "hu_5") 的值都是一定的,我们假设恒等于 1 ,那么上式变成了 ![hu_6](/images/6.SVM/hu_6.png "hu_6") ,并且对于所有的样本点,满足 ![hu_10](/images/6.SVM/hu_10.png "hu_10") 的约束,因此,可以利用拉格朗日乘数法计算出它的极值。也就是求出这个超平面。
推导过程略为复杂,详细了解可以参考凸二次规划知识,结合 SMO 算法理解 SVM 计算超平面的详细过程。
@@ -203,13 +203,13 @@ d<D,米粒
* 左边是求解基本的SVM问题
* 右边是相关扩展
![k_1](/images/SVM/k_1.jpg "k_1")
![k_1](/images/6.SVM/k_1.jpg "k_1")
<b>什么是 SVM </b>
Support Vector Machine, 一个普通的 SVM 就是一条直线罢了,用来完美划分 linearly separable 的两类。但这又不是一条普通的直线,这是无数条可以分类的直线当中最完美的,因为它恰好在两个类的中间,距离两个类的点都一样远。而所谓的 Support vector 就是这些离分界线最近的『点』。如果去掉这些点,直线多半是要改变位置的。可以说是这些 vectors (主,点点) support (谓,定义)了 machine (宾,分类器)...
![k_2](/images/SVM/k_2.jpg "k_2")
![k_2](/images/6.SVM/k_2.jpg "k_2")
所以谜底就在谜面上啊朋友们,只要找到了这些最靠近的点不就找到了 SVM 了嘛。
@@ -223,45 +223,45 @@ Support Vector Machine, 一个普通的 SVM 就是一条直线罢了,用来完
于是自然而然可以得到重要表达 <b>I. direct representation</b>
![k_7](/images/SVM/k_7.png "k_7")
![k_7](/images/6.SVM/k_7.png "k_7")
(可以把 margin 看作是 boundary 的函数,并且想要找到使得是使得 margin 最大化的boundary而 margin(*) 这个函数是:输入一个 boundary ,计算(正确分类的)所有苹果和香蕉中,到 boundary 的最小距离。)
又有最大又有最小看起来好矛盾。实际上『最大』是对这个整体使用不同 boundary 层面的最大,『最小』是在比较『点』的层面上的最小。外层在比较 boundary 找最大的 margin ,内层在比较点点找最小的距离。
其中距离,说白了就是点到直线的距离;只要定义带正负号的距离,是 {苹果+1} 面为正 {香蕉-1} 面为负的距离,互相乘上各自的 label ![k_8](/images/SVM/k_8.png "k_8") ,就和谐统一民主富强了。
其中距离,说白了就是点到直线的距离;只要定义带正负号的距离,是 {苹果+1} 面为正 {香蕉-1} 面为负的距离,互相乘上各自的 label ![k_8](/images/6.SVM/k_8.png "k_8") ,就和谐统一民主富强了。
![k_9](/images/SVM/k_9.png "k_9")
![k_9](/images/6.SVM/k_9.png "k_9")
到这里为止已经说完了所有关于SVM的直观了解如果不想看求解可以跳过下面一大段直接到 objective function 。
直接表达虽然清楚但是求解无从下手。做一些简单地等价变换(分母倒上来)可以得到 <b>II. canonical representation </b> (敲黑板)
![k_10](/images/SVM/k_10.png "k_10")
![k_10](/images/6.SVM/k_10.png "k_10")
要得到 <b>III. dual representation</b> 之前需要大概知道一下拉格朗日乘子法 (method of lagrange multiplier),它是用在有各种约束条件(各种 "subject to" )下的目标函数,也就是直接可以求导可以引出 dual representation怎么还没完摔
![k_11](/images/SVM/k_11.png "k_11")
![k_11](/images/6.SVM/k_11.png "k_11")
稍微借用刚刚数学表达里面的内容看个有趣的东西:
还记得我们怎么预测一个新的水果是苹果还是香蕉吗?我们代入到分界的直线里,然后通过符号来判断。
刚刚w已经被表达出来了也就是说这个直线现在变成了 ![k_12](/images/SVM/k_12.png "k_12")
刚刚w已经被表达出来了也就是说这个直线现在变成了 ![k_12](/images/6.SVM/k_12.png "k_12")
看似仿佛用到了所有的训练水果,但是其中 ![k_13](/images/SVM/k_13.png "k_13") 的水果都没有起到作用,剩下的就是小部分靠边边的 Support vectors 呀。
看似仿佛用到了所有的训练水果,但是其中 ![k_13](/images/6.SVM/k_13.png "k_13") 的水果都没有起到作用,剩下的就是小部分靠边边的 Support vectors 呀。
<b>III. dual representation</b>
![k_14](/images/SVM/k_14.png "k_14")
![k_14](/images/6.SVM/k_14.png "k_14")
<b>如果香蕉和苹果不能用直线分割呢?</b>
![k_3](/images/SVM/k_3.jpg "k_3")
![k_3](/images/6.SVM/k_3.jpg "k_3")
Kernel trick.
其实用直线分割的时候我们已经使用了 kernel ,那就是线性 kernel , ![k_15](/images/SVM/k_15.png "k_15")
其实用直线分割的时候我们已经使用了 kernel ,那就是线性 kernel , ![k_15](/images/6.SVM/k_15.png "k_15")
如果要替换 kernel 那么把目标函数里面的内积全部替换成新的 kernel function 就好了,就是这么简单。
@@ -269,13 +269,13 @@ Kernel trick.
<b>如果香蕉和苹果有交集呢?</b>
![k_4](/images/SVM/k_4.jpg "k_4")
![k_4](/images/6.SVM/k_4.jpg "k_4")
![k_16](/images/SVM/k_16.png "k_16")
![k_16](/images/6.SVM/k_16.png "k_16")
<b>如果还有梨呢?</b>
![k_5](/images/SVM/k_5.jpg "k_5")
![k_5](/images/6.SVM/k_5.jpg "k_5")
可以每个类别做一次 SVM是苹果还是不是苹果是香蕉还是不是香蕉是梨子还是不是梨子从中选出可能性最大的。这是 one-versus-the-rest approach。
@@ -289,7 +289,7 @@ Kernel trick.
<p>最后送一张图我好爱哈哈哈 (Credit: Burr Settles)</p>
![k_6](/images/SVM/k_6.png "k_6")
![k_6](/images/6.SVM/k_6.png "k_6")
<p>[1] Bishop C M. Pattern recognition[J]. Machine Learning, 2006, 128.</p>
<p>[2] Friedman J, Hastie T, Tibshirani R. The elements of statistical learning[M]. Springer, Berlin: Springer series in statistics, 2001.</p>
@@ -311,7 +311,7 @@ Kernel trick.
SVM 的基本原理基本上已经说的差不多了,下面咱们就来看看 SVM 在实际应用该如何使用了。幸运的是,在 python 下面sklearn 提供了一个非常好用的机器学习算法,我们调用相关的包就好啦。
![sklearn_map](/images/SVM/ml_map.png "sklearn")
![sklearn_map](/images/6.SVM/ml_map.png "sklearn")
## 小结