目录
一、支持向量机(Support Vector Machine)介绍
支持向量机(Support Vector Machine
,常简称为SVM)是一种监督式学习
的方法,可广泛地应用于统计分类以及回归分析。它是将向量映射到一个更高维的空间里,在这个空间里建立有一个最大间隔超平面。在分开数据的超平面的两边建有两个互相平行的超平面,分隔超平面使两个平行超平面的距离最大化
。假定平行超平面间的距离或差距越大,分类器的总误差越小。
1. 支持向量机基本型
给定训练样本集
D
=
{
(
x
1
,
y
1
)
,
(
x
2
,
y
2
)
,
.
.
.
,
(
x
m
,
y
m
)
}
,
y
i
∈
{
−
1
,
+
1
}
D = \{{(\pmb{x_1},y_1),(\pmb{x_2},y_2),...,(\pmb{x_m},y_m)}\},y_i\in\{-1,+1\}
D={(x1x1x1,y1),(x2x2x2,y2),...,(xmxmxm,ym)},yi∈{−1,+1},分类学习最基本的想法就是基于训练集
D
D
D 在样本空间中找到一个划分超平面
,将不同类别的样本分开。
在样本空间中,划分超平面可通过如下线性方程来描述:
ω
T
x
+
b
=
0
\pmb{\omega^Tx }+ b =0
ωTxωTxωTx+b=0
其中
ω
=
(
ω
1
;
ω
2
;
.
.
.
;
ω
d
)
\pmb{\omega} = (\omega_1;\omega_2;...;\omega_d)
ωωω=(ω1;ω2;...;ωd) 为法向量,决定了超平面的方向;
b
b
b 为位移项,决定了超平面与原点的距离。显然,划分超平面可被法向量
ω
\pmb\omega
ωωω 和位移
b
b
b 确定,记为
(
ω
,
b
)
(\omega,b)
(ω,b) 。则样本空间中任意一点到超平面
(
ω
,
b
)
(\omega,b)
(ω,b) 的距离
可写为
r
=
∣
ω
T
x
+
b
∣
∣
∣
ω
∣
∣
r = \frac{|\pmb{\omega^Tx}+b|}{||\pmb\omega||}
r=∣∣ωωω∣∣∣ωTxωTxωTx+b∣
假设超平面
(
ω
,
b
)
(\omega,b)
(ω,b) 能够将训练样本正确分类,即对于
(
x
i
,
y
i
)
∈
D
(\pmb{x_i},y_i)\in D
(xixixi,yi)∈D ,若
y
i
=
+
1
y_i = +1
yi=+1,则有
ω
T
x
i
+
b
>
0
\pmb{\omega^Tx_i}+b>0
ωTxiωTxiωTxi+b>0 ;若
y
i
=
−
1
y_i = -1
yi=−1,则有
ω
T
x
i
+
b
<
0
\pmb{\omega^Tx_i}+b<0
ωTxiωTxiωTxi+b<0 。
{
ω
T
x
i
+
b
>
0
y
i
=
+
1
;
ω
T
x
i
+
b
<
0
y
i
=
−
1.
\begin{cases} \pmb{\omega^Tx_i}+b>0& y_i = +1; \\ \pmb{\omega^Tx_i}+b<0&y_i = -1.\\ \end{cases}
{ωTxiωTxiωTxi+b>0ωTxiωTxiωTxi+b<0yi=+1;yi=−1.
如图所示,距离超平面最近的几个训练样本点使式子的等号成立,被称之为“支持向量”(support vector)
,两个异类支持向量到超平面的距离之和为:
γ
=
2
∣
∣
ω
∣
∣
,
\gamma = \frac{2}{||\pmb\omega||},
γ=∣∣ωωω∣∣2,
它被称之为“间隔”(margin)。
欲找到具有“最大间隔”(maximum margin)
的划分超平面,也就是要找到能满足的参数
ω
\omega
ω 和
b
b
b ,使得
γ
\gamma
γ 最大,即
max
w
,
b
=
2
∣
∣
ω
∣
∣
s
.
t
.
y
i
(
ω
T
x
i
+
b
)
≥
1
,
i
=
1
,
2
,
.
.
.
,
m
.
\begin{aligned} &\max_{w,b}= \frac{2}{||\pmb\omega||} \\ &s.t. y_i(\omega^Tx_i+b)\geq1, i=1,2,...,m. \end{aligned}
w,bmax=∣∣ωωω∣∣2s.t.yi(ωTxi+b)≥1,i=1,2,...,m.
显然,为了最大化间隔,仅需最大化
∣
∣
ω
∣
∣
−
1
||\pmb\omega||^{-1}
∣∣ωωω∣∣−1 ,等价于最小化
∣
∣
ω
∣
∣
2
||\pmb\omega||^2
∣∣ωωω∣∣2。于是上式可重写为
min
w
,
b
=
1
2
∣
∣
ω
∣
∣
2
s.t.
y
i
(
ω
T
x
i
+
b
)
≥
1
,
i
=
1
,
2
,
.
.
.
,
m
.
\begin{aligned} &\min_{w,b}= \frac{1}{2} {||\pmb\omega||^2} \\ &\text{ s.t. } y_i(\omega^Tx_i+b)\geq1, i=1,2,...,m. \end{aligned}
w,bmin=21∣∣ωωω∣∣2 s.t. yi(ωTxi+b)≥1,i=1,2,...,m.
这就是支持向量机(Support Vector Machine
,简称
S
V
M
SVM
SVM)的基本型。
2. 核函数
对于线性不可分问题
,线性可分支持向量机并不能有效解决。例如下图中的“异或”问题就是线性不可分的。
对于这类问题,可将样本从原始空间映射到一个更高维的特征空间 ,使得样本在这个特征空间内线性可分。如上图中,若将原始的二维空间映射到一个合适的三维空间,就能找到一个合适的划分超平面。如果原始空间是有限维(即属性有限),那么一定存在一个高维特征空间使样本可分。
令
ϕ
(
x
)
\phi(\pmb x)
ϕ(xxx) 表示将
x
\pmb x
xxx 映射后的特征向量,于是,在特征空间中划分超平面所对应的模型可表示为
f
(
x
)
=
ω
T
ϕ
(
x
)
+
b
f(\pmb x) = \pmb\omega^T\phi(\pmb x) +b
f(xxx)=ωωωTϕ(xxx)+b
其中
ω
\omega
ω 和
b
b
b 是模型参数,则基本型可改写为
min
w
,
b
=
1
2
∣
∣
ω
∣
∣
2
s.t.
y
i
(
ω
T
ϕ
(
x
i
)
+
b
)
≥
1
,
i
=
1
,
2
,
.
.
.
,
m
.
\begin{aligned} &\min_{w,b}= \frac{1}{2} {||\pmb\omega||^2} \\ &\text{ s.t. } y_i(\omega^T\phi(\pmb x_i)+b)\geq1, i=1,2,...,m. \end{aligned}
w,bmin=21∣∣ωωω∣∣2 s.t. yi(ωTϕ(xxxi)+b)≥1,i=1,2,...,m.
其对偶问题是
max α ∑ i = 1 m a 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 \sum^m_{i=1}a_i-\frac{1}{2}\sum^m_{i=1}\sum^m_{j=1}\alpha_i\alpha_jy_iy_j\phi(\pmb x_i)^T\phi(\pmb x_j)\\ &\text{s.t. }\sum^m_{i=1}\alpha_iy_i = 0 ,\alpha_i\geq0,i=1,2,...,m. \end{aligned} αmaxi=1∑mai−21i=1∑mj=1∑mαiαjyiyjϕ(xxxi)Tϕ(xxxj)s.t. i=1∑mαiyi=0,αi≥0,i=1,2,...,m.
ϕ ( x i ) T ϕ ( x j ) \phi(\pmb x_i)^T\phi(\pmb x_j) ϕ(xxxi)Tϕ(xxxj) 是样本 x i \pmb x_i xxxi 与 x j \pmb x_j xxxj 映射到特征空间之后的内积。由于特征空间维数可能很高,甚至是无穷维,因此直接计算 ϕ ( x i ) T ϕ ( x j ) \phi(\pmb x_i)^T\phi(\pmb x_j) ϕ(xxxi)Tϕ(xxxj) 是非常困难的。为了避开此障碍,可以设想这样一个函数:
κ ( x i , x j ) = ⟨ ϕ ( x i ) ϕ ( x j ) ⟩ = ϕ ( x i ) T ϕ ( x j ) \kappa(\pmb x_i,\pmb x_j) =\langle{\phi(\pmb x_i)\phi(\pmb x_j)}\rangle= \phi(\pmb x_i)^T\phi(\pmb x_j) κ(xxxi,xxxj)=⟨ϕ(xxxi)ϕ(xxxj)⟩=ϕ(xxxi)Tϕ(xxxj)
即
x
i
\pmb x_i
xxxi 与
x
j
\pmb x_j
xxxj 在特征空间的内积等于它们在原始样本空间中通过函数
κ
(
⋅
,
⋅
)
\kappa(\cdot,\cdot)
κ(⋅,⋅) 计算的结果。通过此函数,就不必直接计算高维甚至无穷维特征空间中的内积。求解后即可得到:
f
(
x
)
=
ω
T
ϕ
(
x
)
+
b
=
∑
i
=
1
m
α
i
y
i
ϕ
(
x
i
)
T
ϕ
(
x
)
+
b
=
∑
i
=
1
m
α
i
y
i
κ
(
x
,
x
i
)
+
b
.
\begin{aligned} f(\pmb x)& = \pmb\omega^T\phi(\pmb x) +b\\ &= \sum^m_{i=1}\alpha_iy_i\phi(\pmb x_i)^T\phi(\pmb x)+b\\ &= \sum^m_{i=1}\alpha_iy_i\kappa(\pmb x,\pmb x_i)+b.\\ \end{aligned}
f(xxx)=ωωωTϕ(xxx)+b=i=1∑mαiyiϕ(xxxi)Tϕ(xxx)+b=i=1∑mαiyiκ(xxx,xxxi)+b.
此处的函数
κ
(
⋅
,
⋅
)
\kappa(\cdot,\cdot)
κ(⋅,⋅) 就是“核函数”(kernel function)
。模型的最优解可通过训练样本的核函数展开,这一展开式称之为“支持向量机展式”(support vector expansion)
3. 常用核函数
名称 | 表达式 | 参数 |
---|---|---|
线性核 | κ ( x , x i ) = x i T x j \kappa(\pmb x,\pmb x_i) = \pmb{x_i^Tx_j} κ(xxx,xxxi)=xiTxjxiTxjxiTxj | |
多项式核 | κ ( x , x i ) = ( x i T x j ) d \kappa(\pmb x,\pmb x_i) = (\pmb{x_i^Tx_j})^d κ(xxx,xxxi)=(xiTxjxiTxjxiTxj)d | d ≥ 1 d\geq1 d≥1 为多项式的次数 |
高斯核 | κ ( x , x i ) = e x p ( − ∥ x i − x j ∥ 2 2 σ 2 ) \kappa(\pmb x,\pmb x_i) = exp(-\frac{\|x_i-x_j\|^2}{2\sigma^2}) κ(xxx,xxxi)=exp(−2σ2∥xi−xj∥2) | σ > 0 \sigma>0 σ>0 为高斯核的带宽(width) |
拉普拉斯核 | κ ( x , x i ) = e x p ( − ∥ x i − x j ∥ σ ) \kappa(\pmb x,\pmb x_i) = exp(-\frac{\|x_i-x_j\|}{\sigma}) κ(xxx,xxxi)=exp(−σ∥xi−xj∥) | σ > 0 \sigma>0 σ>0 |
Sigmoid核 | κ ( x , x i ) = t a n h ( β x i T x j + θ ) \kappa(\pmb x,\pmb x_i) = tanh(\beta\pmb{x_i^Tx_j}+\theta) κ(xxx,xxxi)=tanh(βxiTxjxiTxjxiTxj+θ) | t a n h tanh tanh 为双曲正切函数, β > 0 , θ < 0 \beta>0,\theta<0 β>0,θ<0 |
二、基于SVM处理月亮数据集分类
- 代码准备
- 绘图函数
# 边界绘制函数
import numpy as np
from matplotlib.colors import ListedColormap
def plot_decision_boundary(model,axis):
x0,x1=np.meshgrid(
np.linspace(axis[0],axis[1],int((axis[1]-axis[0])*100)).reshape(-1,1),
np.linspace(axis[2],axis[3],int((axis[3]-axis[2])*100)).reshape(-1,1))
# meshgrid函数是从坐标向量中返回坐标矩阵
x_new=np.c_[x0.ravel(),x1.ravel()]
y_predict=model.predict(x_new)#获取预测值
zz=y_predict.reshape(x0.shape)
custom_cmap=ListedColormap(['#EF9A9A','#FFF59D','#90CAF9'])
plt.contourf(x0,x1,zz,cmap=custom_cmap)
- 生成测试数据
from sklearn import datasets #导入数据集
data_x,data_y = datasets.make_moons(n_samples=100, shuffle=True, noise=0.1, random_state=None)#生成月亮数据集
datasets.make_moons()参数解释
:
n_numbers
:生成样本数量
shuffle
:否打乱,类似于将数据集random一下
noise
:默认是false,数据集是否加入高斯噪声
random_state
:生成随机种子,给定一个int型数据,能够保证每次生成数据相同。
- 数据预处理
from sklearn.preprocessing import StandardScaler
scaler=StandardScaler()# 标准化
data_x = scaler.fit_transform(data_x)#计算训练数据的均值和方差
- 可视化样本集
import matplotlib.pyplot as plt
plt.scatter(data_x[data_y==0,0],data_x[data_y==0,1])
plt.scatter(data_x[data_y==1,0],data_x[data_y==1,1])
plt.show()
1. 基于线性核函数
from sklearn.svm import LinearSVC
liner_svc=LinearSVC(C=1e9,max_iter=100000)#线性svm分类器,iter是迭达次数
liner_svc.fit(data_x,data_y)
#画图并显示参数和截距
plot_decision_boundary(liner_svc,axis=[-3,3,-3,3])
plt.scatter(data_x[data_y==0,0],data_x[data_y==0,1],color='red')
plt.scatter(data_x[data_y==1,0],data_x[data_y==1,1],color='blue')
plt.show()
print('参数权重')
print(liner_svc.coef_)
print('模型截距')
print(liner_svc.intercept_)
2. 基于多项式核
from sklearn.preprocessing import PolynomialFeatures #导入多项式回归
from sklearn.pipeline import Pipeline #导入python里的管道
def PolynomialSVC(degree,c=10):#多项式svm
'''
:param d:阶数
:param C:正则化常数
:return:一个Pipeline实例
'''
return Pipeline([
# 将源数据 映射到 3阶多项式
("poly_features", PolynomialFeatures(degree=degree)),
# 标准化
("scaler", StandardScaler()),
# SVC线性分类器
("svm_clf", LinearSVC(C=10, loss="hinge", random_state=42,max_iter=10000))
])
poly_svc=PolynomialSVC(degree=3)
poly_svc.fit(data_x,data_y)
# 画图
plot_decision_boundary(poly_svc,axis=[-3,3,-3,3])#绘制边界
plt.scatter(data_x[data_y==0,0],data_x[data_y==0,1],color='red')#画点
plt.scatter(data_x[data_y==1,0],data_x[data_y==1,1],color='blue')
plt.show()
print('参数权重')
print(poly_svc.named_steps['svm_clf'].coef_)
print('模型截距')
print(poly_svc.named_steps['svm_clf'].intercept_)
3. 基于高斯核
from sklearn.svm import SVC #导入svm
def RBFKernelSVC(gamma=1.0):
return Pipeline([
('std_scaler',StandardScaler()),
('svc',SVC(kernel='rbf',gamma=gamma))
])
svc=RBFKernelSVC(gamma=4)#gamma参数很重要,gamma参数越大,支持向量越小
svc.fit(data_x,data_y)
plot_decision_boundary(svc,axis=[-3,3,-3,3])
plt.scatter(data_x[data_y==0,0],data_x[data_y==0,1],color='red')#画点
plt.scatter(data_x[data_y==1,0],data_x[data_y==1,1],color='blue')
plt.show()
三、基于SVM处理鸢尾花数据集分类
- 导入相关库
import numpy as np
from sklearn import datasets #导入数据集
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler
from matplotlib.colors import ListedColormap
- 编写绘图函数
# 边界绘制函数
def plot_decision_boundary(model,axis):
x0,x1=np.meshgrid(
np.linspace(axis[0],axis[1],int((axis[1]-axis[0])*100)).reshape(-1,1),
np.linspace(axis[2],axis[3],int((axis[3]-axis[2])*100)).reshape(-1,1))
# meshgrid函数是从坐标向量中返回坐标矩阵
x_new=np.c_[x0.ravel(),x1.ravel()]
y_predict=model.predict(x_new)#获取预测值
zz=y_predict.reshape(x0.shape)
custom_cmap=ListedColormap(['#EF9A9A','#FFF59D','#90CAF9'])
plt.contourf(x0,x1,zz,cmap=custom_cmap)
- 导入测试数据
iris = datasets.load_iris()
data_x = iris.data[:, :2]
data_y = iris.target
- 数据预处理
scaler=StandardScaler()# 标准化
data_x = scaler.fit_transform(data_x)#计算训练数据的均值和方差
- 绘制使用数据的散点图
plt.rcParams["font.sans-serif"] = ['SimHei'] # 用来正常显示中文标签,SimHei是字体名称,字体必须在系统中存在,字体的查看方式和安装第三部分
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
plt.scatter(data_x[data_y==0, 0],data_x[data_y==0, 1]) # 选取y所有为0的+X的第一列
plt.scatter(data_x[data_y==1, 0],data_x[data_y==1, 1]) # 选取y所有为1的+X的第一列
plt.scatter(data_x[data_y==2, 0],data_x[data_y==2, 1]) # 选取y所有为2的+X的第一列
plt.xlabel('sepal length') # 设置横坐标标注xlabel为sepal width
plt.ylabel('sepal width') # 设置纵坐标标注ylabel为sepal length
plt.title('sepal散点图') # 设置散点图的标题为sepal散点图
plt.show()
1. 基于线性核
from sklearn.svm import LinearSVC
svc_line = LinearSVC(C =1e9,max_iter=1000000) #线性SVM分类器
svc_line.fit(data_x,data_y)#训练svm
plot_decision_boundary(svc_line,axis=[-3,3,-3,4])
plt.scatter(data_x[data_y==0,0],data_x[data_y==0,1])
plt.scatter(data_x[data_y==1,0],data_x[data_y==1,1])
plt.scatter(data_x[data_y==2,0],data_x[data_y==2,1])
plt.show()
2. 基于多项式核
from sklearn.preprocessing import PolynomialFeatures #导入多项式回归
from sklearn.pipeline import Pipeline #导入python里的管道
def PolynomialSVC(degree,c=5):#多项式svm
"""
:param d:阶数
:param C:正则化常数
:return:一个Pipeline实例
"""
return Pipeline([
# 将源数据 映射到 3阶多项式
("poly_features", PolynomialFeatures(degree=degree)),
# 标准化
("scaler", StandardScaler()),
# SVC线性分类器
("svm_clf", LinearSVC(C=c, loss="hinge", random_state=42,max_iter=100000))
])
poly_svc=PolynomialSVC(degree=3)
poly_svc.fit(data_x,data_y)
plot_decision_boundary(poly_svc,axis=[-3,3,-3,4])
plt.scatter(data_x[data_y==0,0],data_x[data_y==0,1])
plt.scatter(data_x[data_y==1,0],data_x[data_y==1,1])
plt.scatter(data_x[data_y==2,0],data_x[data_y==2,1])
plt.show()
3. 基于高斯核
from sklearn.svm import SVC #导入svm
def RBFKernelSVC(gamma=1.0):
return Pipeline([
('std_scaler',StandardScaler()),
('svc',SVC(kernel='rbf',gamma=gamma))
])
svc=RBFKernelSVC(gamma=42)#gamma参数很重要,gamma参数越大,支持向量越小
svc.fit(data_x,data_y)
plot_decision_boundary(svc,axis=[-3,3,-3,4])
plt.scatter(data_x[data_y==0,0],data_x[data_y==0,1])
plt.scatter(data_x[data_y==1,0],data_x[data_y==1,1])
plt.scatter(data_x[data_y==2,0],data_x[data_y==2,1])
plt.show()
四、总结
本文通过对支持向量机(Support Vector Machine)
的原理进行阐述,并介绍了支持向量机的基本型已经常用核函数。并尝试使用多种不同的核函数对月亮数据集与鸢尾花数据集进行分类实践。
虽然SVM使用核函数可以向高维空间进行映射,并可以解决非线性分类,以此达到较好的分类效果。但其对大规模数据训练比较困难,且无法直接支持多分类,同时容易出现过拟合现象。
关于模型参数调整,需要读者自己尝试,本文测试并非最优分类。