9、支持向量机(support vector machines,SVM)算法——监督、分类/回归

时间:2024-02-26 06:56:41

1、支持向量机(support vector machines,SVM)算法

支持向量机算法是由Vapnik等人于1955年提出来的,在人脸识别、文本分类等模式识别问题中得到广泛应用。支持向量机是一种二分类模型。它的基本模型是定义在特征空间上的间隔最大的线性分类器,支持向量机的学习策略就是间隔最大化,可形式化为求解凸二次规划的问题。

支持向量机学习方法包含构建由简至繁的模型:线性可分支持向量机线性支持向量机非线性支持向量机

线性可分支持向量机(硬间隔支持向量机:当训练数据线性可分时,通过硬间隔最大化,可以学习一个线性的分类器。

线性支持向量机(软间隔支持向量机):当训练数据近似线性可分时,通过软间隔最大化,也可以学习一个线性的分类器。

非线性支持向量机:当训练数据线性不可分时,通过使用核技巧及软间隔最大化,可以学习一个非线性的分类器。

支持向量机优缺点:

优点:
(1)非线性映射是SVM方法的理论基础,SVM利用内积核函数代替向高维空间的非线性映射;
(2)对特征空间划分的最优超平面是SVM的目标,最大化分类边际的思想是SVM方法的核心;
(3)支持向量是SVM的训练结果,在SVM分类决策中起决定作用的是支持向量;
(4)SVM 是一种有坚实理论基础的新颖的小样本学习方法;
(5)SVM 的最终决策函数只由少数的支持向量所确定,计算的复杂性取决于支持向量的数目,而不是样本空间的维数,这在某种意义上避免了“维数灾难”;
(6)少数支持向量决定了最终结果,这不但可以帮助抓住关键样本、“剔除”大量冗余样本,而且注定了该方法不但算法简单,而且具有较好的“鲁棒”性。这种“鲁棒”性主要体现在:增、删非支持向量样本对模型没有影响;支持向量样本集具有一定的鲁棒性;有些成功的应用中,SVM 方法对核的选取不敏感。

缺点:
(1) SVM算法对大规模训练样本难以实施。由于SVM是借助二次规划来求解支持向量,而求解二次规划将涉及m阶矩阵的计算(m为样本的个数),当m数目很大时该矩阵的存储和计算将耗费大量的机器内存和运算时间。针对以上问题的主要改进有SMO算法等;
(2) 用SVM解决多分类问题存在困难。经典的支持向量机算法只给出了二类分类的算法,而在数据挖掘的实际应用中,一般要解决多类的分类问题。可以通过多个二类支持向量机的组合来解决。主要有一对多组合模式、一对一组合模式和SVM决策树;再就是通过构造多个分类器的组合来解决。

2、线性可分支持向量机(硬间隔支持向量机

假设给定一个特征空间上的训练数据集$T = \left\{ {\left( {{x^{\left( 1 \right)}}{\rm{,}}{y^{\left( 1 \right)}}} \right){\rm{,}}\left( {{x^{\left( 2 \right)}}{\rm{,}}{y^{\left( 2 \right)}}} \right){\rm{,}} \cdots {\rm{,}}\left( {{x^{\left( N \right)}}{\rm{,}}{y^{\left( N \right)}}} \right)} \right\}$,其中,$\left( {{x^{\left( i \right)}}{\rm{,}}{y^{\left( i \right)}}} \right)$,类标记${y^{\left( i \right)}} \in \left\{ { + 1{\rm{,}} - 1} \right\}$,$i = 1{\rm{,}}2{\rm{,}} \cdots {\rm{,}}N$。

对于线性可分的数据集,学习的目标是在特征空间中找到一个可分离超平面,即:
$w \cdot x + b = 0$

然而,对于逻辑回归算法或感知机,存在无穷多个学习到的超平面,如何确定最佳超平面是SVM算法需要解决的问题。

1)线性可分支持向量机

对于上述线性可分的训练数据集,通过间隔最大化或等价地求解相应的凸二次规划问题学习得到的分离超平面:

${w^ * } \cdot x + {b^ * } = 0$

以及相应的分类决策函数

$f\left( x \right) = sign\left( {{w^ * } \cdot x + {b^ * }} \right)$

称为线性可分支持向量机。

由于线性可分支持向量机是利用间隔最大化求最优分离超平面,其解是唯一的,即代表了该超平面的唯一性。

2)函数间隔

令直线$l$方程为$Ax + By + C = 0$,点P的坐标为$\left( {{x_0}{\rm{,}}{y_0}} \right)$,点P到直线$l$的距离公式为:

$d = \left| {\frac{{A{x_0} + B{y_0} + C}}{{\sqrt {{A^2} + {B^2}} }}} \right|$

因此,对于给定的训练数据集$T$,超平面$w \cdot x + b = 0$,以及样本点P$\left( {{x^{\left( i \right)}}{\rm{,}}{y^{\left( i \right)}}} \right)$,$\left| {w \cdot {x^{\left( i \right)}} + b} \right|$能够相对的表示样本点P到距离超平面的远近,而${w \cdot {x^{\left( i \right)}} + b}$的符号与类标记${{y^{\left( i \right)}}}$的符号是否一致表示分类是否正确,所以,可以用${y^{\left( i \right)}}\left( {w \cdot {x^{\left( i \right)}} + b} \right)$的正负性来判定或表示分类的正确性和确信度。

即可定义函数间隔为:

 ${\widehat \gamma _i} = {y^{\left( i \right)}}\left( {w \cdot {x^{\left( i \right)}} + b} \right)$

则所有样本中,函数间隔的最小值为:

$\widehat \gamma  = \mathop {{\rm{min}}}\limits_{i = 1{\rm{,}}2{\rm{,}} \cdots {\rm{,}}N} {\widehat \gamma _i}$

函数间隔可以表示分类预测的正确性和确信度。但是,只要成比例地改变$w$和$b$,超平面并没有改变,但是函数间隔却成比例改变。因而引入几何间隔。

3)几何间隔

对于给定的训练数据集$T$,超平面$w \cdot x + b = 0$,以及样本点P$\left( {{x^{\left( i \right)}}{\rm{,}}{y^{\left( i \right)}}} \right)$, 样本点P到距离超平面的几何距离为:
${\gamma _i} = {y^{\left( i \right)}}\left( {\frac{w}{{\left\| w \right\|}} \cdot {x^{\left( i \right)}} + \frac{b}{{\left\| w \right\|}}} \right)$

其中,$\left\| {} \right\|$为2范数。则所有样本中,几何间隔的最小值为:

$\gamma  = \mathop {{\rm{min}}}\limits_{i = 1{\rm{,}}2{\rm{,}} \cdots {\rm{,}}N} {\gamma _i}$

如果超平面$w$和$b$成比例地改变,超平面并没有改变,且几何间隔也不变。

函数间隔与几何间隔的关系如下:

${\gamma _i} = \frac{{{{\widehat \gamma }_i}}}{{\left\| w \right\|}}{\rm{,}}\quad \gamma  = \frac{{\widehat \gamma }}{{\left\| w \right\|}}$

4)间隔最大化、支持向量及间隔边界

a)间隔最大化

间隔最大化的直观解释是:对训练数据集找到几何间隔最大的超平面意味着以充分大的确信度对训练数据进行分类。

对于最大间隔分离超平面的求取,可通过如下约束最优化问题:

