* * * The Machine Learning Noting Series * * *
目 录 | Content
1. 广义线性可分下的支持向量机构建策略
2. 在完全线性可分基础上构建广义线性可分支持向量分类模型
第一个新增限制条件:宽松的超平面边界
第二个新增限制条件:总松弛度(由进入边界样本产生)的合理限制
第三个新增限制条件:松弛变量符号的限制(应为非负数)
3. 模型求解与预测
4. python实现
1. 广义线性可分下的支持向量机构建策略
完全线性可分的支持向量机可将两类样本完全分开,而当两类样本有部分交织在一起时无法做到,此时就应采取适当宽松的策略,允许部分样本进入两类边界(用来产生超平面的一对平行线)内。如下图所示,广义线性可分下的超平面构建策略允许部分样本进入超平面与边界间,甚至跨过超平面,因此此类支持向量分类又被称为线性软间隔支持向量分类。
进入边界的样本点会带来误差的相关问题,因此广义线性可分下超平面的构建需要增加相关的限制条件:第一个是直接对进入边界的样本带来的误差进行限制;第二个是对于边界宽度进行调整,以此控制进入边界的样本数量以及误差;第三是对错误预测情况进行限制。这三点条件将会反映在超平面求解模型中,下面模型构建部分会详细叙述
2. 在完全线性可分基础上构建广义线性可分支持向量分类模型
如上图所示,记某个样本点到超平面的距离为M;到其所属类边界的距离为e;超平面边界两侧平行线距离的一半为d.
第一个新增限制条件:宽松的超平面边界
若所有样本点都不进入两类边界内(完全线性可分),则有. 当有样本进入两类边界内部时产生e,此时:
● 若e>d,则说明此样本点预测错误(因为其跨过并位于超平面另一侧),对此,应尽量避免此类情况(即第三个新增限制条件);
● 若e<d,则此样本虽然跨过了边界但仍然预测正确,对此,应对样本进入边界的“深度”进行度量并对其增加限制条件。
基于以上两点,广义线性可分模型只要求凸多边形内或则边上的样本观测点Xi到超平面的距离Mi大于等于d-ei,即 ,等价于 . 进一步,因 ,若记 ,则得到因放松超平面边界需增加的限制条件:
①
这里,e为宽松策略下对样本观测点Xi进入边界内部之“深度”的绝对度量,二非负值则为相对度量,通常称为松弛变量(Slack Variable):若 ,则样本点Xi在所属边界外侧;若 ,则Xi跨过了边界单并未跨过超平面;若 ,则Xi已跨过超平面,预测错误。
第二个新增限制条件:总松弛度(由进入边界样本产生)的合理限制
松弛变量由进入边界内部的样本点产生,而两类边界间的宽窄决定了进入边界内部样本的数量,因此这个宽窄应该在模型中有所体现。
①式不能单独成为模型约束条件,因为只要足够大就一定能满足①式,但显然应避免过大(那代表预测错误),对此,在允许个别情况下,应限制总松弛度 小于一个非负阈值E。显然,若阈值E=0,任何样本都不进入边界内部,此时相当于完全线性可分的情形;若E较小,在这种只允许较少样本进入边界内部的“偏紧”策略下,只能缩小边界宽度;反之,若E较大,则可以选择更宽的边界以此允许更多样本进入边界内部。
基于此,一般使用对错误分类的惩罚C>0参数来间接体现阈值E的大小。惩罚参数C是个可以根据对预测误差容忍度而设置的可调参数。C越大则对误差容忍度越低,因此只能选择E较小下的边界较窄的超平面。由此得到第二个新增条件:
将目标函数调整为:
②
可见C起到平衡误差和模型复杂度的作用,理想情况下两者都应较小。当C较大时,精度较高,模型复杂度较高,②式第一项较大,而第二项误差项较小,由于无法同时保证两者同时较小,因此将其相加形成②式。
下图展现了不同大小的C对超平面边界的影响。C较大或较小均没有预测价值,对此,可使用K折交叉验证来确定C。
第三个新增限制条件:松弛变量符号的限制(应为非负数)
松弛变量应为非负数,因此有第三个新增条件:
③
3. 模型求解与预测
根据上述①②③式,构造广义线性可分下的超平面参数求解模型,使用拉格朗日乘数法求解,方程为:
对新样本进行预测时,只需将样本X代入式子并且关注其符号:
其中Xi为支持向量,共有L个支持向量。若h(X)>0,则y^hat=1;若h(X)<0,则y^hat=-1.
4. python实现
这里以python 实例展示惩罚参数C的大小对支持向量分类的影响。
#导入模块
import numpy as np
from numpy import random
import pandas as pd
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import warnings
warnings.filterwarnings(action = 'ignore')
%matplotlib inline
plt.rcParams['font.sans-serif']=['SimHei'] #解决中文显示乱码问题
plt.rcParams['axes.unicode_minus']=False
from sklearn.datasets import make_classification,make_circles,make_regression
from sklearn.model_selection import train_test_split,KFold
import sklearn.neural_network as net
import sklearn.linear_model as LM
from scipy.stats import multivariate_normal
from sklearn.metrics import r2_score,mean_squared_error,classification_report
from sklearn import svm
import os
# 生成模拟数据
N=100
X,Y=make_classification(n_samples=N,n_features=2,n_redundant=0,n_informative=2,class_sep=1.2,random_state=1,n_clusters_per_class=1)
rng=np.random.RandomState(2)
X+=2*rng.uniform(size=X.shape)
X_train, X_test, Y_train, Y_test = train_test_split(X,Y,train_size=0.85, random_state=1)
plt.figure(figsize=(9,6))
markers=['^','o']
for k,m in zip([1,0],markers):
plt.scatter(X_train[Y_train==k,0],X_train[Y_train==k,1],marker=m,s=50)
plt.title("训练集中样本观测点的分布")
plt.xlabel("X1")
plt.ylabel("X2")
plt.grid(True,linestyle='-.')
plt.show()
生成的模拟数据分布如下图所示:
# 展示不用的C对超平面分类边界宽窄的影响
N=100
X,Y=make_classification(n_samples=N,n_features=2,n_redundant=0,n_informative=2,class_sep=1.2,random_state=1,n_clusters_per_class=1)
rng=np.random.RandomState(2)
X+=2*rng.uniform(size=X.shape)
X_train, X_test, Y_train, Y_test = train_test_split(X,Y,train_size=0.85, random_state=1)
X1,X2= np.meshgrid(np.linspace(X_train[:,0].min(),X_train[:,0].max(),500),np.linspace(X_train[:,1].min(),X_train[:,1].max(),500))
X0=np.hstack((X1.reshape(len(X1)*len(X2),1),X2.reshape(len(X1)*len(X2),1)))
fig,axes=plt.subplots(nrows=1,ncols=2,figsize=(15,6))
for C,H in [(5,0),(0.1,1)]:
modelSVC=svm.SVC(kernel='linear',random_state=123,C=C)
modelSVC.fit(X_train,Y_train)
Y0=modelSVC.predict(X0)
axes[H].scatter(X0[np.where(Y0==1),0],X0[np.where(Y0==1),1],c='lightgray')
axes[H].scatter(X0[np.where(Y0==0),0],X0[np.where(Y0==0),1],c='mistyrose')
for k,m in [(1,'^'),(0,'o')]:
axes[H].scatter(X_train[Y_train==k,0],X_train[Y_train==k,1],marker=m,s=40)
axes[H].scatter(X_test[Y_test==k,0],X_test[Y_test==k,1],marker=m,s=40,c='',edgecolors='g')
axes[H].scatter(modelSVC.support_vectors_[:,0],modelSVC.support_vectors_[:,1],marker='o',c='b',s=120,alpha=0.3)
axes[H].set_xlabel("X1")
axes[H].set_ylabel("X2")
axes[H].set_title("广义线性可分下的支持向量机最大边界超平面\n(C=%.1f,训练误差=%.2f)"%(C,1-modelSVC.score(X_train,Y_train)))
axes[H].grid(True,linestyle='-.')
结果如下图所示:
参考文献
《Python机器学习 数据建模与分析》,薛薇 等/著