基于支持向量机的分类预测
SVM工作原理
支持向量机(Support Vector Machine,SVM)是一个非常优雅的算法,具有非常完善的数学理论,常用于数据分类,也可以用于数据的回归预测中,由于其其优美的理论保证和利用核函数对于线性不可分问题的处理技巧,在上世纪90年代左右,SVM曾红极一时。
解决什么问题
对于下图中的两类数据,我们的目标是找到一个最好的决策边界将两类数据分开。图中L1,L2,L3三条直线都能将两类数据点区分开,但是效果不尽相同。
假设我们要在湖和石山之间规划一条行车的通道,很容易想到,通道越宽越安全。
那么回到上面的数据划分的问题中,我们就应该选择L2作为决策边界,容错能力更强,分类效果自然比窄的好。
线性可分
通俗理解: 在二维空间上,两类点被一条直线完全分开叫做线性可分。
严格定义:
D
0
\ D_0
D0和
D
1
\ D_1
D1是n维欧式空间的两个点集。如果存在n维向量
w
\ w
w和实数
b
\ b
b,使得所有属于
D
0
\ D_0
D0的点
x
i
\ x_i
xi都有
w
x
i
+
b
>
0
\ wx_i + b>0
wxi+b>0,而对于所有属于
D
1
\ D_1
D1的点
x
j
\ x_j
xj则有
w
x
j
+
b
<
0
\ wx_j+b<0
wxj+b<0,则我们称
D
0
\ D_0
D0 和
D
1
\ D_1
D1 线性可分。
距离
对于上述
w
x
j
+
b
=
0
\ wx_j+b=0
wxj+b=0平面,平面上有
x
’
\ x^’
x’和
x
"
\ x^"
x"两点,
W
\ W
W 为平面的法向量,要求点
x
\ x
x到平面的距离。可先计算
x
\ x
x点到
x
’
\ x^’
x’的距离,再投影到平面的法向量上,就可以得到距离定义为:
d
i
s
t
a
n
c
e
(
x
)
=
∣
w
T
∥
w
∥
(
x
−
x
’
)
∣
=
1
∥
w
∥
∣
w
T
x
+
b
∣
\ distance(x)=\vert \cfrac{w^T }{\Vert w \Vert} (x-x^’)\vert=\cfrac{1}{\Vert w \Vert}\vert w^Tx+b \vert
distance(x)=∣∥w∥wT(x−x’)∣=∥w∥1∣wTx+b∣其中,
w
T
∥
w
∥
\cfrac{w^T }{\Vert w \Vert}
∥w∥wT为平面法向量的方向,
∥
w
∥
=
w
1
2
+
w
2
2
+
.
.
.
+
w
n
2
\Vert w \Vert=\sqrt{w_1^2+w_2^2+...+w_n^2}
∥w∥=w12+w22+...+wn2
从二维扩展到多维空间中时,将
D
0
\ D_0
D0和
D
1
\ D_1
D1完全正确地划分开的
w
x
j
+
b
=
0
\ wx_j+b=0
wxj+b=0就成了一个超平面。
为了使这个超平面更具鲁棒性,我们会去找最佳超平面,以最大间隔把两类样本分开的超平面,也称之为最大间隔超平面。
- 两类样本分别分割在该超平面的两侧;
- 两侧距离超平面最近的样本点到超平面的距离被最大化了。
支撑向量
样本中距离超平面最近的一些点,这些点叫做支持向量。
图片来源
标签定义
将数据集定义为
(
X
1
,
Y
1
)
(
X
2
,
Y
2
)
.
.
.
(
X
n
,
Y
n
)
\ (X_1,Y_1)(X_2,Y_2)...(X_n,Y_n)
(X1,Y1)(X2,Y2)...(Xn,Yn),其中,
X
n
\ X_n
Xn为数据的特征,
Y
n
\ Y_n
Yn为数据中的标签,当
X
n
X_n
Xn在
D
0
\ D_0
D0数据集中时,
Y
n
=
+
1
\ Y_n=+1
Yn=+1,当
X
n
X_n
Xn在
D
1
\ D_1
D1数据集中时,
Y
n
=
−
1
\ Y_n=-1
Yn=−1,那么最终的决策方程可以化简为
y
(
x
)
=
w
T
ψ
(
x
)
+
b
\ y(x)=w^T\psi(x)+b
y(x)=wTψ(x)+b
其中
ψ
(
x
)
\psi(x)
ψ(x)表示对数据进行某种变换,可不管他,认为仍是
x
\ x
x,即:
y
(
x
)
=
w
T
x
+
b
\ y(x)=w^Tx+b
y(x)=wTx+b
令,
y
i
y
(
x
)
=
y
i
(
w
T
x
+
b
)
=
1
\ y_iy(x)=y_i(w^Tx+b)=1
yiy(x)=yi(wTx+b)=1,可以得到如下图所示的两个最大间隔超平面的上下两个超平面,距离最大间隔超平面距离为1,重要的的特性是
y
i
y
(
x
)
>
0
\ y_iy(x)>0
yiy(x)>0。
图片来源
目标函数
已知的信息: 数据点和距离计算方式。
要做的事: 寻找一个最优的决策方程也就是
w
\ w
w和
b
\ b
b的值。
优化的目标: 使得离决策方程(超平面)最近的点的距离越远越好。
基于
y
i
y
(
x
i
)
>
0
\ y_iy(x_i)>0
yiy(xi)>0,其中
y
(
x
i
)
\ y(x_i)
y(xi)即
∣
w
T
x
+
b
∣
\vert w^Tx+b\vert
∣wTx+b∣,由于标签值只能是±1,所以乘
y
i
\ y_i
yi不会改变结果,但能直接把绝对值去掉,所以距离公式可以直接化简为:
d
i
s
t
a
n
c
e
(
x
)
=
1
∥
w
∥
∣
w
T
ψ
(
x
)
+
b
∣
=
y
i
(
w
T
ψ
(
x
)
+
b
)
∥
w
∥
\ distance(x)=\cfrac{1}{\Vert w \Vert}\vert w^T\psi(x)+b \vert=\cfrac{y_i(w^T\psi(x)+b)}{\Vert w \Vert}
distance(x)=∥w∥1∣wTψ(x)+b∣=∥w∥yi(wTψ(x)+b)
所以目标函数可以定义为:
arg
max
w
,
b
{
1
∥
w
∥
min
i
[
y
i
(
w
T
ψ
(
x
i
)
)
+
b
]
}
\mathop{\arg\max}\limits_{w,b}\{\cfrac{1}{\Vert w \Vert}\mathop{\min}\limits_{i}\ [y_i(w^T\psi(x_i))+b \ ] \}
w,bargmax{∥w∥1imin [yi(wTψ(xi))+b ]}
上式首先要求的是距离,目的在于找到里边界最近的样本点,然后再求
arg
max
w
,
b
\mathop{\arg\max}\limits_{w,b}
w,bargmax,也就是找到最合适的决策边界
w
和
b
\ w 和 b
w和b,使其离这个样本点的距离越大越好。
为了方便求解,需要对上式进行化简,因为
y
i
y
(
x
)
>
0
\ y_iy(x)>0
yiy(x)>0,通过缩放变换把要求变得更严,令
y
i
(
w
T
x
i
+
b
)
≥
1
\ y_i(w^Tx_i+b)≥1
yi(wTxi+b)≥1,可得
min
i
[
y
i
(
w
T
ψ
(
x
i
)
)
+
b
]
\mathop{\min}\limits_{i}\ [ y_i(w^T\psi(x_i))+b \ ]
imin [yi(wTψ(xi))+b ]的最小值就是1。因此只需要考虑
arg
max
w
,
b
{
1
∥
w
∥
}
\mathop{\arg\max}\limits_{w,b}\{\cfrac{1}{\Vert w \Vert}\}
w,bargmax{∥w∥1}即可。新的目标函数为:
{
arg
max
w
,
b
{
1
∥
w
∥
}
s
t
.
y
i
(
w
T
ψ
(
x
i
)
+
b
)
≥
1
\begin{cases}\mathop{\arg\max}\limits_{w,b}\{\cfrac{1}{\Vert w \Vert}\}\\st. \ \ \ y_i(w^T\psi(x_i)+b)≥1\end{cases}
⎩⎪⎨⎪⎧w,bargmax{∥w∥1}st. yi(wTψ(xi)+b)≥1
上式是一个极大值问题,但机器学习的常规套路是转换成求极小值问题,求一个数的极大值等同于求它的倒数的极小值,且我们关注的是取得极值点时的
w
和
b
w和b
w和b而非具体的极值,对于公式中的函数变换或加入常数项并不影响
w
和
b
w和b
w和b,因此上式转化为:
{
arg
min
w
,
b
{
1
2
∥
w
∥
2
}
s
t
.
y
i
(
w
T
ψ
(
x
i
)
+
b
)
≥
1
\begin{cases}\mathop{\arg\min}\limits_{w,b}\{\cfrac{1}{2}\Vert w \Vert^2\}\\st. \ \ \ y_i(w^T\psi(x_i)+b)≥1\end{cases}
⎩⎪⎨⎪⎧w,bargmin{21∥w∥2}st. yi(wTψ(xi)+b)≥1
求解
拉格朗日乘子法
拉格朗日乘子法用于计算有约束条件下函数的极值优化问题:
{
min
f
0
(
x
)
s
t
.
f
i
(
x
)
<
=
0
,
i
=
1
,
2
,
.
.
.
,
m
,
h
i
(
x
)
=
0
,
i
=
1
,
2...
,
q
\begin{cases}\mathop{\min}f_0(x)\\st.\ \ \ f_i(x)<=0,i=1,2,...,m,h_i(x)=0,i=1,2...,q\end{cases}
{minf0(x)st. fi(x)<=0,i=1,2,...,m,hi(x)=0,i=1,2...,q
min
L
(
x
,
λ
,
v
)
=
f
0
(
x
)
+
∑
i
=
1
m
λ
i
f
i
(
x
)
+
∑
i
=
1
q
v
i
h
i
(
x
)
\mathop{\min}L(x,\lambda,v)=f_0(x)+\sum\limits_{i=1}\limits^{m}\lambda_if_i(x)+\sum\limits_{i=1}\limits^{q}v_ih_i(x)
minL(x,λ,v)=f0(x)+i=1∑mλifi(x)+i=1∑qvihi(x)
直接将目标函数和约束条件套用拉格朗日乘子法,此时约束条件只有一个,得到下式:
{
min
f
(
w
)
=
arg
min
w
,
b
{
1
2
∥
w
∥
2
}
s
t
.
g
i
(
w
)
=
−
[
y
i
(
w
T
ψ
(
x
i
)
+
b
)
−
1
]
≤
0
\begin{cases}\mathop{\min}f(w)=\mathop{\arg\min}\limits_{w,b}\{\cfrac{1}{2}\Vert w \Vert^2\}\\st.\ \ \ g_i(w)=-\ [y_i(w^T\psi(x_i)+b)-1\ ]≤0\end{cases}
⎩⎪⎨⎪⎧minf(w)=w,bargmin{21∥w∥2}st. gi(w)=− [yi(wTψ(xi)+b)−1 ]≤0
进一步得到
L
(
w
,
b
,
α
)
=
1
2
∥
w
∥
2
−
∑
i
=
1
n
α
i
[
y
i
(
w
T
ψ
(
x
i
)
+
b
)
−
1
]
\ L(w,b,\alpha)=\cfrac{1}{2}\Vert w \Vert^2-\sum\limits_{i=1}\limits^{n}\alpha_i\ [ y_i(w^T\psi(x_i)+b)-1\ ]
L(w,b,α)=21∥w∥2−i=1∑nαi [yi(wTψ(xi)+b)−1 ]
对上式种
w
,
b
\ w,b
w,b求偏导,并令其偏导等于0,得到:
∂
L
∂
w
=
0
=
>
w
=
∑
i
=
1
n
α
i
y
i
ψ
(
x
i
)
∂
L
∂
b
=
0
=
>
b
=
∑
i
=
1
n
α
i
y
i
\cfrac{\partial L}{\partial w}=0 =>w=\sum\limits_{i=1}^{n}\alpha_iy_i\psi(x_i)\\\cfrac{\partial L}{\partial b}=0=>b=\sum\limits_{i=1}^{n}\alpha_iy_i
∂w∂L=0=>w=i=1∑nαiyiψ(xi)∂b∂L=0=>b=i=1∑nαiyi
上述结果代入
L
(
w
,
b
,
α
)
\ L(w,b,\alpha)
L(w,b,α),化简如下:
L
(
w
,
b
,
α
)
=
1
2
∥
w
∥
2
−
∑
i
=
1
n
α
i
[
y
i
(
w
T
ψ
(
x
i
)
+
b
)
−
1
]
=
1
2
w
T
w
−
w
T
∑
i
=
1
n
α
i
y
i
ψ
(
x
i
)
−
b
∑
i
=
1
n
α
i
y
i
+
∑
i
=
1
n
α
i
=
∑
i
=
1
n
α
i
−
1
2
∑
i
,
j
=
1
n
α
i
α
j
y
i
y
j
ψ
T
(
x
i
)
ψ
(
x
j
)
\ L(w,b,\alpha)=\cfrac{1}{2}\Vert w \Vert^2-\sum\limits_{i=1}\limits^{n}\alpha_i\ [ y_i(w^T\psi(x_i)+b)-1\ ] \\=\cfrac{1}{2}w^Tw-w^T\sum\limits_{i=1}^{n}\alpha_iy_i\psi(x_i)-b\sum\limits_{i=1}^{n}\alpha_iy_i+\sum\limits_{i=1}^{n}\alpha_i\\=\sum\limits_{i=1}^{n}\alpha_i-\cfrac{1}{2}\sum\limits_{i,j=1}^{n}\alpha_i\alpha_jy_iy_j\psi^T(x_i)\psi(x_j)
L(w,b,α)=21∥w∥2−i=1∑nαi [yi(wTψ(xi)+b)−1 ]=21wTw−wTi=1∑nαiyiψ(xi)−bi=1∑nαiyi+i=1∑nαi=i=1∑nαi−21i,j=1∑nαiαjyiyjψT(xi)ψ(xj)
此时目标变为
α
\alpha
α为多少时,
L
(
w
,
b
,
α
)
\ L(w,b,\alpha)
L(w,b,α)的值最大,转换为求其相反数的最小值:
{
min
α
1
2
∑
i
,
j
=
1
n
α
i
α
j
y
i
y
j
ψ
T
(
x
i
)
ψ
(
x
j
)
−
∑
i
=
1
n
α
i
s
t
.
∑
i
=
1
n
α
i
y
i
=
0
,
α
i
>
=
0
\begin{cases}\mathop{\min}\limits_{\alpha}\cfrac{1}{2}\sum\limits_{i,j=1}^{n}\alpha_i\alpha_jy_iy_j\psi^T(x_i)\psi(x_j)-\sum\limits_{i=1}^{n}\alpha_i\\st.\ \ \ \sum\limits_{i=1}^{n}\alpha_iy_i=0,\alpha_i>=0\end{cases}
⎩⎪⎪⎨⎪⎪⎧αmin21i,j=1∑nαiαjyiyjψT(xi)ψ(xj)−i=1∑nαist. i=1∑nαiyi=0,αi>=0
支持向量机求解
举例:
图中
x
1
(
3
,
3
)
、
x
2
(
3
,
4
)
为
正
例
,
x
3
(
1
,
1
)
为
负
例
\ x_1(3,3)、x_2(3,4)为正例,x_3(1,1)为负例
x1(3,3)、x2(3,4)为正例,x3(1,1)为负例,将三个点代入
{
min
α
1
2
∑
i
,
j
=
1
n
α
i
α
j
y
i
y
j
ψ
T
(
x
i
)
ψ
(
x
j
)
−
∑
i
=
1
n
α
i
s
t
.
∑
i
=
1
n
α
i
y
i
=
0
,
α
i
>
=
0
\begin{cases}\mathop{\min}\limits_{\alpha}\cfrac{1}{2}\sum\limits_{i,j=1}^{n}\alpha_i\alpha_jy_iy_j\psi^T(x_i)\psi(x_j)-\sum\limits_{i=1}^{n}\alpha_i\\st.\ \ \ \sum\limits_{i=1}^{n}\alpha_iy_i=0,\alpha_i>=0\end{cases}
⎩⎪⎪⎨⎪⎪⎧αmin21i,j=1∑nαiαjyiyjψT(xi)ψ(xj)−i=1∑nαist. i=1∑nαiyi=0,αi>=0中,得到:
{
min
α
1
2
[
α
1
α
1
∗
1
∗
1
∗
(
3
∗
3
+
3
∗
3
)
+
α
1
α
2
∗
1
∗
1
∗
(
3
∗
4
+
3
∗
3
)
+
α
1
α
3
∗
1
∗
(
−
1
)
+
α
2
α
1
∗
1
∗
1
∗
(
4
∗
3
+
3
∗
3
)
+
α
2
α
2
∗
1
∗
1
∗
(
4
∗
4
+
3
∗
3
)
+
α
2
α
3
∗
1
∗
(
−
1
)
∗
(
3
∗
1
+
3
∗
1
)
+
α
3
α
1
∗
(
−
1
)
∗
1
∗
(
1
∗
3
+
1
∗
3
)
+
α
3
α
2
∗
(
−
1
)
∗
1
∗
(
1
∗
4
+
1
∗
3
)
+
α
3
α
3
∗
(
−
1
)
∗
(
−
1
)
∗
(
1
∗
1
+
1
∗
1
)
]
−
(
α
1
+
α
2
+
α
3
)
s
t
.
α
1
∗
1
+
α
2
∗
1
+
α
3
∗
(
−
1
)
=
0
,
α
1
,
α
2
,
α
3
>
=
0
,
i
=
1
,
2
,
3
\begin{cases}\mathop{\min}\limits_{\alpha}\cfrac{1}{2}[\alpha_1\alpha_1*1*1*(3*3+3*3)+\alpha_1\alpha_2*1*1*(3*4+3*3)+\alpha_1\alpha_3*1*(-1)\\+\alpha_2\alpha1*1*1*(4*3+3*3)+\alpha_2\alpha_2*1*1*(4*4+3*3)+\alpha_2\alpha_3*1*(-1)*(3*1+3*1)\\+\alpha_3\alpha_1*(-1)*1*(1*3+1*3)+\alpha_3\alpha_2*(-1)*1*(1*4+1*3)+\alpha_3\alpha_3*(-1)*(-1)*(1*1+1*1)]\\-(\alpha_1+\alpha_2+\alpha_3)\\st.\ \ \ \alpha_1*1+\alpha_2*1+\alpha_3*(-1)=0,\alpha_1,\alpha_2,\alpha_3>=0,i=1,2,3\end{cases}
⎩⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎧αmin21[α1α1∗1∗1∗(3∗3+3∗3)+α1α2∗1∗1∗(3∗4+3∗3)+α1α3∗1∗(−1)+α2α1∗1∗1∗(4∗3+3∗3)+α2α2∗1∗1∗(4∗4+3∗3)+α2α3∗1∗(−1)∗(3∗1+3∗1)+α3α1∗(−1)∗1∗(1∗3+1∗3)+α3α2∗(−1)∗1∗(1∗4+1∗3)+α3α3∗(−1)∗(−1)∗(1∗1+1∗1)]−(α1+α2+α3)st. α1∗1+α2∗1+α3∗(−1)=0,α1,α2,α3>=0,i=1,2,3
两式联立,对结果中
α
1
,
α
2
\alpha_1,\alpha_2
α1,α2分别求偏导,并令偏导等于0得到:
{
α
1
=
0
,
α
2
=
2
/
13
α
1
=
0.25
,
α
2
=
0
\begin{cases}\alpha_1=0,\alpha_2=2/13\\\alpha_1=0.25,\alpha_2=0 \end{cases}
{α1=0,α2=2/13α1=0.25,α2=0
将上述两组解分别代入上上式中即可得出所有
α
1
,
2
,
3
\alpha_{1,2,3}
α1,2,3的值,再计算
w
,
b
\ w,b
w,b的值,本例解为
w
=
(
0.5
,
0.5
)
,
b
=
−
2
\ w=(0.5,0.5),b=-2
w=(0.5,0.5),b=−2
需要特别注意的是本例中
x
1
(
3
,
3
)
、
x
3
(
1
,
1
)
\ x_1(3,3)、x_3(1,1)
x1(3,3)、x3(1,1)就叫做支撑向量
调参
软间隔
在之前的分析中,需要寻找的时再将两类数据完全分开的情况下,让决策边界越宽越好,比如:
如果不考虑图中的离群点那么L2应该是我们要寻找的决策边界,但是如果要把这个点考虑进去,那么L1就应该是我们新的决策边界了。但是为了满足个别点模型做出来了较大的牺牲,这些点往往可能是异常值、离群点,这时候,可能模型就会过拟合。
我们引入软间隔允许个别样本点出现在间隔带里面。
具体过程不再阐述,参考本链接
核函数
y
i
(
w
T
ψ
(
x
i
)
+
b
)
≥
1
y_i(w^T\psi(x_i)+b)≥1
yi(wTψ(xi)+b)≥1中
ψ
(
x
i
)
\psi(x_i)
ψ(xi)就是核函数,在逻辑回归中,我们通过相关性分析,主成分分析等方法对数据降维提取主要信息,这里的核函数做的工作却是升维。
对于上面的二维线性不可分数据集,通过一种数据变换方法将其映射到三维空间中:
线性不可分任务就变得可分了。
变换的方法主要是内积运算。常用的核函数是高斯核函数:
k
(
x
1
,
x
2
)
=
<
ψ
(
x
1
)
,
ψ
(
x
2
)
>
=
e
−
∥
x
1
−
x
2
∥
2
2
σ
2
\ k(x_1,x_2)=<\psi(x_1),\psi(x_2)>=e^{\ {-\cfrac{\Vert x_1-x_2\Vert^2}{2\sigma^2}\ }}
k(x1,x2)=<ψ(x1),ψ(x2)>=e −2σ2∥x1−x2∥2
实践
Demo实践
Step1:库函数导入
## 基础函数库
import numpy as np
## 导入画图库
import matplotlib.pyplot as plt
import seaborn as sns
## 导入逻辑回归模型函数
from sklearn import svm
Step2:构建数据集并进行模型训练
##Demo演示LogisticRegression分类
构造数据集
x_fearures = np.array([[-1, -2], [-2, -1], [-3, -2], [1, 3], [2, 1], [3, 2]])
y_label = np.array([0, 0, 0, 1, 1, 1])
## 调用SVC模型 (支持向量机分类)
svc = svm.SVC(kernel='linear')#核函数为线性核函数,相当于不对数据进行变换
## 用SVM模型拟合构造的数据集
svc = svc.fit(x_fearures, y_label)
Step3:模型参数查看
## 查看其对应模型的w
print('the weight(w) of Logistic Regression:',svc.coef_)
## 查看其对应模型的b
print('the intercept(b) of Logistic Regression:',svc.intercept_)
#the weight(w) of Logistic Regression: [[0.33364706 0.33270588]]
#the intercept(b) of Logistic Regression: [-0.00031373]
超平面为: 0.33364706 ∗ x 1 + 0.33270588 ∗ x 2 − 0.00031373 = 0 \ 0.33364706*x_1+0.33270588*x_2-0.00031373=0 0.33364706∗x1+0.33270588∗x2−0.00031373=0
Step4:模型预测
## 模型预测
y_train_pred = svc.predict(x_fearures)
print('The predction result:',y_train_pred)
The predction result: [0 0 0 1 1 1]
Step5:模型可视化
#绘图函数
def plot_svc_decision_function(model, ax=None, plot_support=True):
if ax is None:
ax = plt.gca()
xlim = ax.get_xlim()
ylim = ax.get_ylim()
# 用SVM自带的decision_function函数来绘制
x = np.linspace(xlim[0], xlim[1], 30)
y = np.linspace(ylim[0], ylim[1], 30)
Y, X = np.meshgrid(y, x)
xy = np.vstack([X.ravel(), Y.ravel()]).T
P = model.decision_function(xy).reshape(X.shape)
# 绘制决策边界
ax.contour(X, Y, P, colors='k',
levels=[-1, 0, 1], alpha=0.5,
linestyles=['--', '-', '--'])
# 绘制支持向量
if plot_support:
ax.scatter(model.support_vectors_[:, 0],
model.support_vectors_[:, 1],
s=300, linewidth=1, alpha=0.2);
ax.set_xlim(xlim)
ax.set_ylim(ylim)
plt.scatter(x_fearures[:, 0], x_fearures[:, 1], c=y_label, s=50, cmap='autumn')
plot_svc_decision_function(svc)
#查看支撑向量
svc.support_vectors_
array([[-1., -2.],
[-2., -1.],
[ 2., 1.]])
支持向量机介绍
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets.samples_generator import make_blobs#引入造数函数,此写法会出现警告
from sklearn.datasets import make_blobs#引入造数函数,推荐
'''
make_blobs造数函数,产生一个数据集和相应的标签
n_samples:表示数据样本点个数,默认值100
n_features:表示数据的维度,默认值是2
centers:产生数据的中心点,默认值3
cluster_std:数据集的标准差,浮点数或者浮点数序列,默认值1.0
center_box:中心确定之后的数据边界,默认值(-10.0, 10.0)
shuffle :洗乱,默认值是True
random_state:随机生成器的种子
'''
%matplotlib inline
# 画图
X, y = make_blobs(n_samples=60, centers=2, random_state=0, cluster_std=0.4)
plt.scatter(X[:, 0], X[:, 1], c=y, s=60, cmap=plt.cm.Paired)
现在需要一个线性分类器,将这些数据分开来。我们可能会有多种分法:
# 画散点图
X, y = make_blobs(n_samples=60, centers=2, random_state=0, cluster_std=0.4)
plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap=plt.cm.Paired)
x_fit = np.linspace(0, 3)
# 画函数
y_1 = 1 * x_fit + 0.8
plt.plot(x_fit, y_1, '-c')
y_2 = -0.3 * x_fit + 3
plt.plot(x_fit, y_2, '-k')
那么现在有一个问题,两个分类器,哪一个更好呢?
为了判断好坏,我们需要引入一个准则:好的分类器不仅仅是能够很好的分开已有的数据集,还能对未知数据集进行两个的划分。
假设,现在有一个属于红色数据点的新数据(3,2.8)
# 画散点图
X, y = make_blobs(n_samples=60, centers=2, random_state=0, cluster_std=0.4)
plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap=plt.cm.Paired)
plt.scatter([3], [2.8], c='#cccc00', marker='<', s=100, cmap=plt.cm.Paired)
x_fit = np.linspace(0, 3)
# 画函数
y_1 = 1 * x_fit + 0.8
plt.plot(x_fit, y_1, '-c')
y_2 = -0.3 * x_fit + 3
plt.plot(x_fit, y_2, '-k')
可以看到,此时黑色的线会把这个新的数据集分错,而蓝色的线不会。我们刚刚举的例子可能会带有一些主观性。那么如何客观的评判两条线的健壮性呢?此时,我们需要引入一个非常重要的概念:最大间隔。最大间隔刻画着当前分类器与数据集的边界,以这两个分类器为例:
# 画散点图
X, y = make_blobs(n_samples=60, centers=2, random_state=0, cluster_std=0.4)
plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap=plt.cm.Paired)
x_fit = np.linspace(0, 3)#生成50个0到3的等差数列
# 画函数
y_1 = 1 * x_fit + 0.8
plt.plot(x_fit, y_1, '-c')
# 画边距
plt.fill_between(x_fit, y_1 - 0.6, y_1 + 0.6, edgecolor='none', color='#AAAAAA', alpha=0.4)
y_2 = -0.3 * x_fit + 3
plt.plot(x_fit, y_2, '-k')
plt.fill_between(x_fit, y_2 - 0.4, y_2 + 0.4, edgecolor='none', color='#AAAAAA', alpha=0.4)
可以看到, 蓝色的线最大间隔是大于黑色的线的。所以我们会选择蓝色的线作为我们的分类器。那么,我们现在的分类器是最优分类器吗?或者说,有没有更好的分类器,它具有更大的间隔?答案是有的。为了找出最优分类器,我们需要引入我们今天的主角:SVM。
from sklearn.svm import SVC
# SVM 函数
clf = SVC(kernel='linear')
clf.fit(X, y)
SVC(C=1.0, break_ties=False, cache_size=200, class_weight=None, coef0=0.0,decision_function_shape='ovr', degree=3, gamma='scale', kernel='linear',max_iter=-1, probability=False, random_state=None, shrinking=True,tol=0.001, verbose=False)
参数 | 说明 |
---|---|
C | C-SVC的惩罚参数C默认值是1.0C越大,相当于惩罚松弛变量,希望松弛变量接近0,即对误分类的惩罚增大,趋向于对训练集全分对的情况,这样对训练集测试时准确率很高,但泛化能力弱。C值小,对误分类的惩罚减小,允许容错,将他们当成噪声点,泛化能力较强。 |
kernel | 核函数,默认是rbf,可以是‘linear’, ‘poly’, ‘rbf’, ‘sigmoid’, ‘precomputed’ |
degree | 多项式poly函数的维度,默认是3,选择其他核函数时会被忽略。 |
gamma | ‘rbf’,‘poly’ 和‘sigmoid’的核函数参数。默认是’auto’,则会选择1/n_features |
coef0 | 核函数的常数项。对于‘poly’和 ‘sigmoid’有用。 |
probability | 是否采用概率估计.默认为False决定是否启用概率估计。需要在训练fit()模型时加上这个参数,之后才能用相关的方法:predict_proba和predict_log_proba |
shrinking | 是否采用shrinking heuristic方法,默认为true |
tol | 停止训练的误差值大小,默认为1e-3 |
cache_size | 核函数cache缓存大小,默认为200 |
class_weight | 类别的权重,字典形式传递。设置第几类的参数C为weight*C(C-SVC中的C) |
verbose | 允许冗余输出? |
max_iter | 最大迭代次数。-1为无限制。 |
decision_function_shape | ‘ovo’, ‘ovr’ or None, default=None |
random_state | 数据洗牌时的种子值,int值 |
# 最佳函数
w = clf.coef_[0]
a = -w[0] / w[1]
y_3 = a*x_fit - (clf.intercept_[0]) / w[1]
# 最大边距 下界
b_down = clf.support_vectors_[0]
y_down = a* x_fit + b_down[1] - a * b_down[0]
# 最大边距 上界
b_up = clf.support_vectors_[-1]
y_up = a* x_fit + b_up[1] - a * b_up[0]
# 画散点图
X, y = make_blobs(n_samples=60, centers=2, random_state=0, cluster_std=0.4)
plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap=plt.cm.Paired)
# 画函数
plt.plot(x_fit, y_3, '-c')
# 画边距
plt.fill_between(x_fit, y_down, y_up, edgecolor='none', color='#AAAAAA', alpha=0.4)
# 画支持向量
plt.scatter(clf.support_vectors_[:, 0], clf.support_vectors_[:, 1], edgecolor='b',
s=80, facecolors='none')
图中带蓝色边的点就是支持向量。
# 画散点图
X, y = make_blobs(n_samples=60, centers=2, random_state=0, cluster_std=0.9)
plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap=plt.cm.Paired)
这种情况并不容易找到这样的最大间隔。于是我们就有了软间隔,相比于硬间隔而言,我们允许个别数据出现在间隔带中。我们知道,如果没有一个原则进行约束,满足软间隔的分类器也会出现很多条。所以需要对分错的数据进行惩罚,SVC 函数中,有一个参数 C 就是惩罚参数。惩罚参数越小,容忍性就越大。以 C=1 为例子,比如说:
# 画散点图
X, y = make_blobs(n_samples=60, centers=2, random_state=0, cluster_std=0.9)
plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap=plt.cm.Paired)
# 惩罚参数:C=1
clf = SVC(C=1, kernel='linear')
clf.fit(X, y)
# 最佳函数
w = clf.coef_[0]
a = -w[0] / w[1]
y_3 = a*x_fit - (clf.intercept_[0]) / w[1]
# 最大边距 下界
b_down = clf.support_vectors_[0]
y_down = a* x_fit + b_down[1] - a * b_down[0]
# 最大边距 上界
b_up = clf.support_vectors_[-1]
y_up = a* x_fit + b_up[1] - a * b_up[0]
# 画散点图
X, y = make_blobs(n_samples=60, centers=2, random_state=0, cluster_std=0.4)
plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap=plt.cm.Paired)
# 画函数
plt.plot(x_fit, y_3, '-c')
# 画边距
plt.fill_between(x_fit, y_down, y_up, edgecolor='none', color='#AAAAAA', alpha=0.4)
# 画支持向量
plt.scatter(clf.support_vectors_[:, 0], clf.support_vectors_[:, 1], edgecolor='b',
s=80, facecolors='none')
图中蓝色的线为决策边界也就是刚开始说的超平面(二维情况下是不是叫超直线),最大间隔中包含了多个样本点。
惩罚参数 C=0.2 时,SVM 会更具包容性,从而兼容更多的错分样本:
X, y = make_blobs(n_samples=60, centers=2, random_state=0, cluster_std=0.9)
plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap=plt.cm.Paired)
# 惩罚参数:C=0.2
clf = SVC(C=0.2, kernel='linear')
clf.fit(X, y)
x_fit = np.linspace(-1.5, 4)
# 最佳函数
w = clf.coef_[0]
a = -w[0] / w[1]
y_3 = a*x_fit - (clf.intercept_[0]) / w[1]
# 最大边距 下界
b_down = clf.support_vectors_[10]
y_down = a* x_fit + b_down[1] - a * b_down[0]
# 最大边距 上界
b_up = clf.support_vectors_[1]
y_up = a* x_fit + b_up[1] - a * b_up[0]
# 画散点图
X, y = make_blobs(n_samples=60, centers=2, random_state=0, cluster_std=0.4)
plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap=plt.cm.Paired)
# 画函数
plt.plot(x_fit, y_3, '-c')
# 画边距
plt.fill_between(x_fit, y_down, y_up, edgecolor='none', color='#AAAAAA', alpha=0.4)
# 画支持向量
plt.scatter(clf.support_vectors_[:, 0], clf.support_vectors_[:, 1], edgecolor='b',
s=80, facecolors='none')
线性不可分问题
from sklearn.datasets.samples_generator import make_circles
# 画散点图
X, y = make_circles(100, factor=.1, noise=.1, random_state=2019)
plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap=plt.cm.Paired)
clf = SVC(kernel='linear').fit(X, y)
# 最佳函数
x_fit = np.linspace(-1.5, 1.5)
w = clf.coef_[0]
a = -w[0] / w[1]
y_3 = a*X - (clf.intercept_[0]) / w[1]
plt.plot(X, y_3, '-c')
此时线性核函数已经无法将数据分开了,我们可以将二维(低维)空间的数据映射到三维(高维)空间中。此时,我们便可以通过一个超平面对数据进行划分所以,我们映射的目的在于使用 SVM 在高维空间找到超平面的能力。
# 数据映射
r = np.exp(-(X[:, 0] ** 2 + X[:, 1] ** 2))#高斯核函数
ax = plt.subplot(projection='3d')
ax.scatter3D(X[:, 0], X[:, 1], r, c=y, s=50, cmap=plt.cm.Paired)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
x_1, y_1 = np.meshgrid(np.linspace(-1, 1), np.linspace(-1, 1))
z = 0.01*x_1 + 0.01*y_1 + 0.5
ax.plot_surface(x_1, y_1, z, alpha=0.3)
高斯核函数的解决方法
# 画图
X, y = make_circles(100, factor=.1, noise=.1, random_state=2019)
plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap=plt.cm.Paired)
clf = SVC(kernel='rbf')
clf.fit(X, y)
ax = plt.gca()
x = np.linspace(-1, 1)
y = np.linspace(-1, 1)
x_1, y_1 = np.meshgrid(x, y)
P = np.zeros_like(x_1)
for i, xi in enumerate(x):
for j, yj in enumerate(y):
P[i, j] = clf.decision_function(np.array([[xi, yj]]))
ax.contour(x_1, y_1, P, colors='k', levels=[-1, 0, 0.9], alpha=0.5,
linestyles=['--', '-', '--'])
plt.scatter(clf.support_vectors_[:, 0], clf.support_vectors_[:, 1], edgecolor='b',
s=80, facecolors='none');
可以看出对比线性核函数,结果发生了变化,不可分任务变得可分了。