$\mathop {{\rm{max}}}\limits_{w{\rm{,}}b} {\rm{  }}\; \gamma \quad {\rm{        s}}{\rm{.t    }}\  \ {y^{\left( i \right)}}\left( {\frac{w}{{\left\| w \right\|}} \cdot {x^{\left( i \right)}} + \frac{b}{{\left\| w \right\|}}} \right) \ge \gamma {\rm{,    }}\quad i = 1{\rm{,}}2{\rm{,}} \cdots {\rm{,}}N$

上式约束条件表示的是超平面关于每个训练样本点的几何间隔至少是$\gamma $。

考虑几何间隔函数间隔的关系,可将上式最优化问题改写为:
$\mathop {{\rm{max}}} \limits_{w{\rm{,}}b} {\rm{  }}\; \frac{{\widehat \gamma }}{{\left\| w \right\|}}\quad {\rm{        s}}{\rm{.t    }}\ \ {y^{\left( i \right)}}\left( {w \cdot {x^{\left( i \right)}} + b} \right) \ge \widehat \gamma {\rm{,    }}\quad i = 1{\rm{,}}2{\rm{,}} \cdots {\rm{,}}N$

函数间隔${\widehat \gamma }$的取值并不影响最优化问题的解,因此,可取$\widehat \gamma  = 1$。注意到最大化$\frac{1}{{\left\| w \right\|}}$和最小化$\frac{1}{2}{\left\| w \right\|^2}$是等价的。于是可得如下最优化问题

$\mathop {{\rm{min}}}\limits_{w{\rm{,}}b} {\rm{  }}\; \frac{1}{2}{\left\| w \right\|^2} \quad {\rm{        s}}{\rm{.t    }}\ \ {y^{\left( i \right)}}\left( {w \cdot {x^{\left( i \right)}} + b} \right) - 1 \ge 0{\rm{,    }}\quad  i = 1{\rm{,}}2{\rm{,}} \cdots {\rm{,}}N$

此为支持向量机的基本型,属于凸二次规划问题,可求得解${w^ * }$和${b^ * }$。进一步求得超平面${w^ * } \cdot x + {b^ * } = 0$和分类决策函数$f\left( x \right) = sign\left( {{w^ * } \cdot x + {b^ * }} \right)$。

注:线性可分训练集的最大间隔分离超平面是存在且唯一的。

b)支持向量(support vector)

在线性可分的情况下,训练数据集的样本点中与分离超平面几何距离最近的样本点称为支持向量,如上图所示

特别地,在决定分离超平面时只有支持向量起作用,而其他样本点并不起作用。

c)间隔边界

两个间隔边界的距离为$\frac{2}{{\left\| w \right\|}}$,该两个边界共同组成间隔边界,如上图所示。

5)学习的对偶算法

为了求解线性可分支持向量机的最优化问题,可应用拉格朗日对偶性求得最优解对偶算法优点在于:一是对偶问题更容易求解;二是自然引入核函数,进而推广到非线性分类问题。

a)构建拉格朗日函数

即对每一个不等式约束引进拉格朗日乘子${\alpha _i} \ge 0$,$i = 1{\rm{,}}2{\rm{,}} \cdots {\rm{,}}N$,定义拉格朗日函数

$L\left( {w{\rm{,}}b{\rm{,}}\alpha } \right) = \frac{1}{2}{\left\| w \right\|^2} - \sum\limits_{i = 1}^N {{\alpha _i}{y^{\left( i \right)}}\left( {w \cdot {x^{\left( i \right)}} + b} \right) + } \sum\limits_{i = 1}^N {{\alpha _i}} $

其中,$\alpha  = {\left( {{\alpha _1}{\rm{,}}{\alpha _2}{\rm{,}} \cdots {\rm{,}}{\alpha _N}} \right)^T}$为拉格朗日乘子向量。

b)对偶问题

根据拉格朗日对偶性,原始问题的对偶问题是极大极小问题:

$\mathop {{\rm{max}}}\limits_\alpha  \mathop {{\rm{min}}}\limits_{w{\rm{,}}b} {\rm{  }}\; L\left( {w{\rm{,}}b{\rm{,}}\alpha } \right)$

所以,为了得到对偶问题的解,需要先求$L\left( {w{\rm{,}}b{\rm{,}}\alpha } \right)$对${w{\rm{,}}b}$的极小,再求对$\alpha $的极大。

c)求$\mathop {{\rm{min}}}\limits_{w{\rm{,}}b} {\rm{  }}\; L\left( {w{\rm{,}}b{\rm{,}}\alpha } \right)$

将拉格朗日函数$L\left( {w{\rm{,}}b{\rm{,}}\alpha } \right)$分别对${w{\rm{,}}b}$求偏导数并令其为0。

${\nabla _w}L\left( {w{\rm{,}}b{\rm{,}}\alpha } \right) = w - \sum\limits_{i = 1}^N {{\alpha _i}{y^{\left( i \right)}}{x^{\left( i \right)}}}  = 0$

${\nabla _b}L\left( {w{\rm{,}}b{\rm{,}}\alpha } \right) =  - \sum\limits_{i = 1}^N {{\alpha _i}{y^{\left( i \right)}} = 0} $

得:

$w = \sum\limits_{i = 1}^N {{\alpha _i}{y^{\left( i \right)}}{x^{\left( i \right)}}} $

$\sum\limits_{i = 1}^N {{\alpha _i}{y^{\left( i \right)}} = 0} $

将上式带入b)中的拉格朗日函数,即得:

$\begin{array}{l}
L\left( {w{\rm{,}}b{\rm{,}}\alpha } \right) = \frac{1}{2}\sum\limits_{i = 1}^N {\sum\limits_{j = 1}^N {{\alpha _i}{\alpha _j}{y^{\left( i \right)}}{y^{\left( j \right)}}\left( {{x^{\left( i \right)}} \cdot {x^{\left( j \right)}}} \right)} } - \sum\limits_{i = 1}^N {{\alpha _i}{y^{\left( i \right)}}\left( {\left( {\sum\limits_{j = 1}^N {{\alpha _j}{y^{\left( j \right)}}{x^{\left( j \right)}}} } \right) \cdot {x^{\left( i \right)}} + b} \right) + } \sum\limits_{i = 1}^N {{\alpha _i}} \\
{\rm{ }} = - \frac{1}{2}\sum\limits_{i = 1}^N {\sum\limits_{j = 1}^N {{\alpha _i}{\alpha _j}{y^{\left( i \right)}}{y^{\left( j \right)}}\left( {{x^{\left( i \right)}} \cdot {x^{\left( j \right)}}} \right)} } + \sum\limits_{i = 1}^N {{\alpha _i}}
\end{array}$

即:
$\mathop {{\rm{min}}}\limits_{w{\rm{,}}b}\; L\left( {w{\rm{,}}b{\rm{,}}\alpha } \right) =  - \frac{1}{2}\sum\limits_{i = 1}^N {\sum\limits_{j = 1}^N {{\alpha _i}{\alpha _j}{y^{\left( i \right)}}{y^{\left( j \right)}}\left( {{x^{\left( i \right)}} \cdot {x^{\left( j \right)}}} \right)} }  + \sum\limits_{i = 1}^N {{\alpha _i}} $

d)求$\mathop {{\rm{min}}}\limits_{w{\rm{,}}b}\; L\left( {w{\rm{,}}b{\rm{,}}\alpha } \right)$对$\alpha $的极大,即是对偶问题:

