支持向量机理论与代码简析

SVM简介

在机器学习中,支援向量机(support vector machine)是在分类与回归分析中分析数据的监督式学习模型与相关的学习算法。给定一组训练实例,每个训练实例被标记为属于两个类别中的一个或另一个,SVM训练算法建立一个将新的实例分配给两个类别之一的模型,使其成为非概率二元线性分类器。

除了进行线性分类之外,SVM还可以使用所谓的核技巧(kernel trick)有效地进行非线性分类,将其输入隐式映射到高维特征空间中。

SVM基本型

给定训练集样本 D = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , ⋯   , ( x m , y m ) } , y i ∈ { − 1 , + 1 } D=\{(x_1,y_1),(x_2,y_2),\cdots,(x_m,y_m)\},y_i \in\{-1,+1\} D={ (x1,y1),(x2,y2),,(xm,ym)},yi{ 1,+1}。分类学习基本想法是基于训练集 D D D在样本空间找到一个划分超平面。

在样本空间,划分超平面可以通过线性方程来描述
w T x + b = 0 w^Tx+b=0 wTx+b=0

其中 w = [ w 0 w 1 ⋮ w d ] w=\begin{bmatrix}w_0 \\ w_1 \\ \vdots \\ w_d \end{bmatrix} w=w0w1wd为法向量,决定了超平面的方向; b b b为位移项,决定超平面与原点距离。
显然,超平面由 w w w b b b决定。因此,问题变成:根据训练集样本去求解 w w w b b b

如何求解样本空间中任意一点 x x x到超平面的距离? 为什么需要距离后续会解释。

