支持向量机简介以及一个小实例
支持向量机(support vector machine,简称SVM)是一个功能强大且全面的机器学习模型,它能够执行线性或者非线性分类、回归以及异常值检测任务。
说明: 为了说明方便,本篇博客插入了许多图片,部分图片由《机器学习实战》的作者通过jupyter notebook绘制,上传于GitHub供大家学习。
SVM简介
线性SVM分类
首先是它的线性分类,它的基本思想可以通过下面这张图来说明,图中蓝色和土黄色代表其在特征空间中的位置,左边是三种线性分类器的分类结果,其中虚线表示的线性分类器表现非常糟糕,不能完成分类任务,而另外两个线性分类器则在训练集上表现的非常出色,然而现在也出现了一个问题:它们的决策边界过于接近,这可能导致在面对新的示例时,表现比较差。
基于这个问题,就引出了支持向量机分类器,上面的右图所示,可以看出,SVM分类器的决策边界不仅仅分离了两个类别,并且尽可能的远离了最近的训练实例。因此,我们可以将其理解为在类别之间拟合出一条最宽的街道,这个街道在图中用虚线标出。另外根据对它的介绍我们可以知道,在街道以外的地方增加实例不会对训练结果或者说决策边界产生影响,也就是说它的结果只会受到位于街道边缘的实例影响,这些实例就叫做支持向量,支持向量机的名字就是从这里得到的。
另外值得一说的是,SVM对特征的缩放非常敏感,可以通过下图直观的展示出来。下面左图中,垂直刻度就比水平刻度大得多,因此可能的最宽的街道接近于水平。右边则是经过特征缩放后的决策边界,决策边界看上去好很多。
软间隔分类与硬间隔分类
之前提到了支持向量机是在类别之间拟合出一条最宽的间隔,如果严格按照这条规则执行的话,就称为硬间隔分类。然而这种分类方法对异常值非常敏感,比如下面的左图中的情况,硬间隔是无法完成分类的,而对于右图中的情况,它的决策边界与没有异常值的情况下的决策边界大不相同,这可能会导致模型在实际工作时无法很好的完成泛化。
解决上述问题的一个办法就是允许一定的间隔违例(即允许一些实例位于街道之上或者位于错误的一侧),这样就称为软间隔分类。软间隔分类相比于硬间隔分类,其实就是尽可能在保持街道宽阔或限制间隔违例之间找到一个平衡,如下面这两张图所示。间隔或限制间隔违例之间的关系由超参数C控制,C越大,间隔越窄,但是违例也更少,反之则间隔越宽,但是违例也越多。这个C具体是什么,我们之后还会提到。
一般来说,可以通过降低C来进行正则化以解决过拟合问题。
下面是使用鸢尾花数据集,通过训练SVM来检测Virginica鸢尾花:
import numpy as np
from sklearn import datasets
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import LinearSVC
iris = datasets.load_iris()
X = iris["data"][:,(2,3)] # 特征:花瓣的长和宽
y = (iris["target"] == 2).astype(np.float64) #标签
svm_clf = Pipeline((
("scaler",StandardScaler()),
("linear_svc",LinearSVC(C=1,loss="hinge"))
))
svm_clf.fit(X,y)
svm_clf.predict([[5.5,1.7]])
# array([1.])
这里要说一下,对于线性SVM分类,可以使用的方法为LinearSVC(线性分类专用,速度快)和SVC(除了线性分类外还支持非线性分类,速度慢)。
另外,SVM分类器不会输出每个类别的概率。
非线性SVM分类
有了软间隔分类器,在许多情况下,线性SVM是非常有效的,并且通常结果出人意料的好,但是还有的许多数据集不是线性可分离的。比如下面左边这张图片中的种类就无法使用线性SVM进行分离,处理这样的数据集的方式之一就是添加更多的特征,比如多项式特征,这可能会使得数据集变为线性可分的。比如对左图中的数据集添加一个特征x2,x2等于x1的平方,此时生成的二维数据集就变得线性可分了。
左边这张图是我使用软件生成的一个二维的线性不可分的数据集。
之后我们通过添加3阶多项式特征来完成,数据集从二维的变化成了一个9维的。之后右边是在新生成的数据集上训练的结果。
完整的代码:
from sklearn.datasets import make_moons
from sklearn.svm import SVC
X, y = make_moons(n_samples=100, noise=0.15, random_state=42)
# 创建线性不可分的数据集
ploy_kernel_svm_clf = Pipeline((
("scaler",StandardScaler()),
("svm_clf",SVC(kernel="poly",degree=3,coef0=1,C=5))
#coef0控制的是受高阶多项式还是低阶多项式影响的程度
))
ploy_kernel_svm_clf.fit(X,y)
SVM回归
如之前提到的,支持向量机不仅仅可以完成分类任务,还可以完成回归任务,诀窍就是将目标反转一下:将尽可能多的实例位于间隔上,同时限制间隔违例,当然,这里的间隔违例他指的是不在间隔之内的实例。下面这张图就是一个线性回归的例子,街道宽度由超参数epsilon控制。
当然我们可以使用之前非线性分类任务中相同的手法来完成非线性回归任务。下面就是对一个一维数据集添加2阶多项式特征之后的回归结果。
SVM的数学原理
如果不需要了解的话可以跳过~
决策函数和预测
线性支持向量机判断类别的方法其实非常简单,就是将实例的特征向量与权值向量相乘,之后加上偏置项,若结果大于零则输出为1判断为正类,若结果小于0则输出为0判定为负类,见下面的式子:
y
^
=
{
0
i
f
w
T
⋅
x
+
b
<
0
,
1
i
f
w
T
⋅
x
+
b
≤
0
\hat y=\begin{cases}0\ \ \ if\ \bf w^T\cdot x+\it b<0,\\1\ \ \ if\ \bf w^T\cdot x + \it b\leq0\end{cases}
y^={0 if wT⋅x+b<0,1 if wT⋅x+b≤0
下图是包含两个特征的数据集,两个特征分别在x轴和y轴上体现,实线则是他的决策边界,从左边这个公式可以看出就是决策函数等于0的点的集合。虚线是epsilon等于1时候的间隔,就是决策函数等于等于±1时的点的集合。训练SVM就是找到合适的权重w和b的值。另外我们知道如果我们想避免任何违例,那么就要是的所有正类训练集的值大于1而所有负类训练集的决策函数小于-1。
训练目标
对于决策函数的斜率,它是等于权重向量的范数。在ϵ给定的条件下,权重向量越小,间隔越大。下面这张图就是以epsilon等于1的情况,数据集变为了1维,若果我们将w1除以2,那么间隔将会增长一倍。即权重越小,间隔越大。
根据之前的分析,SVM分类器的训练目标其实就是一个约束优化问题,对于硬间隔SVM分类器,目标就是下面公式所展示的,第一行就是让其间隔最小,第二行则是它必须满足的前提,那就是让所有点都位于间隔之外。其中权重的点积就等于权重范数的平方,将其最小化与将权重的范数最小化等价。
最
小
化
1
2
w
T
⋅
w
最小化\frac{1}{2}\bf w^T\cdot w
最小化21wT⋅w
使 得 t ( i ) ( w T ⋅ w + b ) ≥ 1 ( i = 1 , 2 , ⋯ , m ) 使得t^{(i)}(\bf w^T \cdot w \it +b)\geq 1\ (i=1,2,\cdots ,m) 使得t(i)(wT⋅w+b)≥1 (i=1,2,⋯,m)
其 中 t ( i ) = { − 1 i f y ( i ) = 0 1 i f y ( i ) = 1 其中t^{(i)}=\begin{cases}-1\ \ \ if\ y^{(i)}=0\\1\ \ \ \ \ \ if\ y^{(i)}=1\end{cases} 其中t(i)={−1 if y(i)=01 if y(i)=1
对于软间隔,需要引入一个松弛变量ζ(i),ζ(i)衡量的是第i个实例允许多大程度上的违例。那么现在就需要在减小松弛变量以减小间隔违例以及尽量增大间隔之间做出一个平衡,其目标为下面这个公式所示,可以看出它的目标中多出了一项松弛变量,C则用于在两个目标之前平衡。它要满足的条件也有所放宽,变为了所有点必须落在决策函数的绝对值大于1-ζ的范围之外。
最
小
化
1
2
w
T
⋅
w
+
C
∑
i
=
1
m
ζ
(
i
)
最小化\frac{1}{2}\bf w^T\cdot w+C\sum^m_{i=1}\zeta^{(i)}
最小化21wT⋅w+Ci=1∑mζ(i)
使 得 t ( i ) ( w T ⋅ x ( i ) + b ) ≥ 1 − ζ ( i ) , 且 ζ ( i ) ≥ 0 ( i = 1 , 2 , ⋯ , m ) 使得t^{(i)}(\bf w^T\cdot x^{(i)}\it +b)\geq 1-\zeta^{(i)},且\zeta^{(i)}\geq0\ (i=1,2,\cdots ,m) 使得t(i)(wT⋅x(i)+b)≥1−ζ(i),且ζ(i)≥0 (i=1,2,⋯,m)
对于回归任务则目标为下面这个图所示,可以看出它必须满足的条件是所有实例都位于一定的间隔之内。
最
小
化
1
2
w
T
⋅
w
+
C
∑
i
=
1
m
(
η
i
+
η
i
∗
)
使
得
(
w
T
⋅
x
i
+
b
)
−
y
i
≤
ϵ
+
η
i
y
i
−
(
w
T
⋅
x
i
+
b
)
≤
ϵ
+
η
i
∗
η
i
(
∗
)
≥
0
,
i
=
1
,
2
,
⋯
,
m
最小化\frac{1}{2}w^T\cdot w+C\sum^m_{i=1}(\eta_i+\eta^*_i)\newline 使得(w^T\cdot x_i+b)-y_i\leq\epsilon+\eta_i\\y_i-(w^T\cdot x_i+b)\leq\epsilon+\eta_i^*\\\eta_i^{(*)}\geq0,i=1,2,\cdots,m
最小化21wT⋅w+Ci=1∑m(ηi+ηi∗)使得(wT⋅xi+b)−yi≤ϵ+ηiyi−(wT⋅xi+b)≤ϵ+ηi∗ηi(∗)≥0,i=1,2,⋯,m
那么现在目标有了,如何求解呢?首先我们的问题其实属于一个二次规划问题,二次规划问题的基本形式就像下面的公式描述的那样,并且好消息是对于二次规划问题我们可以直接使用现成的二次规划求解器求解。
寻
找
p
最
小
化
1
2
p
T
⋅
H
⋅
p
+
f
T
⋅
p
寻找\bf p最小化\ \it{\frac{1}{2}}\bf p^T\cdot H \cdot p+f^T\cdot p
寻找p最小化 21pT⋅H⋅p+fT⋅p
使
得
A
⋅
p
≤
b
使得\bf A\cdot p\leq b
使得A⋅p≤b
其
中
{
p
是
一
个
n
p
维
向
量
(
n
p
为
参
数
数
量
)
H
是
一
个
n
p
×
n
p
矩
阵
f
是
一
个
n
p
维
向
量
A
是
一
个
n
c
×
n
p
矩
阵
(
n
c
为
约
束
数
量
)
b
是
一
个
n
c
维
向
量
其中\begin{cases}\bf p是一个\it n_p维向量(n_p为参数数量)\\\bf H是一个\it n_p\times n_p矩阵\\\bf f是一个\it n_p维向量\\\bf A是一个\it n_c\times n_p矩阵(n_c为约束数量)\\\bf b是一个\it n_c维向量\end{cases}
其中⎩⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎧p是一个np维向量(np为参数数量)H是一个np×np矩阵f是一个np维向量A是一个nc×np矩阵(nc为约束数量)b是一个nc维向量
讲到这里,可能会觉得支持向量机到这里基本上问题就都解决了,但是事实上并没有。比如说,我们之前使用对二维的数据集添加了3阶的多项式特征,可以看到特征直接从2个变成了9个,如果原始的数据集本身特征就比较多,在添加高阶多项式特征之后,特征总数就会变得非常非常多,这对计算是非常的不利的。
在解决这个问题之前,我想先介绍一下支持向量机的对偶问题,只要解决支持向量机的对偶问题,也就可以得到原始问题的答案。下面的公式就是SVM目标的对偶形式,通过二次规划求解器得到α之后就可以推得w和b。
寻 找 α 最 小 化 1 2 ∑ i = 1 m ∑ j = 1 m α ( i ) α ( j ) t ( i ) t ( j ) x ( i ) T ⋅ x ( j ) − ∑ i = 1 m α ( i ) 寻找\alpha最小化\ \frac{1}{2}\sum^m_{i=1}\sum^m_{j=1}\alpha ^{(i)}\alpha^{(j)}t^{(i)}t^{(j)}\bf x^{\it (i)T}\cdot x^{\it (j)}-\sum^{\it m}_{\it i=1}\alpha ^{(i)} 寻找α最小化 21i=1∑mj=1∑mα(i)α(j)t(i)t(j)x(i)T⋅x(j)−i=1∑mα(i)
使 得 α ( i ) ≥ 0 ( i = 1 , 2 , ⋯ , m ) 使得\ \bf{\alpha}^{(i)}\geq0 \ (\it i=1,2,\cdots,m) 使得 α(i)≥0 (i=1,2,⋯,m)
w ^ = ∑ i = 1 m α ( i ) t ( i ) x ( i ) \bf{\hat w}=\sum^m_{i=1}\alpha^{(i)}\it t^{(i)}\bf x^{(i)} w^=i=1∑mα(i)t(i)x(i)
b
^
=
1
n
s
∑
i
=
1
α
^
(
i
)
≥
0
m
(
1
−
t
(
i
)
(
w
^
T
⋅
x
(
i
)
)
)
\hat b=\frac{1}{n_s}\sum^m_{i=1 \ \hat\alpha^{(i)}\geq0 }(1-t^{(i)}(\bf \hat w^T\cdot x^{(\it i)}))
b^=ns1i=1 α^(i)≥0∑m(1−t(i)(w^T⋅x(i)))
现在假设有一个具有两个特征的训练集,我们想添加二阶多项式特征,之后对SVM进行训练,转换后每一个实例的特征变为了3个。我们似乎需要在训练之前完成特征的转换,然后在对目标进行求解,就像下面的公式中所示的那样。
ϕ ( x ) = ϕ ( ( x 1 x 2 ) ) = ( x 1 2 2 x 1 x 2 x 2 2 ) \bf \phi (x)=\phi \begin{pmatrix}\begin{pmatrix}x_1\\x_2\end{pmatrix}\end{pmatrix}=\begin{pmatrix}x_1^2\\ \sqrt{2}x_1x_2 \\ x_2^2 \end{pmatrix} ϕ(x)=ϕ((x1x2))=⎝⎛x122x1x2x22⎠⎞
寻 找 α 最 小 化 1 2 ∑ i = 1 m ∑ j = 1 m α ( i ) α ( j ) t ( i ) t ( j ) ϕ ( x ( i ) ) T ⋅ ϕ ( x ( j ) ) − ∑ i = 1 m α ( i ) 寻找\alpha最小化\ \frac{1}{2}\sum^m_{i=1}\sum^m_{j=1}\alpha ^{(i)}\alpha^{(j)}t^{(i)}t^{(j)}\bf \phi (x^{\it (i)})^{\it T}\cdot \phi (x^{\it (j)})-\sum^{\it m}_{\it i=1}\alpha ^{(i)} 寻找α最小化 21i=1∑mj=1∑mα(i)α(j)t(i)t(j)ϕ(x(i))T⋅ϕ(x(j))−i=1∑mα(i)
使
得
α
(
i
)
≥
0
(
i
=
1
,
2
,
⋯
,
m
)
使得\ \bf{\alpha}^{(i)}\geq0 \ (\it i=1,2,\cdots,m)
使得 α(i)≥0 (i=1,2,⋯,m)
然而事实上并不需要,这也是我要介绍对偶问题的原因,通过下面的推导,结合之前的推导,可以知道对于对偶问题我们可以直接使用两个实例的原始特征向量的点积的平方来代替转换后特征之间的点积,提升了模型的计算效率。
ϕ ( a ) T ⋅ ϕ ( b ) = ( a 1 2 2 a 1 a 2 a 2 2 ) T ⋅ ( b 1 2 2 b 1 b 2 b 2 2 ) = a 1 2 b 1 2 + 2 a 1 b 1 a 2 b 2 + a 2 2 b 2 2 \phi(\bf a)^{\it T}\cdot\phi(b)=\begin{pmatrix}a_1^2\\\sqrt{2}a_1a_2\\a_2^2\end{pmatrix}^{\it T}\cdot \begin{pmatrix}b_1^2\\ \sqrt{2}b_1b_2 \\ b_2^2\end{pmatrix}=\it a_1^2b_1^2+2a_1b_1a_2b_2+a_2^2b_2^2 ϕ(a)T⋅ϕ(b)=⎝⎛a122a1a2a22⎠⎞T⋅⎝⎛b122b1b2b22⎠⎞=a12b12+2a1b1a2b2+a22b22
= ( a T ⋅ b ) 2 \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =(\bf a^{\it T}\cdot b)^{\it 2} =(aT⋅b)2
寻 找 α 最 小 化 1 2 ∑ i = 1 m ∑ j = 1 m α ( i ) α ( j ) t ( i ) t ( j ) ( a T ⋅ b ) 2 − ∑ i = 1 m α ( i ) 寻找\alpha最小化\ \frac{1}{2}\sum^m_{i=1}\sum^m_{j=1}\alpha ^{(i)}\alpha^{(j)}t^{(i)}t^{(j)}\bf (a^{\it T}\cdot b)^{\it 2}-\sum^{\it m}_{\it i=1}\alpha ^{(i)} 寻找α最小化 21i=1∑mj=1∑mα(i)α(j)t(i)t(j)(aT⋅b)2−i=1∑mα(i)
使
得
α
(
i
)
≥
0
(
i
=
1
,
2
,
⋯
,
m
)
使得\ \bf{\alpha}^{(i)}\geq0 \ (\it i=1,2,\cdots,m)
使得 α(i)≥0 (i=1,2,⋯,m)
我们提到的这个关系称为二项多项式核函数。
K
(
a
,
b
)
=
(
a
T
⋅
b
)
2
K(\bf a,b)=(a^{\it T} \cdot b)^{\it 2}
K(a,b)=(aT⋅b)2
核函数对应原始特征向量到另一维度空间的映射,下面是一些常用的核函数,使用这些核函数我们可以比较轻松的将特征映射到另外一个空间,提高了运算效率。比如说,高斯RBF核函数实际上是将特征映射到了一个无限维的空间,如果我们不使用核函数的话,这样的映射是不可能实现的。
线 性 核 函 数 : K ( a , b ) = a T ⋅ b 线性核函数:K(\bf a,b)=a^{\it T}\cdot b 线性核函数:K(a,b)=aT⋅b
多 项 式 核 函 数 : K ( a , b ) = ( γ a T ⋅ b + r ) d 多项式核函数:K(\bf a,b)=(\gamma a^{\it T}\cdot b + \it r)^d 多项式核函数:K(a,b)=(γaT⋅b+r)d
高 斯 R B F 核 函 数 : K ( a , b ) = e x p ( − γ ∣ ∣ a − b ∣ ∣ 2 ) 高斯RBF核函数:K(\bf a,b)=\it exp(-\gamma||\bf a-b||^{\it 2}) 高斯RBF核函数:K(a,b)=exp(−γ∣∣a−b∣∣2)
S i g m o i d 核 函 数 : K ( a , b ) = t a n h ( γ a T ⋅ b + r ) Sigmoid核函数:K(\bf a,b)=\it tanh(\gamma\bf a^{\it T}\cdot b+\it r) Sigmoid核函数:K(a,b)=tanh(γaT⋅b+r)
支持向量机的一个小应用
这个小应用来自MathorCup 2020 研究生组A题的一部分,简单的来说就是题目给出了无车承运平台以往发布的交易信息以及最终的交易价格,让我们根据这些数据在给定交易条件的情况下估算出一个合理的报价,保证盈利的情况下快速促成交易。
这个是他所给的数据集,数据集中包括16016个实例,每个实例都含有63个特征,包括数值、字符串以及时间序列。图中第六列就是我们需要预测的目标。
最终我们将80%的数据集作为训练集,剩下的20%的数据集作为测试集,在63个特征中选择了15个特征来对模型进行训练,下面这张图就是我们选择的特征。
对数据进行标准化等处理后对支持向量机进行训练,其中支持向量机使用的核函数为3阶多项式函数。训练好的模型在测试集上的平均绝对误差在100左右,然后下面是在测试集上的相对误差分布,可以看出支持向量机给出的绝大部分预测的相对误差都处于-5%~5%之间,表现还是非常的不错的。具体程序已上传值附件。