$\mathop {{\rm{max}}}\limits_\alpha  {\rm{ }}\;  - \frac{1}{2}\sum\limits_{i = 1}^N {\sum\limits_{j = 1}^N {{\alpha _i}{\alpha _j}{y^{\left( i \right)}}{y^{\left( j \right)}}\left( {{x^{\left( i \right)}} \cdot {x^{\left( j \right)}}} \right)} }  + \sum\limits_{i = 1}^N {{\alpha _i}} $

${\rm{s}}{\rm{.t    }}\ \ \sum\limits_{i = 1}^N {{\alpha _i}{y^{\left( i \right)}} = 0} $

       ${\alpha _i} \ge 0{\rm{,      }}\quad i = 1{\rm{,}}2{\rm{,}} \cdots {\rm{,}}N$

将上式目标函数由极大转换为求极小,即可得如下等价的对偶约束最优化问题

$\mathop {{\rm{min}}}\limits_\alpha  {\rm{ }}\;  \frac{1}{2}\sum\limits_{i = 1}^N {\sum\limits_{j = 1}^N {{\alpha _i}{\alpha _j}{y^{\left( i \right)}}{y^{\left( j \right)}}\left( {{x^{\left( i \right)}} \cdot {x^{\left( j \right)}}} \right)} }  - \sum\limits_{i = 1}^N {{\alpha _i}} $

${\rm{s}}{\rm{.t    }}\ \ \sum\limits_{i = 1}^N {{\alpha _i}{y^{\left( i \right)}} = 0} $

       ${\alpha _i} \ge 0{\rm{,      }}\quad i = 1{\rm{,}}2{\rm{,}} \cdots {\rm{,}}N$

求得最优解${\alpha ^ * } = {\left( {\alpha _1^*{\rm{,}}\alpha _2^*{\rm{,}} \cdots {\rm{,}}\alpha _N^*} \right)^T}$。

e)计算${w^ * }$和${b^ * }$

计算${w^ * }$:

${w^ * } = \sum\limits_{i = 1}^N {\alpha _i^*{y^{\left( i \right)}}{x^{\left( i \right)}}} $

选择${\alpha ^ * }$的一个正分量$\alpha _j^* > 0$,计算${b^ * }$:

${b^ * } = {y^{\left( j \right)}} - \sum\limits_{i = 1}^N {\alpha _i^*{y^{\left( i \right)}}\left( {{x^{\left( i \right)}} \cdot {x^{\left( j \right)}}} \right)} $

进一步,即可求得分离超平面和决策函数:

分离超平面:${w^ * } \cdot x + {b^ * } = 0$

决策函数:$f\left( x \right) = sign\left( {{w^ * } \cdot x + {b^ * }} \right)$

附录:${w^ * }$和${b^ * }$求解证明

证:  原始问题为凸二次规划问题,解满足KKT条件,可得

${\nabla _w}L\left( {{w^ * }{\rm{,}}{b^ * }{\rm{,}}{\alpha ^ * }} \right) = {w^ * } - \sum\limits_{i = 1}^N {\alpha _i^*{y^{\left( i \right)}}{x^{\left( i \right)}}}  = 0$

${\nabla _b}L\left( {{w^ * }{\rm{,}}{b^ * }{\rm{,}}{\alpha ^ * }} \right) =  - \sum\limits_{i = 1}^N {\alpha _i^*{y^{\left( i \right)}} = 0} $

$\alpha _i^*\left( {{y^{\left( i \right)}}\left( {{w^ * } \cdot {x^{\left( i \right)}} + {b^ * }} \right) - 1} \right) = 0{\rm{,    }}\quad i = 1{\rm{,}}2{\rm{,}} \cdots {\rm{,}}N$

${y^{\left( i \right)}}\left( {{w^ * } \cdot {x^{\left( i \right)}} + {b^ * }} \right) - 1 \ge 0{\rm{,    }}\quad i = 1{\rm{,}}2{\rm{,}} \cdots {\rm{,}}N$

$\alpha _i^* \ge 0{\rm{,    }}\quad i = 1{\rm{,}}2{\rm{,}} \cdots {\rm{,}}N$

易得:

${w^ * } = \sum\limits_{i = 1}^N {\alpha _i^*{y^{\left( i \right)}}{x^{\left( i \right)}}} $

对于条件3,可知至少有一个$\alpha _j^* > 0$(反证法:假设${\alpha ^ * } = 0$,由条件1可知${w^ * } = 0$,而${w^ * } = 0$不是原始最优化问题的解,矛盾),对此$j$有:

${y^{\left( j \right)}}\left( {{w^ * } \cdot {x^{\left( j \right)}} + {b^ * }} \right) - 1 = 0$

由${\left( {{y^{\left( j \right)}}} \right)^2} = 1$,即得:

${b^ * } = {y^{\left( j \right)}} - \sum\limits_{i = 1}^N {\alpha _i^*{y^{\left( i \right)}}\left( {{x^{\left( i \right)}} \cdot {x^{\left( j \right)}}} \right)}$

f)支持向量

由上可知,分离超平面参数${w^ * }$和${b^ * }$只依赖于训练数据中对应于$\alpha _j^* > 0$的样本点$\left( {{x^{\left( j \right)}}{\rm{,}}{y^{\left( j \right)}}} \right)$,而其他样本点对${w^ * }$和${b^ * }$没有影响。

即将训练数据中对应于$\alpha _j^* > 0$的样本点称为支持向量

6)实例

如图所示训练数据集,正例点是${x^{\left( 1 \right)}} = {\left( {3{\rm{,}}3} \right)^T}$,${x^{\left( 2 \right)}} = {\left( {4{\rm{,}}3} \right)^T}$,负例点是${x^{\left( 3 \right)}} = {\left( {1{\rm{,}}1} \right)^T}$,试用上述SVM算法求分离超平面和分类决策函数。

:根据所给数据,对偶问题为:

$\mathop {{\rm{min}}}\limits_\alpha  {\rm{ }}\frac{1}{2}\sum\limits_{i = 1}^N {\sum\limits_{j = 1}^N {{\alpha _i}{\alpha _j}{y^{\left( i \right)}}{y^{\left( j \right)}}\left( {{x^{\left( i \right)}} \cdot {x^{\left( j \right)}}} \right)} }  - \sum\limits_{i = 1}^N {{\alpha _i}} $

     ${\rm{ = }}\frac{1}{2}\left( {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}} \right) - {\alpha _i} - {\alpha _2} - {\alpha _3}$

${\rm{s}}{\rm{.t    }}\; {\alpha _1} + {\alpha _2} - {\alpha _3} = 0$

     ${\alpha _i} \ge 0{\rm{,      }}\quad i = 1{\rm{,}}2{\rm{,}}3$ 

解这一最优化问题,可将${\alpha _3} = {\alpha _1} + {\alpha _2}$带入目标函数并记为:

$s\left( {{\alpha _1}{\rm{,}}{\alpha _2}} \right) = 4\alpha _1^2 + \frac{{13}}{2}\alpha _2^2 + 10{\alpha _1}{\alpha _2} - 2{\alpha _1} - 2{\alpha _2}$

对${{\alpha _1}{\rm{,}}{\alpha _2}}$求偏导数并令其为0,易知$s\left( {{\alpha _1}{\rm{,}}{\alpha _2}} \right)$在点${\left( {\frac{3}{2}{\rm{,}} - 1} \right)^T}$取极值,但该点不满足约束条件${\alpha _2} \ge 0$,所以最小值在边界上达到。