考虑超平面上一点 x ′ x' x,则必然满足超平面方程: w T x ′ + b = 0 w^Tx'+b=0 wTx+b=0,则空间中任意一点 x x x到超平面的距离为 x x x x ′ x' x两点构成的向量在法向量 w w w上的投影,那么只要将法向量的单位向量与 ( x − x ′ ) (x-x') (xx)向量求内积再取模即可:
r = ∣ w ∥ w ∥ ⋅ ( x − x ′ ) ∣ = ∣ w T x + b ∣ ∥ w ∥ r=|\frac{w}{\|w\|}\cdot(x-x')|=\frac{|w^Tx+b|}{\|w\|} r=ww(xx)=wwTx+b

此时,假设超平面 ( w , b ) (w,b) (w,b)可将样本分开。那么对于 ( x i , y i ) ∈ D (x_i,y_i)\in D (xi,yi)D,若 y i = + 1 y_i=+1 yi=+1 w T x i + b > 0 w^Tx_i+b>0 wTxi+b>0 y i = − 1 y_i=-1 yi=1 w T x i + b < 0 w^Tx_i+b<0 wTxi+b<0但是!真正鲁棒的超平面应当很好区分开样本,令
{ w T x i + b ⩾ + 1 , y i = + 1 w T x i + b ⩽ − 1 , y i = − 1 \begin{cases} \begin{aligned} w^Tx_i+b\geqslant+1,\enspace y_i=+1\\ w^Tx_i+b\leqslant-1,\enspace y_i=-1 \end{aligned} \end{cases} { wTxi+b+1,yi=+1wTxi+b1,yi=1

如图1所示,距离超平面最近的这几个样本点使得上式等号成立。它们被称为"支持向量"。两个异类支持向量到超平面的距离之和为
γ = 2 ∥ w ∥ \gamma=\frac{2}{\|w\|} γ=w2

这被称为"间隔"。
在这里插入图片描述

图1. 支持向量与间隔

间隔 γ \gamma γ是我们的优化目标,即问题转换成:找到 w w w b b b,使得 γ \gamma γ最大。
max ⁡ w , b 2 ∥ w ∥ s . t . y i ( w T x i + b ) ⩾ 1 , i = 1 , 2 , ⋯   , m \begin{aligned} &\max_{w,b}\frac{2}{\|w\|} \\\\ &s.t. \enspace y_i(w^Tx_i+b)\geqslant1 , i=1,2,\cdots,m \end{aligned} w,bmaxw2s.t.yi(wTxi+b)1,i=1,2,,m

扫描二维码关注公众号,回复: 14465501 查看本文章

优化问题中最大化某个函数都会被转换成最小化
min ⁡ w , b 1 2 ∥ w ∥ 2 s . t . y i ( w T x i + b ) ⩾ 1 , i = 1 , 2 , ⋯   , m \begin{aligned} &\min_{w,b}\frac{1}{2}\|w\|^2 \\\\ &s.t. \enspace y_i(w^Tx_i+b)\geqslant1 , i=1,2,\cdots,m \end{aligned} w,bmin21w2s.t.yi(wTxi+b)1,i=1,2,,m

对偶问题

如何求解上述最优化问题? → \to 拉格朗日乘子法

对每条约束施加拉格朗日乘子 α i ⩾ 0 \alpha_i\geqslant0 αi0,则该问题的拉格朗日函数为
L ( w , b , α ) = 1 2 ∥ w ∥ 2 + ∑ i = 1 m α i ( 1 − y i ( w T x i + b ) ) L(w,b,\alpha)=\frac{1}{2}\|w\|^2+\sum_{i=1}^m\alpha_i(1-y_i(w^Tx_i+b)) L(w,b,α)=21w2+i=1mαi(1yi(wTxi+b))

其中, α = ( α 1 ; α 2 ; ⋯   ; α m ) 。 \alpha=(\alpha_1;\alpha_2;\cdots;\alpha_m)。 α=(α1;α2;;αm) L ( w , b , α ) L(w,b,\alpha) L(w,b,α) w w w b b b分别求偏导,得

∂ x T x x = 2 x \frac{\partial{x^Tx}}{x}=2x xxTx=2x

∂ L ∂ w = w − ∑ i = 1 m α i y i x i = 0 ∂ L ∂ b = ∑ i = 1 m α i y i = 0 \begin{aligned} &\frac{\partial{L}}{\partial{w}}=w-\sum_{i=1}^{m}\alpha_iy_ix_i=0\\ &\frac{\partial{L}}{\partial{b}}=\sum_{i=1}^{m}\alpha_iy_i=0 \end{aligned} wL=wi=1mαiyixi=0bL=i=1mαiyi=0

由此,可得
w = ∑ i = 1 m α i y i x i ∑ i = 1 m α i y i = 0 \begin{aligned} &w=\sum_{i=1}^{m}\alpha_iy_ix_i\\ &\sum_{i=1}^{m}\alpha_iy_i=0 \end{aligned} w=i=1mαiyixii=1mαiyi=0

此时,有两点值得思考:

  • b b b求偏导时,结果中没有 b b b项,自然无法用 α i \alpha_i αi来表示 b b b,难道就无法解出 b b b吗?
  • w w w的结果可以看出, x x x是多少维的,自然 w w w的维数与 x x x是一样的。

w w w α i \alpha_i αi表达的式子回代到 L ( w , b , α ) L(w,b,\alpha) L(w,b,α)中,可得对偶问题
max ⁡ α ∑ i = 1 m α i − 1 2 ∑ i = 1 m ∑ j = 1 m α i α j y i y j x i T x j s . t . ∑ i = 1 m α i y i = 0 , α i ⩾ 0 , i = 1 , 2 , ⋯   , m \begin{aligned} &\max_{\alpha}\enspace\sum_{i=1}^{m}\alpha_i-\frac{1}{2}\sum_{i=1}^{m}\sum_{j=1}^{m}\alpha_i\alpha_jy_iy_jx_i^Tx_j \\\\ &s.t.\sum_{i=1}^{m}\alpha_iy_i=0, \enspace \alpha_i\geqslant0, \enspace i=1,2,\cdots,m \end{aligned} αmaxi=1mαi21i=1mj=1mαiαjyiyjxiTxjs.t.i=1mαiyi=0,αi0,i=1,2,,m

按照套路,求极大值一般转换为求极小值
min ⁡ α 1 2 ∑ i = 1 m ∑ j = 1 m α i α j y i y j x i T x j − ∑ i = 1 m α i s . t . ∑ i = 1 m α i y i = 0 , α i ⩾ 0 , i = 1 , 2 , ⋯   , m \begin{aligned} &\min_{\alpha}\enspace\frac{1}{2}\sum_{i=1}^{m}\sum_{j=1}^{m}\alpha_i\alpha_jy_iy_jx_i^Tx_j-\sum_{i=1}^{m}\alpha_i \\\\ &s.t.\sum_{i=1}^{m}\alpha_iy_i=0, \enspace \alpha_i\geqslant0, \enspace i=1,2,\cdots,m \end{aligned} αmin21i=1mj=1mαiαjyiyjxiTxji=1mαis.t.i=1mαiyi=0,αi0,i=1,2,,m
解出 α \alpha α后,即可求得 w w w b b b

至此,似乎只要解出 α \alpha α,该问题自然就迎刃而解了,即可得到模型
f ( x ) = w T x + b = ∑ i = 1 m α i y i x i T x + b f(x)=w^Tx+b=\sum_{i=1}^{m}\alpha_iy_ix_i^Tx+b f(x)=wTx+b=i=1mαiyixiTx+b

但,其中由于不等式约束的存在,必须满足KKT条件,即
{ α i ⩾ 0 y i f ( x i ) − 1 ⩾ 0 α i ( y i f ( x i ) − 1 ) = 0 \begin{cases} \begin{aligned} &\alpha_i\geqslant0\\ &y_if(x_i)-1\geqslant0\\ &\alpha_i(y_if(x_i)-1)=0 \end{aligned} \end{cases} αi0yif(xi)10αi(yif(xi)1)=0

KKT条件具体我也不懂,略过。

如何求解该对偶问题呢? 先举一个简单例子。

有三个数据点:正例 x 1 = ( 3 , 3 ) , x 2 = ( 4 , 3 ) x_1=(3,3),x_2=(4,3) x1=(3,3),x2=(4,3),负例 x 3 = ( 1 , 1 ) x_3=(1,1) x3=(1,1)SVM该如何将它们区分开呢?由上所述,可归纳为求解对偶问题:
min ⁡ α 1 2 ∑ i = 1 3 ∑ j = 1 3 α i α j y i y j x i T x j − ∑ i = 1 3 α i s . t . α 1 + α 2 − α 3 = 0 , α i ⩾ 0 , i = 1 , 2 , 3 \begin{aligned} &\min_{\alpha}\enspace\frac{1}{2}\sum_{i=1}^{3}\sum_{j=1}^{3}\alpha_i\alpha_jy_iy_jx_i^Tx_j-\sum_{i=1}^{3}\alpha_i \\\\ &s.t.\enspace\alpha_1+\alpha_2-\alpha_3=0, \enspace \alpha_i\geqslant0, \enspace i=1,2,3 \end{aligned} αmin21i=13j=13αiαjyiyjxiTxji=13αis.t.α1+α2α3=0,αi0,i=1,2,3

将数据进一步代入,可得
1 2 ( 18 α 1 2 + 25 α 2 2 + 2 α 3 2 + 42 α 1 α 2 − 12 α 1 α 3 − 14 α 2 α 3 ) − α 1 − α 2 − α 3 \frac{1}{2}(18\alpha_1^2+25\alpha_2^2+2\alpha_3^2+42\alpha_1\alpha_2-12\alpha_1\alpha_3-14\alpha_2\alpha_3)-\alpha_1-\alpha_2-\alpha_3 21(18α12+25α22+2α32+42α1α212α1α314α2α3)α1α2α3

由于: α 1 + α 2 − α 3 = 0 \alpha_1+\alpha_2-\alpha_3=0 α1+α2α3=0,化简可得: 4 α 1 2 + 13 2 α 2 2 + 10 α 1 α 2 − 2 α 1 − 2 α 2 4\alpha_1^2+\frac{13}{2}\alpha_2^2+10\alpha_1\alpha_2-2\alpha_1-2\alpha_2 4α12+213α22+10α1α22α12α2

分别对 α 1 \alpha_1 α1 α 2 \alpha_2 α2求偏导,得
{ α 1 = 1.5 α 2 = − 1 { α 1 = 0 α 2 = − 2 / 13 { α 1 = 0.25 α 2 = 0 \begin{cases} \begin{aligned} &\alpha_1=1.5\\ &\alpha_2=-1\\ \end{aligned} \end{cases} \enspace \begin{cases} \begin{aligned} &\alpha_1=0\\ &\alpha_2=-2/13\\ \end{aligned} \end{cases} \enspace \begin{cases} \begin{aligned} &\alpha_1=0.25\\ &\alpha_2=0\\ \end{aligned} \end{cases} { α1=1.5α2=1{ α1=0α2=2/13{ α1=0.25α2=0

只有第三个解满足条件,因此目标函数最小值在 ( 0.25 , 0 , 0.25 ) (0.25,0,0.25) (0.25,0,0.25)处取得。

α \alpha α代回,可得 w w w b b b
w = ∑ i = 1 3 α i y i x i = 0.25 × 1 × ( 3 , 3 ) + 0 + 0.25 × ( − 1 ) × ( 1 , 1 ) = ( 0.5 , 0.5 ) w=\sum_{i=1}^{3}\alpha_iy_ix_i=0.25\times1\times(3,3)+0+0.25\times(-1)\times(1,1)=(0.5,0.5) w=i=13αiyixi=0.25×1×(3,3)+0+0.25×(1)×(1,1)=(0.5,0.5)
这里重点回答前面的一个疑问:为什么 b b b可以解出来?

因为,支持向量的正样本点在最大间隔边界上,满足方程 w T x + b = 1 w^Tx+b=1 wTx+b=1;同理,负样本点的支持向量满足 w T x + b = − 1 w^Tx+b=-1 wTx+b=1
b = y i − ∑ i = 1 3 α i y i x i T x = 1 − ( 0.25 × 1 × ( 3 × 3 + 3 × 3 ) + 0.25 × ( − 1 ) × ( 1 × 3 + 1 × 3 ) ) = − 2 b=y_i-\sum_{i=1}^{3}\alpha_iy_ix_i^Tx=1-(0.25\times1\times(3\times3+3\times3)+0.25\times(-1)\times(1\times3+1\times3))=-2 b=yii=13αiyixiTx=1(0.25×1×(3×3+3×3)+0.25×(1)×(1×3+1×3))=2
因此,平面方程为: 0.5 x 1 + 0.5 x 2 − 2 = 0 0.5x_1+0.5x_2-2=0 0.5x1+0.5x22=0

由此,可以看出:最大间隔边界上 α \alpha α值不为零的样本点,称为支持向量,而非边界上的样本点其 α \alpha α值必然为零。这显示出支持向量机的一个核心性质:训练完成后,大部分的训练样本不需要保留,最终模型仅与支持向量有关。

对于更一般的问题,当样本数较多且样本属性较多时,求解最优化的问题规模正比于训练样本数。此时,建议使用SMO算法来求解。

核函数

之前在样本空间中寻找超平面时,有一个前提是:在原始样本空间中存在一个划分超平面,可将训练样本正确分类。那若是假设不成立,即在原始样本空间中找不到这样一个划分超平面,该如何处理分类问题呢?

在这里插入图片描述

图2. 非线性映射

对于这样的问题,可将样本从原始空间映射到一个更高维的特征空间,使得样本在这个特征空间内线性可分。例如,在图2中,若将原始的二维空间映射到一个合适的三维空间,就能找到一个划分超平面。

ϕ ( x ) \phi(x) ϕ(x)表示将 x x x映射后的特征向量,则在特征空间中划分超平面的模型表示为:
f ( x ) = w T ϕ ( x ) + b f(x)=w^T\phi(x)+b f(x)=wTϕ(x)+b

同理,可得优化方程为
min ⁡ w , b 1 2 ∥ w ∥ 2 s . t . y i ( w T ϕ ( x i ) + b ) ⩾ 1 , i = 1 , 2 , ⋯   , m \begin{aligned} & \min_{w,b}\frac{1}{2}\|w\|^2 \\\\ & s.t. \enspace y_i(w^T\phi(x_i)+b)\geqslant1 , i=1,2,\cdots,m \end{aligned} w,bmin21w2s.t.yi(wTϕ(xi)+b)1,i=1,2,,m

使用拉格朗日乘子法,其对偶问题为
min ⁡ α 1 2 ∑ i = 1 m ∑ j = 1 m α i α j y i y j ϕ ( x i ) T ϕ ( x j ) − ∑ i = 1 m α i s . t . ∑ i = 1 m α i y i = 0 , α i ⩾ 0 , i = 1 , 2 , ⋯   , m \begin{aligned} &\min_{\alpha}\enspace\frac{1}{2}\sum_{i=1}^{m}\sum_{j=1}^{m}\alpha_i\alpha_jy_iy_j\phi(x_i)^T\phi(x_j)-\sum_{i=1}^{m}\alpha_i \\\\ &s.t.\sum_{i=1}^{m}\alpha_iy_i=0, \enspace \alpha_i\geqslant0, \enspace i=1,2,\cdots,m \end{aligned} αmin21i=1mj=1mαiαjyiyjϕ(xi)Tϕ(xj)i=1mαis.t.i=1mαiyi=0,αi0,i=1,2,,m

求解该问题会涉及到 ϕ ( x i ) T ϕ ( x j ) \phi(x_i)^T\phi(x_j) ϕ(xi)Tϕ(xj),这是样本 x i x_i xi x j x_j xj映射到特征空间后的内积。一般来说,直接计算 ϕ ( x i ) T ϕ ( x j ) \phi(x_i)^T\phi(x_j) ϕ(xi)Tϕ(xj)会很困难,因此引入一个函数
κ ( x i , x j ) = ⟨ ϕ ( x i ) , ϕ ( x j ) ⟩ = ϕ ( x i ) T ϕ ( x j ) \kappa(x_i,x_j)=\langle\phi(x_i),\phi(x_j)\rangle=\phi(x_i)^T\phi(x_j) κ(xi,xj)=ϕ(xi),ϕ(xj)=ϕ(xi)Tϕ(xj)

x i x_i xi x j x_j xj在特征空间的内积等于它们在原始样本空间中通过函数 κ ( ⋅ , ⋅ ) \kappa(\cdot,\cdot) κ(,)计算的结果。若是存在这样的函数,则省去计算高维特征空间中的内积。这里 κ ( ⋅ , ⋅ ) \kappa(\cdot,\cdot) κ(,)就是核函数。

依旧插播一个小例子来通俗解释核函数的好处

假设我们有两个数据, x = ( x 1 , x 2 , x 3 ) , y = ( y 1 , y 2 , y 3 ) x=(x_1,x_2,x_3),y=(y_1,y_2,y_3) x=(x1,x2,x3)y=(y1,y2,y3),此时3D空间中已经不能进行线性划分了。那么我们通过一个函数将数据映射到更高维的空间,比如9维的话,那么 f ( x ) = ( x 1 x 1 , x 1 x 2 , x 1 x 3 , x 2 x 1 , x 2 x 2 , x 2 x 3 , x 3 x 1 , x 3 x 2 , x 3 x 3 ) f(x)=(x_1x_1,x_1x_2,x_1x_3,x_2x_1,x_2x_2,x_2x_3,x_3x_1,x_3x_2,x_3x_3) f(x)=(x1x1,x1x2,x1x3,x2x1,x2x2,x2x3,x3x1,x3x2,x3x3),由于需要计算内积,所以新的数据在9维空间,需要计算 ⟨ f ( x ) , f ( y ) ⟩ \langle f(x),f(y)\rangle f(x),f(y)的内积,花费 O ( n 2 ) O(n^2) O(n2)

具体来讲,令 x = ( 1 , 2 , 3 ) , y = ( 4 , 5 , 6 ) x=(1,2,3),y=(4,5,6) x=(1,2,3)y=(4,5,6),那么 f ( x ) = ( 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ) f(x)=(1,2,3,4,5,6,7,8,9) f(x)=(1,2,3,4,5,6,7,8,9) f ( x ) = ( 16 , 20 , 24 , 20 , 25 , 36 , 24 , 30 , 36 ) f(x)=(16,20,24,20,25,36,24,30,36) f(x)=(16,20,24,20,25,36,24,30,36)

此时, ⟨ f ( x ) , f ( y ) ⟩ = 16 + 40 + 72 + 40 + 100 + 180 + 72 + 180 + 324 = 1024 \langle f(x),f(y)\rangle=16+40+72+40+100+180+72+180+324=1024 f(x),f(y)=16+40+72+40+100+180+72+180+324=1024

但是,发现 κ ( x , y ) = ( ⟨ x , y ⟩ ) 2 = ( 4 + 10 + 18 ) 2 = 1024 \kappa(x,y)=(\langle x,y\rangle)^2=(4+10+18)^2=1024 κ(x,y)=(x,y)2=(4+10+18)2=1024居然是一样的

因此, κ ( x , y ) \kappa(x,y) κ(x,y)计算比 ⟨ f ( x ) , f ( y ) ⟩ \langle f(x),f(y)\rangle f(x),f(y)简单得多,使用核函数的好处是:在低维空间去完成高维空间样本内积的计算。

有了这样的核函数后,我们避开了直接计算高维空间中的内积。从而优化问题改写成
min ⁡ α 1 2 ∑ i = 1 m ∑ j = 1 m α i α j y i y j κ ( x i , x j ) − ∑ i = 1 m α i s . t . ∑ i = 1 m α i y i = 0 , α i ⩾ 0 , i = 1 , 2 , ⋯   , m \begin{aligned} &\min_{\alpha}\enspace\frac{1}{2}\sum_{i=1}^{m}\sum_{j=1}^{m}\alpha_i\alpha_jy_iy_j\kappa(x_i,x_j)-\sum_{i=1}^{m}\alpha_i \\\\ &s.t.\sum_{i=1}^{m}\alpha_iy_i=0, \enspace \alpha_i\geqslant0, \enspace i=1,2,\cdots,m \end{aligned} αmin21i=1mj=1mαiαjyiyjκ(xi,xj)i=1mαis.t.i=1mαiyi=0,αi0,i=1,2,,m

求解后,得到 w w w b b b
f ( x ) = w T ϕ ( x ) + b = ∑ i = 1 m α i y i ϕ ( x i ) T ϕ ( x ) + b = ∑ i = 1 m α i y i κ ( x , x i ) + b f(x)=w^T\phi(x)+b=\sum_{i=1}^{m}\alpha_iy_i\phi(x_i)^T\phi(x)+b=\sum_{i=1}^{m}\alpha_iy_i\kappa(x,x_i)+b f(x)=wTϕ(x)+b=i=1mαiyiϕ(xi)Tϕ(x)+b=i=1mαiyiκ(x,xi)+b

若已知映射 ϕ ( ⋅ ) \phi(\cdot) ϕ()的具体形式,则可写出核函数 κ ( ⋅ , ⋅ ) \kappa(\cdot,\cdot) κ(,)。但一般不知道 ϕ ( ⋅ ) \phi(\cdot) ϕ()的具体形式,核函数是否一定存在?

事实上,任何一个核函数都隐式地定义了一个称为“再生核希尔伯特空间”的特征空间。而特征空间的好坏对于支持向量机的性能至关重要。因此,核函数的选择成为支持向量机的最大变数。常用的核函数为高斯核和多项式核。

名称 表达式
多项式核 κ ( x i , x j ) = ( x i T x j ) d \kappa(x_i,x_j)=(x_i^Tx_j)^d κ(xi,xj)=(xiTxj)d
高斯核 κ ( x i , x j ) = e x p ( − ∣ x i − x j ∣ 2 2 σ 2 ) \kappa(x_i,x_j)=exp(-\frac{| x_i-x_j|^2}{2\sigma^2}) κ(xi,xj)=exp(2σ2xixj2)

软间隔

在现实数据集中,通常会存在一个问题:数据中会存在一些噪音点,若是采用前面所述的支持向量机的形式会将所有样本严格区分开,你可能会想数据集中正负样本全部区分开这不是挺好的吗?但是一般若是真的使用“硬间隔”,即在训练集上所有样本均划分正确,此时的支持向量机会有过拟合的风险,导致模型泛化性能不佳。

为了解决该问题,可以允许支持向量机在一些样本上出错,因此,有了“软间隔”的概念。

软间隔允许某些样本不满足约束,引入松弛因子 ξ i ⩾ 0 \xi_i\geqslant0 ξi0
min ⁡ w , b , ξ i 1 2 ∥ w ∥ 2 + C ∑ i = 1 m ξ i s . t . y i ( w T ϕ ( x i ) + b ) ⩾ 1 − ξ i , ξ i ⩾ 0 , i = 1 , 2 , ⋯   , m \begin{aligned} & \min_{w,b,\xi_i}\frac{1}{2}\|w\|^2+C\sum_{i=1}^{m}\xi_i \\\\ & s.t. \enspace y_i(w^T\phi(x_i)+b)\geqslant1-\xi_i , \enspace\xi_i\geqslant0,\enspace i=1,2,\cdots,m \end{aligned} w,b,ξimin21w2+Ci=1mξis.t.yi(wTϕ(xi)+b)1ξi,ξi0,i=1,2,,m

使用拉格朗日乘子法得拉格朗日函数
L ( w , b , α , ξ , μ ) = 1 2 ∥ w ∥ 2 + C ∑ i = 1 m ξ i + ∑ i = 1 m α i ( 1 − ξ i − y i ( w T x i + b ) ) − ∑ i = 1 m μ i ξ i L(w,b,\alpha,\xi,\mu)=\frac{1}{2}\|w\|^2+C\sum_{i=1}^{m}\xi_i+\sum_{i=1}^{m}\alpha_i(1-\xi_i-y_i(w^Tx_i+b))-\sum_{i=1}^{m}\mu_i\xi_i L(w,b,α,ξ,μ)=21w2+Ci=1mξi+i=1mαi(1ξiyi(wTxi+b))i=1mμiξi

其中, α i ⩾ 0 , μ i ⩾ 0 \alpha_i\geqslant0,\mu_i\geqslant0 αi0,μi0是拉格朗日乘子。

L ( w , b , α , ξ , μ ) L(w,b,\alpha,\xi,\mu) L(w,b,α,ξ,μ) w , b , ξ i w,b,\xi_i w,b,ξi分别求偏导为零
∂ L ∂ w = w − ∑ i = 1 m α i y i x i = 0 ∂ L ∂ b = ∑ i = 1 m α i y i = 0 ∂ L ∂ ξ i = C − α i − μ i = 0 \begin{aligned} &\frac{\partial{L}}{\partial{w}}=w-\sum_{i=1}^{m}\alpha_iy_ix_i=0\\ &\frac{\partial{L}}{\partial{b}}=\sum_{i=1}^{m}\alpha_iy_i=0\\ &\frac{\partial{L}}{\partial{\xi_i}}=C-\alpha_i-\mu_i=0 \end{aligned} wL=wi=1mαiyixi=0bL=i=1mαiyi=0ξiL=Cαiμi=0

可得
w = ∑ i = 1 m α i y i x i ∑ i = 1 m α i y i = 0 C = α i + μ i \begin{aligned} &w=\sum_{i=1}^{m}\alpha_iy_ix_i\\ &\sum_{i=1}^{m}\alpha_iy_i=0\\ &C=\alpha_i+\mu_i \end{aligned} w=i=1mαiyixii=1mαiyi=0C=αi+μi

回代后,得软间隔支持向量机未引入核函数的优化方程
min ⁡ α 1 2 ∑ i = 1 m ∑ j = 1 m α i α j y i y j x i T x j − ∑ i = 1 m α i s . t . ∑ i = 1 m α i y i = 0 , 0 ⩽ α i ⩽ C , i = 1 , 2 , ⋯   , m \begin{aligned} &\min_{\alpha}\enspace\frac{1}{2}\sum_{i=1}^{m}\sum_{j=1}^{m}\alpha_i\alpha_jy_iy_jx_i^Tx_j-\sum_{i=1}^{m}\alpha_i \\\\ &s.t.\sum_{i=1}^{m}\alpha_iy_i=0, \enspace 0 \leqslant{\alpha_i}\leqslant{C}, \enspace i=1,2,\cdots,m \end{aligned} αmin21i=1mj=1mαiαjyiyjxiTxji=1mαis.t.i=1mαiyi=0,0αiC,i=1,2,,m

该优化目标同样可以引入核函数处理。

代码实战

数据集准备:鸢尾花数据集。可以从scikit-learn0.19中直接导入。

鸢尾花数据集共收集了三类鸢尾花,即Setosa鸢尾花、Versicolour鸢尾花和Virginica鸢尾花,每一类鸢尾花收集了50条样本记录,共计150条。数据集包括4个属性,分别为花萼的长、花萼的宽、花瓣的长和花瓣的宽。

线性可分支持向量机

import numpy as np
import matplotlib.pyplot as plt
from sklearn.svm import SVC
from sklearn import datasets
plt.rcParams['axes.labelsize'] = 14
plt.rcParams['xtick.labelsize'] = 12
plt.rcParams['ytick.labelsize'] = 12

iris = datasets.load_iris()  # 导入鸢尾花数据集
X = iris['data'][:, (2, 3)]  # 取后两种属性:petal length, petal width
y = iris['target']
# print(iris.target_names)

setosa_or_versicolor = (y == 0) | (y == 1)  # 三分类改成二分类
X = X[setosa_or_versicolor]
y = y[setosa_or_versicolor]

svm_clf = SVC(kernel="linear", C=float('inf'))  # 线性支持向量机
svm_clf.fit(X, y)  # 根据样本与标签训练支持向量机
print(svm_clf.predict([[4, 1]]))  # 根据训练好的模型做预测

# 一般的模型,用作与支持向量机做对比
x0 = np.linspace(0, 5.5, 200)
pred_1 = 5 * x0 - 20
pred_2 = x0 - 1.8
pred_3 = 0.1 * x0 + 0.5


# 画支持向量机的决策边界
# svm: 支持向量机模型
# xmin: 横轴最小值
# xmax:纵轴最大值
# sv: 是否画出支持向量
def plot_svc_boundary(svm, xmin, xmax, sv=True):
    w = svm.coef_[0]
    b = svm.intercept_[0]
    # print(w)
    # print(b)
    x = np.linspace(xmin, xmax, 200)
    # 样本属性二维时的决策方程:w1x1 + w2x2 + b = 0
    # x2 = -w1 / w2 * x1 - b / w2
    decision_boundary = -w[0] / w[1] * x - b / w[1]
    margin = 1 / w[1]
    gutter_up = decision_boundary + margin
    gutter_down = decision_boundary - margin
    if sv:
        svs = svm.support_vectors_
        # print(svs)
        plt.scatter(svs[:, 0], svs[:, 1], s=180, facecolors='#FFAAAA')  # 画支持向量点
    plt.plot(x0, decision_boundary, 'k-', linewidth=2)  # 画决策边界
    plt.plot(x0, gutter_up, 'k--', linewidth=2)  # 画两条最大间隔线
    plt.plot(x0, gutter_down, 'k--', linewidth=2)


plt.figure(figsize=(14, 4))
plt.subplot(121)
plt.plot(X[:, 0][y == 1], X[:, 1][y == 1], 'bs')
plt.plot(X[:, 0][y == 0], X[:, 1][y == 0], 'ys')
plt.plot(x0, pred_1, 'g--', linewidth=2)
plt.plot(x0, pred_2, 'm-', linewidth=2)
plt.plot(x0, pred_3, 'r-', linewidth=2)
plt.axis([0, 5.5, 0, 2])

plt.subplot(122)
plt.plot(X[:, 0][y == 1], X[:, 1][y == 1], 'bs')
plt.plot(X[:, 0][y == 0], X[:, 1][y == 0], 'ys')
plot_svc_boundary(svm_clf, 0, 5.5)
plt.axis([0, 5.5, 0, 2])
plt.show()

在这里插入图片描述

加入软间隔

一般数据集进行训练前需要进行数据标准化

import numpy as np
from sklearn import datasets
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import LinearSVC
import matplotlib.pyplot as plt

# 数据集导入并处理
iris = datasets.load_iris()
X = iris['data'][:, (2, 3)] # 只用150个样本中后两个属性:petal length, petal width
y = (iris['target'] == 2).astype(np.float64)  # 将原本第二类改为第一类

svm_clf = Pipeline(steps=[
    ('std', StandardScaler()),
    ('linear_svc', LinearSVC(C=1))
])
svm_clf.fit(X, y)
print(svm_clf.predict([[5.5, 1.7]]))

scaler = StandardScaler()  # 数据集相同,归一化处理结果是一样的
svm_clf1 = LinearSVC(C=1, random_state=42)
svm_clf2 = LinearSVC(C=100, random_state=42)

scaler_svm_clf1 = Pipeline(steps=[
    ('std', scaler),
    ('linear_svc', svm_clf1)
])
scaler_svm_clf2 = Pipeline(steps=[
    ('std', scaler),
    ('linear_svc', svm_clf2)
])

scaler_svm_clf1.fit(X, y)  # C=1   训练软间隔支持向量机
scaler_svm_clf2.fit(X, y)  # C=100 训练软间隔支持向量机

print(scaler.mean_)
print(scaler.scale_)


def plot_svc_decision_boundary(svm, xmin, xmax, sv=True):
    w = svm.coef_[0]
    b = svm.intercept_[0]
    # print(w)
    # print(b)
    x = np.linspace(xmin, xmax, 200)
    decision_boundary = -w[0] / w[1] * x - b / w[1]
    margin = 1 / w[1]
    gutter_up = decision_boundary + margin
    gutter_down = decision_boundary - margin
    if sv:
        svs = svm.support_vectors_
        # print(svs)
        plt.scatter(svs[:, 0], svs[:, 1], s=180, facecolors='#FFAAAA')  # 画支持向量点
    plt.plot(x, decision_boundary, 'k-', linewidth=2)  # 画决策边界
    plt.plot(x, gutter_up, 'k--', linewidth=2)  # 画两条最大间隔线
    plt.plot(x, gutter_down, 'k--', linewidth=2)


# 经归一化处理后的b和w得反变换回去
b1 = svm_clf1.decision_function([-scaler.mean_/scaler.scale_])
b2 = svm_clf2.decision_function([-scaler.mean_/scaler.scale_])
w1 = svm_clf1.coef_[0] / scaler.scale_
w2 = svm_clf2.coef_[0] / scaler.scale_
svm_clf1.intercept_ = np.array([b1])
svm_clf2.intercept_ = np.array([b2])
svm_clf1.coef_ = np.array([w1])
svm_clf2.coef_ = np.array([w2])

plt.figure(figsize=(14, 4))
plt.subplot(121)
plt.plot(X[:, 0][y == 1], X[:, 1][y == 1], "ys ", label="Iris-Virginica")
plt.plot(X[:, 0][y == 0], X[:, 1][y == 0], "bs", label="Iris-Versicolor")
plot_svc_decision_boundary(svm_clf1, 4, 6, sv=False)
plt.xlabel("Petal length", fontsize=14)
plt.ylabel("Petal width", fontsize=14)
plt.legend(loc="upper left", fontsize=14)
plt.title("$C = {}$".format(svm_clf1.C), fontsize=16)
plt.axis([4, 6, 0.8, 2.8])

plt.subplot(122)
plt.plot(X[:, 0][y == 1], X[:, 1][y == 1], "ys ", label="Iris-Virginica")
plt.plot(X[:, 0][y == 0], X[:, 1][y == 0], "bs", label="Iris-Versicolor")
plot_svc_decision_boundary(svm_clf2, 4, 6, sv=False)
plt.xlabel("Petal length", fontsize=14)
plt.ylabel("Petal width", fontsize=14)
plt.legend(loc="upper left", fontsize=14)
plt.title("$C = {}$".format(svm_clf2.C), fontsize=16)
plt.axis([4, 6, 0.8, 2.8])
plt.show()

在这里插入图片描述

非线性支持向量机

非线性SVM一方面可以直接对数据在样本空间做非线性变换,另一方面也可以通过核函数将数据映射到高维空间。

  • 直接对数据在样本空间做非线性变换

一维数据不可分,映射到二维可分

import numpy as np
import matplotlib.pyplot as plt

X1D = np.linspace(-4, 4, 9).reshape(-1, 1)
print(X1D)
X2D = np.c_[X1D, X1D**2]
print(X2D)
y = np.array([0, 0, 1, 1, 1, 1, 1, 0, 0])

# print(X1D[:, 0][y == 1])

print(X2D[:, 0])
print(X2D[:, 1])
print(X2D[:, 0][y == 0])
print(X2D[:, 1][y == 0])

plt.figure(figsize=(11, 4))
plt.subplot(121)
plt.grid(True, which='both')
plt.axhline(y=0, color='k')
plt.plot(X1D[:, 0][y == 0], np.zeros(4), "bs")
plt.plot(X1D[:, 0][y == 1], np.zeros(5), "g^")
plt.gca().get_yaxis().set_ticks([-2, -1, 0, 1, 2])
plt.xlabel(r"$x_1$", fontsize=20)
plt.ylabel(r"$x_2$", fontsize=20, rotation=0)
plt.axis([-4.5, 4.5, -2, 2])

plt.subplot(122)
plt.grid(True, which='both')
plt.axhline(y=0, color='k')
plt.axvline(x=0, color='k')
plt.plot(X2D[:, 0][y == 0], X2D[:, 1][y == 0], "bs")
plt.plot(X2D[:, 0][y == 1], X2D[:, 1][y == 1], "g^")
plt.gca().get_yaxis().set_ticks([0, 4, 8, 12, 16])
plt.xlabel(r"$x_1$", fontsize=20)
plt.ylabel(r"$x_2$", fontsize=20, rotation=0)
plt.plot([-4.5, 4.5], [6.5, 6.5], "r--", linewidth=3)
plt.axis([-4.5, 4.5, -1, 17])
plt.show()

在这里插入图片描述
手动制作月亮型数据并使用支持向量机训练

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_moons
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures
from sklearn.preprocessing import StandardScaler
from sklearn.svm import LinearSVC
X, y = make_moons(n_samples=100, noise=0.15, random_state=42)

# print(X)
# print(y)

polynomial_svm_clf = Pipeline(steps=[
    ("poly_features", PolynomialFeatures(degree=3)),
    ("scaler", StandardScaler()),
    ("svm_clf", LinearSVC(C=10, loss="hinge"))
])

polynomial_svm_clf.fit(X, y)


def plot_dataset(x_, y_, axes):
    plt.plot(x_[:, 0][y_ == 0], x_[:, 1][y_ == 0], 'bs')
    plt.plot(x_[:, 0][y_ == 1], x_[:, 1][y_ == 1], 'g^')
    plt.axis(axes)
    plt.grid(True, which='both')
    plt.xlabel(r"$x_1$", fontsize=20)
    plt.ylabel(r"$x_2$", fontsize=20, rotation=0)


def plot_predictions(clf, axes):
    x0s = np.linspace(axes[0], axes[1], 100)  # 在横坐标间隔内返回均匀分布的数字
    x1s = np.linspace(axes[2], axes[3], 100)  # 在纵坐标间隔内返回均匀分布的数字
    x0, x1 = np.meshgrid(x0s, x1s)            # 从坐标向量返回坐标矩阵 x0.shape = (100, 100) x1.shape = (100, 100)
    # print(x0)
    # print(x1)
    x = np.c_[x0.ravel(), x1.ravel()]         # ravel()返回一个包含输入元素的一维数组 x.shape = (10000, 2)
    y_pred = clf.predict(x).reshape(100, 100)
    # print(y_pred)
    plt.contourf(x0, x1, y_pred, cmap=plt.cm.brg, alpha=0.2)  # 绘制填充轮廓


plot_predictions(polynomial_svm_clf, [-1.5, 2.5, -1, 1.5])
plot_dataset(X, y, [-1.5, 2.5, -1, 1.5])
plt.show()

在这里插入图片描述

  • 引入核函数——高斯核函数
import numpy as np
import matplotlib.pyplot as plt
from sklearn.svm import SVC
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.datasets import make_moons

X, y = make_moons(n_samples=100, noise=0.15, random_state=42)
print(X.shape)

gamma1, gamma2 = 0.1, 5
C1, C2 = 0.001, 1000
hyperparams = (gamma1, C1), (gamma1, C2), (gamma2, C1), (gamma2, C2)

print(hyperparams)

svm_clfs = []
for gamma, C in hyperparams:
    rbf_kernel_svm_clf = Pipeline(steps=[
        ("scaler", StandardScaler()),
        ("svm_clf", SVC(kernel="rbf", gamma=gamma, C=C))
    ])
    print(rbf_kernel_svm_clf)
    rbf_kernel_svm_clf.fit(X, y)
    svm_clfs.append(rbf_kernel_svm_clf)


def plot_dataset(x_, y_, axes):
    plt.plot(x_[:, 0][y_ == 0], x_[:, 1][y_ == 0], 'bs')
    plt.plot(x_[:, 0][y_ == 1], x_[:, 1][y_ == 1], 'g^')
    plt.axis(axes)
    plt.grid(True, which='both')
    # plt.xlabel(r"$x_1$", fontsize=20)
    # plt.ylabel(r"$x_2$", fontsize=20, rotation=0)


def plot_predictions(clf, axes):
    x0s = np.linspace(axes[0], axes[1], 100)
    x1s = np.linspace(axes[2], axes[3], 100)
    x0, x1 = np.meshgrid(x0s, x1s)
    x = np.c_[x0.ravel(), x1.ravel()]
    y_pred = clf.predict(x).reshape(100, 100)
    plt.contourf(x0, x1, y_pred, cmap=plt.cm.brg, alpha=0.2)


plt.figure(figsize=(11, 7))
for i, svm_clf in enumerate(svm_clfs):
    plt.subplot(221 + i)
    plot_predictions(svm_clf, [-1.5, 2.5, -1, 1.5])
    plot_dataset(X, y, [-1.5, 2.5, -1, 1.5])
    gamma, C = hyperparams[i]
    plt.title(r"$\gamma = {}, C = {}$".format(gamma, C), fontsize=16)
plt.show()

在这里插入图片描述
参数分析

参数变化 影响
γ \gamma γ减小 每个实例影响范围较大,决策边界更加平滑
γ \gamma γ增大 每个实例影响范围较小,决策边界更不规则
C C C增大 严格分类不能有错误
C C C减小 有较大的错误容忍

参考文献

唐宇迪老师讲解SVM支持向量机
机器学习-白板推导系列(六)-支持向量机SVM(Support Vector Machine)
《机器学习》—— 周志华
支持向量机 —— 维基百科,自由的百科全书

猜你喜欢

转载自blog.csdn.net/Star_ID/article/details/125010631