当${\alpha _1} = 0$时,$s\left( {{\alpha _1}{\rm{,}}{\alpha _2}} \right)$在点${\left( {0{\rm{,}}\frac{2}{{13}}} \right)^T}$处取最小值$ - \frac{2}{{13}}$;当${\alpha _2} = 0$时,$s\left( {{\alpha _1}{\rm{,}}{\alpha _2}} \right)$在点${\left( {\frac{1}{4}{\rm{,}}0} \right)^T}$处取最小值$- \frac{1}{4}$,并且有$- \frac{1}{4} <  - \frac{2}{{13}}$。所以,取$\alpha _1^* = \frac{1}{4}{\rm{,}}\alpha _2^* = 0{\rm{,}}\alpha _3^* = \frac{1}{4}$为最优化方程的解。

这样可知,$\alpha _1^* = \frac{1}{4}{\rm{,}}\alpha _2^* = 0{\rm{,}}\alpha _3^* = \frac{1}{4}$对应的样本点${x^{\left( 1 \right)}}$和${x^{\left( 3 \right)}}$为支持向量。根据上式可得:

${w^ * } = \sum\limits_{i = 1}^N {\alpha _i^*{y^{\left( i \right)}}{x^{\left( i \right)}}}  = \frac{1}{4} \cdot 1 \cdot {\left( {3{\rm{,}}3} \right)^T} + 0 \cdot 1 \cdot {\left( {4{\rm{,}}3} \right)^T} + \frac{1}{4} \cdot \left( { - 1} \right) \cdot {\left( {1{\rm{,}}1} \right)^T} = {\left( {\frac{1}{2}{\rm{,}}\frac{1}{2}} \right)^T}$

即$w_1^ *  = w_2^ *  = \frac{1}{2}$;

选取${\alpha ^*}$中一个正分量$\alpha _3^*$,$j = 3$。

${b^ * } = {y^{\left( j \right)}} - \sum\limits_{i = 1}^N {\alpha _i^*{y^{\left( i \right)}}\left( {{x^{\left( i \right)}} \cdot {x^{\left( j \right)}}} \right)}  =  - 1 - \left( {\frac{1}{4} \cdot 1 \cdot \left( {3{\rm{,}}3} \right){{\left( {1{\rm{,}}1} \right)}^T} + 0 \cdot 1 \cdot \left( {4{\rm{,}}3} \right){{\left( {1{\rm{,}}1} \right)}^T} + \frac{1}{4} \cdot \left( { - 1} \right) \cdot \left( {1{\rm{,}}1} \right){{\left( {1{\rm{,}}1} \right)}^T}} \right) =  - 2$

分离超平面为:$\frac{1}{2}{x^{\left( 1 \right)}} + \frac{1}{2}{x^{\left( 2 \right)}} - 2 = 0$

分类决策函数为:$f\left( x \right) = {\rm{sign}}\left( {\frac{1}{2}{x^{\left( 1 \right)}} + \frac{1}{2}{x^{\left( 2 \right)}} - 2} \right)$

3、线性支持向量机(软间隔支持向量机

假设给定一个特征空间上的训练数据集$T = \left\{ {\left( {{x^{\left( 1 \right)}}{\rm{,}}{y^{\left( 1 \right)}}} \right){\rm{,}}\left( {{x^{\left( 2 \right)}}{\rm{,}}{y^{\left( 2 \right)}}} \right){\rm{,}} \cdots {\rm{,}}\left( {{x^{\left( N \right)}}{\rm{,}}{y^{\left( N \right)}}} \right)} \right\}$,其中,$\left( {{x^{\left( i \right)}}{\rm{,}}{y^{\left( i \right)}}} \right)$,类标记${y^{\left( i \right)}} \in \left\{ { + 1{\rm{,}} - 1} \right\}$,$i = 1{\rm{,}}2{\rm{,}} \cdots {\rm{,}}N$。

若该数据集中存在少数特异点,导致数据集不是线性可分,即某些样本点$\left( {{x^{\left( j \right)}}{\rm{,}}{y^{\left( j \right)}}} \right)$不能满足函数间隔大于等于1的约束条件。如下图所示:

 

其中,红色标注的为不满足约束条件的点。

1)线性支持向量机

为了解决该问题,引入松弛变量${\xi _i} \ge 0$,线性不可分支持向量机的学习问题变为如下凸二次规划问题(原始问题)

$\mathop {{\rm{min}}}\limits_{w{\rm{,}}b{\rm{,}}\xi } {\rm{  }}\; \frac{1}{2}{\left\| w \right\|^2}{\rm{ + }}C\sum\limits_{i = 1}^N {{\xi _i}} $

${\rm{s}}{\rm{.t    }}\; {y^{\left( i \right)}}\left( {w \cdot {x^{\left( i \right)}} + b} \right) \ge 1 - {\xi _i}{\rm{,   }}\quad i = 1{\rm{,}}2{\rm{,}} \cdots {\rm{,}}N$

     ${\xi _i} \ge 0{\rm{,    }}\quad i = 1{\rm{,}}2{\rm{,}} \cdots {\rm{,}}N$

其中,$C$为惩罚参数。$C$值大时对误分类的惩罚增大,$C$值小时对误分类的惩罚减小。最优化目标函数包含两层含义:使$\frac{1}{2}{\left\| w \right\|^2}$尽量小即间隔尽量大;使误分类的个数尽量少。

2)学习的对偶算法

上述原始问题的对偶问题为:

$\mathop {{\rm{min}}}\limits_\alpha  {\rm{ }}\; \frac{1}{2}\sum\limits_{i = 1}^N {\sum\limits_{j = 1}^N {{\alpha _i}{\alpha _j}{y^{\left( i \right)}}{y^{\left( j \right)}}\left( {{x^{\left( i \right)}} \cdot {x^{\left( j \right)}}} \right)} }  - \sum\limits_{i = 1}^N {{\alpha _i}} $

${\rm{s}}{\rm{.t    }}\; \sum\limits_{i = 1}^N {{\alpha _i}{y^{\left( i \right)}} = 0} $

     $0 \le {\alpha _i} \le C{\rm{,      }}\quad i = 1{\rm{,}}2{\rm{,}} \cdots {\rm{,}}N$

证明如下

原始最优化问题的拉格朗日函数为:

$L\left( {w{\rm{,}}b{\rm{,}}\xi {\rm{,}}\alpha {\rm{,}}\mu } \right) = \frac{1}{2}{\left\| w \right\|^2} + C\sum\limits_{i = 1}^N {{\xi _i}}  - \sum\limits_{i = 1}^N {{\alpha _i}\left( {{y^{\left( i \right)}}\left( {w \cdot {x^{\left( i \right)}} + b} \right) - 1 + {\xi _i}} \right) - } \sum\limits_{i = 1}^N {{\mu _i}{\xi _i}} $

其中,${\alpha _i} \ge 0{\rm{,}}{\mu _i} \ge 0$

对偶问题是拉格朗日函数的极大极小问题。首先求$L\left( {w{\rm{,}}b{\rm{,}}\xi {\rm{,}}\alpha {\rm{,}}\mu } \right)$对${w{\rm{,}}b{\rm{,}}\xi }$的极小,由

$\begin{array}{l}
{\nabla _w}L\left( {w{\rm{,}}b{\rm{,}}\xi {\rm{,}}\alpha {\rm{,}}\mu } \right) = w - \sum\limits_{i = 1}^N {{\alpha _i}{y^{\left( i \right)}}{x^{\left( i \right)}}} = 0\\
{\nabla _b}L\left( {w{\rm{,}}b{\rm{,}}\xi {\rm{,}}\alpha {\rm{,}}\mu } \right) = - \sum\limits_{i = 1}^N {{\alpha _i}{y^{\left( i \right)}} = 0} \\
{\nabla _{{\xi _i}}}L\left( {w{\rm{,}}b{\rm{,}}\xi {\rm{,}}\alpha {\rm{,}}\mu } \right) = C - {\alpha _i} - {\mu _i} = 0
\end{array}$

得:

$\begin{array}{l}
w = \sum\limits_{i = 1}^N {{\alpha _i}{y^{\left( i \right)}}{x^{\left( i \right)}}} \\
\sum\limits_{i = 1}^N {{\alpha _i}{y^{\left( i \right)}} = 0} \\
C - {\alpha _i} - {\mu _i} = 0
\end{array}$

进一步,可得:

$\mathop {{\rm{min}}}\limits_{w{\rm{,}}b{\rm{,}}\xi } {\rm{ }}\; L\left( {w{\rm{,}}b{\rm{,}}\xi {\rm{,}}\alpha {\rm{,}}\mu } \right) =  - \frac{1}{2}\sum\limits_{i = 1}^N {\sum\limits_{j = 1}^N {{\alpha _i}{\alpha _j}{y^{\left( i \right)}}{y^{\left( j \right)}}\left( {{x^{\left( i \right)}} \cdot {x^{\left( j \right)}}} \right)} }  + \sum\limits_{i = 1}^N {{\alpha _i}} $

再对上式求$\alpha $极大,即得对偶问题:

$\mathop {{\rm{max}}}\limits_\alpha  {\rm{ }} - \frac{1}{2}\sum\limits_{i = 1}^N {\sum\limits_{j = 1}^N {{\alpha _i}{\alpha _j}{y^{\left( i \right)}}{y^{\left( j \right)}}\left( {{x^{\left( i \right)}} \cdot {x^{\left( j \right)}}} \right)} }  + \sum\limits_{i = 1}^N {{\alpha _i}} $

${\rm{s}}{\rm{.t    }}\; \sum\limits_{i = 1}^N {{\alpha _i}{y^{\left( i \right)}} = 0} $

     $C - {\alpha _i} - {\mu _i} = 0$

     ${\alpha _i} \ge 0$

     ${\mu _i} \ge 0{\rm{,      }}i = 1{\rm{,}}2{\rm{,}} \cdots {\rm{,}}N$

再进行少量变换即可得证。

3)对偶问题求解

设${\alpha ^ * } = {\left( {\alpha _1^*{\rm{,}}\alpha _2^*{\rm{,}} \cdots {\rm{,}}\alpha _N^*} \right)^T}$是对偶问题的解,若存在${\alpha ^ * }$的一个分量$\alpha _j^*{\rm{, }}0 < \alpha _j^* < C$,则原始问题的解${w^ * }{\rm{, }}{b^ * }$为:

$\begin{array}{l}
{w^ * } = \sum\limits_{i = 1}^N {\alpha _i^*{y^{\left( i \right)}}{x^{\left( i \right)}}} \\
{b^ * } = {y^{\left( j \right)}} - \sum\limits_{i = 1}^N {\alpha _i^*{y^{\left( i \right)}}\left( {{x^{\left( i \right)}} \cdot {x^{\left( j \right)}}} \right)}
\end{array}$

证明如下:

原始问题是凸二次规划问题,解满足KKT条件,可得

$\begin{array}{l}
{\nabla _w}L\left( {{w^*}{\rm{,}}{b^*}{\rm{,}}{\xi ^*}{\rm{,}}{\alpha ^*}{\rm{,}}{\mu ^*}} \right) = {w^*} - \sum\limits_{i = 1}^N {\alpha _i^*{y^{\left( i \right)}}{x^{\left( i \right)}}} = 0\\
{\nabla _b}L\left( {{w^*}{\rm{,}}{b^*}{\rm{,}}{\xi ^*}{\rm{,}}{\alpha ^*}{\rm{,}}{\mu ^*}} \right) = - \sum\limits_{i = 1}^N {\alpha _i^*{y^{\left( i \right)}} = 0} \\
{\nabla _{{\xi _i}}}L\left( {{w^*}{\rm{,}}{b^*}{\rm{,}}{\xi ^*}{\rm{,}}{\alpha ^*}{\rm{,}}{\mu ^*}} \right) = C - \alpha _i^* - \mu _i^* = 0\\
\alpha _i^*\left( {{y^{\left( i \right)}}\left( {{w^ * } \cdot {x^{\left( i \right)}} + {b^ * }} \right) - 1 + \xi _i^*} \right) = 0\\
\mu _i^*\xi _i^* = 0\\
{y^{\left( i \right)}}\left( {{w^ * } \cdot {x^{\left( i \right)}} + {b^ * }} \right) - 1 + \xi _i^* \ge 0\\
\xi _i^* \ge 0\\
\alpha _i^* \ge 0
\end{array}$

$\mu _i^* \ge 0{\rm{,    }}\quad i = 1{\rm{,}}2{\rm{,}} \cdots {\rm{,}}N$

则若存在$\alpha _j^*{\rm{, }}0 < \alpha _j^* < C$,即有${y^{\left( i \right)}}\left( {{w^ * } \cdot {x^{\left( i \right)}} + {b^ * }} \right) - 1 = 0$,即证。

分离超平面为:${w^ * } \cdot x + {b^ * } = 0$

分离决策函数为:$f\left( x \right) = sign\left( {{w^ * } \cdot x + {b^ * }} \right)$

对任一条件$0 < \alpha _j^* < C$的$\alpha _j^*$,对于求出的${b^ * }$,其解可能不唯一。

4)支持向量

由上可知,分离超平面参数${w^ * }$和${b^ * }$只依赖于训练数据中对应于$\alpha _j^* > 0$的样本点$\left( {{x^{\left( j \right)}}{\rm{,}}{y^{\left( j \right)}}} \right)$,而其他样本点对${w^ * }$和${b^ * }$没有影响。

即将训练数据中对应于$\alpha _j^* > 0$的样本点称为支持向量

在软间隔的支持向量或在间隔边界上,或在间隔边界与分离超平面之间,或在分离超平面误分一侧。即:

$\alpha _j^* < C$,则$\xi _i^* = 0$,则支持向量在间隔边界上;

$\alpha _j^* = C{\rm{,}}0 < \xi _i^* < 1$,则分类正确;

$\alpha _j^* = C{\rm{,}}\xi _i^* = 1$,则支持向量在分离超平面上;

$\alpha _j^* = C{\rm{,}}\xi _i^* > 1$,则支持向量在分离超平面误分一侧上;

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

对于线性分类问题,线性支持向量机是一种非常有效的方法。但是,对于非线性分类问题,可使用非线性支持向量机,其特点是是利用核函数技巧。如下图所示:

1)非线性支持向量机学习算法

输入:假设给定一个特征空间上的训练数据集$T = \left\{ {\left( {{x^{\left( 1 \right)}}{\rm{,}}{y^{\left( 1 \right)}}} \right){\rm{,}}\left( {{x^{\left( 2 \right)}}{\rm{,}}{y^{\left( 2 \right)}}} \right){\rm{,}} \cdots {\rm{,}}\left( {{x^{\left( N \right)}}{\rm{,}}{y^{\left( N \right)}}} \right)} \right\}$,其中,$\left( {{x^{\left( i \right)}}{\rm{,}}{y^{\left( i \right)}}} \right)$,类标记${y^{\left( i \right)}} \in \left\{ { + 1{\rm{,}} - 1} \right\}$,$i = 1{\rm{,}}2{\rm{,}} \cdots {\rm{,}}N$。

输出:分类决策函数

(1)选取适当的核函数$K\left( {x{\rm{,}}z} \right)$和适当的参数$C$,构造并求解最优化问题:

$\mathop {{\rm{min}}}\limits_\alpha  {\rm{ }}\; \frac{1}{2}\sum\limits_{i = 1}^N {\sum\limits_{j = 1}^N {{\alpha _i}{\alpha _j}{y^{\left( i \right)}}{y^{\left( j \right)}}K\left( {{x^{\left( i \right)}}{\rm{,}}{x^{\left( j \right)}}} \right)} }  - \sum\limits_{i = 1}^N {{\alpha _i}} $

${\rm{s}}{\rm{.t    }}\;\; \sum\limits_{i = 1}^N {{\alpha _i}{y^{\left( i \right)}} = 0} $

     $0 \le {\alpha _i} \le C{\rm{,      }}\quad i = 1{\rm{,}}2{\rm{,}} \cdots {\rm{,}}N$

求得最优解${\alpha ^ * } = {\left( {\alpha _1^*{\rm{,}}\alpha _2^*{\rm{,}} \cdots {\rm{,}}\alpha _N^*} \right)^T}$。

(2)选择${\alpha ^ * }$的一个正分量$0 < \alpha _j^* < C$,计算:

${b^ * } = {y^{\left( j \right)}} - \sum\limits_{i = 1}^N {\alpha _i^*{y^{\left( i \right)}}K\left( {{x^{\left( i \right)}}{\rm{,}}{x^{\left( j \right)}}} \right)} $

(3)构造决策函数

$f\left( x \right) = sign\left( {\sum\limits_{i = 1}^N {\alpha _i^*{y^{\left( i \right)}}K\left( {x{\rm{,}}{x^{\left( i \right)}}} \right)}  + {b^ * }} \right)$

当$K\left( {x{\rm{,}}z} \right)$为正定核函数时,其为凸二次规划问题,解是存在的。

2)核函数

线性核函数(linear kernel):$K\left( {x{\rm{,}}z} \right) = \left( {x \cdot z} \right)$

多项式核函数(Polynomial kernel):$K\left( {x{\rm{,}}z} \right) = {\left( {s\left( {x \cdot z} \right) + c} \right)^d}$

高斯核函数(gaussian kernel):$K\left( {x{\rm{,}}z} \right) = {\rm{exp}}\left( { - \frac{{{{\left\| {x - z} \right\|}^2}}}{{2{\sigma ^2}}}} \right)$

径向基核函数(radical basis function,RBF):$K\left( {x{\rm{,}}z} \right) = {\rm{exp}}\left( { - \gamma {{\left| {x - z} \right|}^2}} \right)$

3)序列最小最优化算法(sequential minimal optimization,SMO)

输入:假设给定一个特征空间上的训练数据集$T = \left\{ {\left( {{x^{\left( 1 \right)}}{\rm{,}}{y^{\left( 1 \right)}}} \right){\rm{,}}\left( {{x^{\left( 2 \right)}}{\rm{,}}{y^{\left( 2 \right)}}} \right){\rm{,}} \cdots {\rm{,}}\left( {{x^{\left( N \right)}}{\rm{,}}{y^{\left( N \right)}}} \right)} \right\}$,其中,$\left( {{x^{\left( i \right)}}{\rm{,}}{y^{\left( i \right)}}} \right)$,类标记${y^{\left( i \right)}} \in \left\{ { + 1{\rm{,}} - 1} \right\}$,$i = 1{\rm{,}}2{\rm{,}} \cdots {\rm{,}}N$,精度为$\varepsilon $。

输出:近似解$\widehat \alpha $。

(1)取初值${\alpha ^{\left( 0 \right)}} = 0$,令$k = 0$;

(2)选取优化变量$\alpha _1^{\left( k \right)}{\rm{,}}\alpha _2^{\left( k \right)}$,解析求解两个变量的最优化问题:

$\begin{array}{l}
\mathop {{\rm{min}}}\limits_{{\alpha _1}{\rm{,}}{\alpha _2}} {\rm{ }}\; W\left( {{\alpha _1}{\rm{,}}{\alpha _2}} \right) = \frac{1}{2}{K_{11}}\alpha _1^2 + \frac{1}{2}{K_{22}}\alpha _2^2 + {y^{\left( 1 \right)}}{y^{\left( 2 \right)}}{K_{12}}{\alpha _1}{\alpha _2}\\
{\rm{ }}\quad\quad\; - \left( {{\alpha _1} + {\alpha _2}} \right) + {y^{\left( 1 \right)}}{\alpha _1}\sum\limits_{i = 3}^N {{y^{\left( i \right)}}{\alpha _i}{K_{i1}}} + {y^{\left( 2 \right)}}{\alpha _2}\sum\limits_{i = 3}^N {{y^{\left( i \right)}}{\alpha _i}{K_{i2}}}
\end{array}$

${\rm{s}}{\rm{.t    }}\; \;{\alpha _1}{y^{\left( 1 \right)}} + {\alpha _2}{y^{\left( 2 \right)}} =  - \sum\limits_{i = 3}^N {{\alpha _i}{y^{\left( i \right)}} = \varsigma } $

      $0 \le {\alpha _i} \le C{\rm{,      }}\quad i = 1{\rm{,}}2$

其中,${K_{ij}} = K\left( {{x^{\left( i \right)}}{\rm{,}}{x^{\left( j \right)}}} \right){\rm{, }}i{\rm{,}}j = 1{\rm{,}}2{\rm{,}} \cdots {\rm{,}}N$。

根据上式求得最优解$\alpha _1^{\left( {k + 1} \right)}{\rm{,}}\alpha _2^{\left( {k + 1} \right)}$,更新$\alpha $为${\alpha ^{\left( {k + 1} \right)}}$;

(3)若在精度$\varepsilon $范围内满足停止条件:

$\begin{array}{l}
\sum\limits_{i = 1}^N {{\alpha _i}{y^{\left( i \right)}} = 0} \\
0 \le {\alpha _i} \le C{\rm{, }}i = 1{\rm{,}}2{\rm{,}} \cdots {\rm{,}}N\\
{y^{\left( i \right)}} \cdot g\left( {{x^{\left( i \right)}}} \right) = \left\{ {\begin{array}{*{20}{c}}
{ \ge 1{\rm{,}}\left\{ {{x^{\left( i \right)}}|{\alpha _i} = 0} \right\}}\\
{ = 1{\rm{,}}\left\{ {{x^{\left( i \right)}}|0 < {\alpha _i} < C} \right\}}\\
{ \le 1{\rm{,}}\left\{ {{x^{\left( i \right)}}|{\alpha _i} = C} \right\}}
\end{array}} \right.
\end{array}$

其中,

$g\left( {{x^{\left( i \right)}}} \right) = \sum\limits_{j = 1}^N {{\alpha _j}{y^{\left( j \right)}}} K\left( {{x^{\left( i \right)}}{\rm{,}}{x^{\left( j \right)}}} \right) + b$

则转(4);否则令$k=k+1$,转(2);

(4)取$\widehat \alpha  = {\alpha ^{\left( {k + 1} \right)}}$。

4、支持向量机算法Python实践[1]

1)SVM算法

#coding:UTF-8
import numpy as np
import pickle

class SVM:
    def __init__(self, dataSet, labels, C, toler, kernel_option):
        self.train_x = dataSet # 训练特征
        self.train_y = labels  # 训练标签
        self.C = C # 惩罚参数
        self.toler = toler     # 迭代的终止条件之一
        self.n_samples = np.shape(dataSet)[0] # 训练样本的个数
        self.alphas = np.mat(np.zeros((self.n_samples, 1))) # 拉格朗日乘子
        self.b = 0
        self.error_tmp = np.mat(np.zeros((self.n_samples, 2))) # 保存E的缓存
        self.kernel_opt = kernel_option # 选用的核函数及其参数
        self.kernel_mat = calc_kernel(self.train_x, self.kernel_opt) # 核函数的输出

def cal_kernel_value(train_x, train_x_i, kernel_option):
    \'\'\'样本之间的核函数的值
    input:  train_x(mat):训练样本
            train_x_i(mat):第i个训练样本
            kernel_option(tuple):核函数的类型以及参数
    output: kernel_value(mat):样本之间的核函数的值
            
    \'\'\'
    kernel_type = kernel_option[0] # 核函数的类型,分为rbf和其他
    m = np.shape(train_x)[0] # 样本的个数
    
    kernel_value = np.mat(np.zeros((m, 1)))
    
    if kernel_type == \'rbf\': # rbf核函数
        sigma = kernel_option[1]
        if sigma == 0:
            sigma = 1.0
        for i in range(m):
            diff = train_x[i, :] - train_x_i
            kernel_value[i] = np.exp(diff * diff.T / (-2.0 * sigma**2))
    else: # 不使用核函数
        kernel_value = train_x * train_x_i.T
    return kernel_value


def calc_kernel(train_x, kernel_option):
    \'\'\'计算核函数矩阵
    input:  train_x(mat):训练样本的特征值
            kernel_option(tuple):核函数的类型以及参数
    output: kernel_matrix(mat):样本的核函数的值
    \'\'\'
    m = np.shape(train_x)[0] # 样本的个数
    kernel_matrix = np.mat(np.zeros((m, m))) # 初始化样本之间的核函数值
    for i in range(m):
        kernel_matrix[:, i] = cal_kernel_value(train_x, train_x[i, :], kernel_option)
    return kernel_matrix

def cal_error(svm, alpha_k):
    \'\'\'误差值的计算
    input:  svm:SVM模型
            alpha_k(int):选择出的变量
    output: error_k(float):误差值
    \'\'\'
    output_k = float(np.multiply(svm.alphas, svm.train_y).T * svm.kernel_mat[:, alpha_k] + svm.b)
    error_k = output_k - float(svm.train_y[alpha_k])
    return error_k


def update_error_tmp(svm, alpha_k):
    \'\'\'重新计算误差值
    input:  svm:SVM模型
            alpha_k(int):选择出的变量
    output: 对应误差值
    \'\'\'
    error = cal_error(svm, alpha_k)
    svm.error_tmp[alpha_k] = [1, error]

def select_second_sample_j(svm, alpha_i, error_i):
    \'\'\'选择第二个样本
    input:  svm:SVM模型
            alpha_i(int):选择出的第一个变量
            error_i(float):E_i
    output: alpha_j(int):选择出的第二个变量
            error_j(float):E_j
    \'\'\'
    # 标记为已被优化
    svm.error_tmp[alpha_i] = [1, error_i]
    candidateAlphaList = np.nonzero(svm.error_tmp[:, 0].A)[0]
    
    maxStep = 0
    alpha_j = 0
    error_j = 0

    if len(candidateAlphaList) > 1:
        for alpha_k in candidateAlphaList:
            if alpha_k == alpha_i: 
                continue
            error_k = cal_error(svm, alpha_k)
            if abs(error_k - error_i) > maxStep:
                maxStep = abs(error_k - error_i)
                alpha_j = alpha_k
                error_j = error_k
    else: # 随机选择          
        alpha_j = alpha_i
        while alpha_j == alpha_i:
            alpha_j = int(np.random.uniform(0, svm.n_samples))
        error_j = cal_error(svm, alpha_j)
    
    return alpha_j, error_j

def choose_and_update(svm, alpha_i):
    \'\'\'判断和选择两个alpha进行更新
    input:  svm:SVM模型
            alpha_i(int):选择出的第一个变量
    \'\'\'
    error_i = cal_error(svm, alpha_i) # 计算第一个样本的E_i
    
    # 判断选择出的第一个变量是否违反了KKT条件
    if (svm.train_y[alpha_i] * error_i < -svm.toler) and (svm.alphas[alpha_i] < svm.C) or\
        (svm.train_y[alpha_i] * error_i > svm.toler) and (svm.alphas[alpha_i] > 0):

        # 1、选择第二个变量
        alpha_j, error_j = select_second_sample_j(svm, alpha_i, error_i)
        alpha_i_old = svm.alphas[alpha_i].copy()
        alpha_j_old = svm.alphas[alpha_j].copy()

        # 2、计算上下界
        if svm.train_y[alpha_i] != svm.train_y[alpha_j]:
            L = max(0, svm.alphas[alpha_j] - svm.alphas[alpha_i])
            H = min(svm.C, svm.C + svm.alphas[alpha_j] - svm.alphas[alpha_i])
        else:
            L = max(0, svm.alphas[alpha_j] + svm.alphas[alpha_i] - svm.C)
            H = min(svm.C, svm.alphas[alpha_j] + svm.alphas[alpha_i])
        if L == H:
            return 0

        # 3、计算eta
        eta = 2.0 * svm.kernel_mat[alpha_i, alpha_j] - svm.kernel_mat[alpha_i, alpha_i] \
                  - svm.kernel_mat[alpha_j, alpha_j]
        if eta >= 0:
            return 0

        # 4、更新alpha_j
        svm.alphas[alpha_j] -= svm.train_y[alpha_j] * (error_i - error_j) / eta

        # 5、确定最终的alpha_j
        if svm.alphas[alpha_j] > H:
            svm.alphas[alpha_j] = H
        if svm.alphas[alpha_j] < L:
            svm.alphas[alpha_j] = L

        # 6、判断是否结束      
        if abs(alpha_j_old - svm.alphas[alpha_j]) < 0.00001:
            update_error_tmp(svm, alpha_j)
            return 0

        # 7、更新alpha_i
        svm.alphas[alpha_i] += svm.train_y[alpha_i] * svm.train_y[alpha_j] \
                                * (alpha_j_old - svm.alphas[alpha_j])

        # 8、更新b
        b1 = svm.b - error_i - svm.train_y[alpha_i] * (svm.alphas[alpha_i] - alpha_i_old) \
                                                    * svm.kernel_mat[alpha_i, alpha_i] \
                             - svm.train_y[alpha_j] * (svm.alphas[alpha_j] - alpha_j_old) \
                                                    * svm.kernel_mat[alpha_i, alpha_j]
        b2 = svm.b - error_j - svm.train_y[alpha_i] * (svm.alphas[alpha_i] - alpha_i_old) \
                                                    * svm.kernel_mat[alpha_i, alpha_j] \
                             - svm.train_y[alpha_j] * (svm.alphas[alpha_j] - alpha_j_old) \
                                                    * svm.kernel_mat[alpha_j, alpha_j]
        if (0 < svm.alphas[alpha_i]) and (svm.alphas[alpha_i] < svm.C):
            svm.b = b1
        elif (0 < svm.alphas[alpha_j]) and (svm.alphas[alpha_j] < svm.C):
            svm.b = b2
        else:
            svm.b = (b1 + b2) / 2.0

        # 9、更新error
        update_error_tmp(svm, alpha_j)
        update_error_tmp(svm, alpha_i)

        return 1
    else:
        return 0

def SVM_training(train_x, train_y, C, toler, max_iter, kernel_option = (\'rbf\', 0.431029)):
    \'\'\'SVM的训练
    input:  train_x(mat):训练数据的特征
            train_y(mat):训练数据的标签
            C(float):惩罚系数
            toler(float):迭代的终止条件之一
            max_iter(int):最大迭代次数
            kerner_option(tuple):核函数的类型及其参数
    output: svm模型
    \'\'\'
    # 1、初始化SVM分类器
    svm = SVM(train_x, train_y, C, toler, kernel_option)
    
    # 2、开始训练
    entireSet = True
    alpha_pairs_changed = 0
    iteration = 0
    
    while (iteration < max_iter) and ((alpha_pairs_changed > 0) or entireSet):
        print ("\t iterration: ", iteration)
        alpha_pairs_changed = 0

        if entireSet:
            # 对所有的样本
            for x in range(svm.n_samples):
                alpha_pairs_changed += choose_and_update(svm, x)
            iteration += 1
        else:
            # 非边界样本
            bound_samples = []
            for i in range(svm.n_samples):
                if svm.alphas[i,0] > 0 and svm.alphas[i,0] < svm.C:
                    bound_samples.append(i)
            for x in bound_samples:
                alpha_pairs_changed += choose_and_update(svm, x)
            iteration += 1
        
        # 在所有样本和非边界样本之间交替
        if entireSet:
            entireSet = False
        elif alpha_pairs_changed == 0:
            entireSet = True

    return svm

def svm_predict(svm, test_sample_x):
    \'\'\'利用SVM模型对每一个样本进行预测
    input:  svm:SVM模型
            test_sample_x(mat):样本
    output: predict(float):对样本的预测
    \'\'\'
    # 1、计算核函数矩阵
    kernel_value = cal_kernel_value(svm.train_x, test_sample_x, svm.kernel_opt)
    # 2、计算预测值
    predict = kernel_value.T * np.multiply(svm.train_y, svm.alphas) + svm.b
    return predict

def cal_accuracy(svm, test_x, test_y):
    \'\'\'计算预测的准确性
    input:  svm:SVM模型
            test_x(mat):测试的特征
            test_y(mat):测试的标签
    output: accuracy(float):预测的准确性
    \'\'\'
    n_samples = np.shape(test_x)[0] # 样本的个数
    correct = 0.0
    for i in range(n_samples):
        # 对每一个样本得到预测值
        predict=svm_predict(svm, test_x[i, :])
        # 判断每一个样本的预测值与真实值是否一致
        if np.sign(predict) == np.sign(test_y[i]):
            correct += 1
    accuracy = correct / n_samples
    return accuracy

def save_svm_model(svm_model, model_file):
    \'\'\'保存SVM模型
    input:  svm_model:SVM模型
            model_file(string):SVM模型需要保存到的文件
    \'\'\'
    with open(model_file, \'wb+\') as f:
        pickle.dump(svm_model, f)
        
View Code

2)训练

# coding:UTF-8

import numpy as np
import svm

def load_data_libsvm(data_file):
    \'\'\'导入训练数据
    input:  data_file(string):训练数据所在文件
    output: data(mat):训练样本的特征
            label(mat):训练样本的标签
    \'\'\'
    data = []
    label = []
    f = open(data_file)
    for line in f.readlines():
        lines = line.strip().split(\' \')
        
        # 提取得出label
        label.append(float(lines[0]))
        # 提取出特征,并将其放入到矩阵中
        index = 0
        tmp = []
        for i in range(1, len(lines)):
            li = lines[i].strip().split(":")
            if int(li[0]) - 1 == index:
                tmp.append(float(li[1]))
            else:
                while(int(li[0]) - 1 > index):
                    tmp.append(0)
                    index += 1
                tmp.append(float(li[1]))
            index += 1
        while len(tmp) < 13:
            tmp.append(0)
        data.append(tmp)
    f.close()
    return np.mat(data), np.mat(label).T

if __name__ == "__main__":
    # 1、导入训练数据
    print ("------------ 1、load data --------------")
    dataSet, labels = load_data_libsvm("heart_scale")
    # 2、训练SVM模型
    print ("------------ 2、training ---------------")
    C = 0.6
    toler = 0.001
    maxIter = 500
    svm_model = svm.SVM_training(dataSet, labels, C, toler, maxIter)
    # 3、计算训练的准确性
    print ("------------ 3、cal accuracy --------------")
    accuracy = svm.cal_accuracy(svm_model, dataSet, labels)  
    print ("The training accuracy is: %.3f%%" % (accuracy * 100))
    # 4、保存最终的SVM模型
    print ("------------ 4、save model ----------------")
    svm.save_svm_model(svm_model, "model_file")
View Code

3)测试

# coding:UTF-8

import numpy as np
import pickle
from svm import svm_predict

def load_test_data(test_file):
    \'\'\'导入测试数据
    input:  test_file(string):测试数据
    output: data(mat):测试样本的特征
    \'\'\'
    data = []
    f = open(test_file)
    for line in f.readlines():
        lines = line.strip().split(\' \')
        
        # 处理测试样本中的特征
        index = 0
        tmp = []
        for i in range(0, len(lines)):
            li = lines[i].strip().split(":")
            if int(li[0]) - 1 == index:
                tmp.append(float(li[1]))
            else:
                while(int(li[0]) - 1 > index):
                    tmp.append(0)
                    index += 1
                tmp.append(float(li[1]))
            index += 1
        while len(tmp) < 13:
            tmp.append(0)
        data.append(tmp)
    f.close()
    return np.mat(data)

def load_svm_model(svm_model_file):
    \'\'\'导入SVM模型
    input:  svm_model_file(string):SVM模型保存的文件
    output: svm_model:SVM模型
    \'\'\'
    with open(svm_model_file, \'rb\') as f:
        svm_model = pickle.load(f)
    return svm_model

def get_prediction(test_data, svm):
    \'\'\'对样本进行预测
    input:  test_data(mat):测试数据
            svm:SVM模型
    output: prediction(list):预测所属的类别
    \'\'\'
    m = np.shape(test_data)[0]
    prediction = []
    for i in range(m):
        # 对每一个样本得到预测值
        predict = svm_predict(svm, test_data[i, :])
        # 得到最终的预测类别
        prediction.append(str(np.sign(predict)[0, 0]))
    return prediction

def save_prediction(result_file, prediction):
    \'\'\'保存预测的结果
    input:  result_file(string):结果保存的文件
            prediction(list):预测的结果
    \'\'\'
    f = open(result_file, \'w\')
    f.write(" ".join(prediction))
    f.close()

if __name__ == "__main__":
    # 1、导入测试数据
    print ("--------- 1.load data ---------")
    test_data = load_test_data("svm_test_data")
    # 2、导入SVM模型
    print ("--------- 2.load model ----------")
    svm_model = load_svm_model("model_file")
    # 3、得到预测值
    print ("--------- 3.get prediction ---------")
    prediction = get_prediction(test_data, svm_model)
    # 4、保存最终的预测值
    print ("--------- 4.save result ----------")
    save_prediction("result", prediction)
View Code

参考文献 

[1] 赵志勇. Python机器学习算法[M]. 北京:电子工业出版社,2017.

[2] 李航. 统计学习方法[M]. 北京:清华大学出版社,2012.

[3] 周志华. 机器学习[M]. 北京:清华大学出版社,2016.

附录

数据集下载

链接:https://pan.baidu.com/s/1Dwa4cwo99o-l81uVO1Ec6w
提取码:sele