支撑向量机SVM(Support Vector Machine),可以解决分类问题和回归问题,
(一)数学原理
对于分类问题,其本质是找到一个决策边界,决策边界的两侧分别对应两类样本。但对于有些分类问题,决策边界不唯一,也就是不适定问题,之前的逻辑回归解决不适定问题的方法是求得损失函数的最小值。
对于下图中的决策边界,可以发现,其泛化能力较弱。出现在红色点附近的点,如果在边界的另一侧,就会被分为蓝色的类,但是显然,将其分为红色更合理。也就是说决策边界的泛化能力不够好,原因是决策边界距离其中一类样本太近。
基于此,支撑向量机的目的就是找到一条决策边界到两类样本的距离都尽可能的远,那么首先要找到每一类样本中距离边界最近的点。保证这些点到边界的距离最大化,就保证了所有样本点到边界都尽可能的远。并且要使得两类样本到便捷的距离相同,那么就应该使两边距离边界最近的点到便捷的距离相同。下图中的三个到决策边界最近的点就是支撑向量。这些点到决策边界的距离为d,而margin=2d。SVM的目的就是最大化margin。
**Hard Margin SVM**是针对线型可分问题,能够找到一条决策边界或者超平面将样本分类。
**Soft Margin SVM**则针对线性不可分问题
这里可以发现,以往的算法提升模型的泛化能力是通过模型的正则化或者数据的预处理,而支撑向量机则将模型的泛化能力考虑在了算法中。
最大化margin的方法
以上图中的情况为例,这里要实现两条直线的距离的最大化,首先支撑向量到决策边界的距离。进而扩展为空间中的高维超平面。
假设决策边界的方程为wTx+b=0。为了便于计算,将两类样本分别分类为“1”和“-1”,那么所有的样本应该满足以下条件。在直线上侧(右侧)的点,代入直线中,数值大于0,直线下侧(左侧)的点代入直线中,数值小于0.而所有点到直线的距离都大于等于d。因此,可化简为下式。之后,将式子左右两边除以d,最后用wd和bd表示除以||w||d后的参数向量和截距b。相应的,例题中用于表示范围的两条直线的方程也可做化简。图一中,决策边界的方程各系数与两外两条直线方程的系数差一个||w||d,可做进一步化简。而最后的w和b不同于开始的w和b,是为了书写方便。最后,两种分类情况下的表达式可以合并为一个数学式子,这正是之前将两类样本分别分类为1和-1的原因。所有的样本都应该满足这个不等式。
此时,回到支撑向量机的目标上===》最大化d,也就是支撑向量到决策边界的距离。设任意一个支撑向量为x,则目标转化为求①式,由于支撑向量满足方程|wTx+b|=1,因此①式可转化为②式,也就是求||w||的最小值(参数向量的模长),但为了方便求导计算,这里我们用④式表示最终目标。但是之前说过,由于所有有样本都应该在支撑向量所在的直线范围之外,因此存在一个限制条件s.t.(such that)⑤。
综上所述:支撑向量机的最终目标为求得满足⑤的条件下的④
① ② ③ ④ ⑤
(二)Soft Margin SVM和SVM的正则化
之前的Hard Margin要求两条margin之间不能存在样本,但对于有些存在极端数据或者存在极少数特殊样本的数据,依据Hard Margin建立的决策边界就会存在泛化能力弱的问题
如图①中所示对于蓝色类的样本,其中有一个样本非常靠近红色的,其他的样本与红色样本之间具有较宽的界限。这个特殊的蓝色点可能是误差数据或者极其特殊的数据,不具有代表性和一般性。但是,依据(一)中的数学原理,最终会得到“1”所在的决策边界,显然,这条决策边界受到特殊点的巨大影响,并且这样的模型泛化能力显然不如“2”对应的模型。
对于图②中的问题,这类分类问题是线性不可分问题。
以上两种情况,这就要求我们在构建模型时,需要增加一定的容错空间,以提高模型的泛化能力。这种具有容错空间的SVM就是Soft Margin SVM。
Soft Margin SVM是求满足②的条件下的①,其中η大于等于0,此时样本点可以出现在图③的虚线与margin之间,虚线的方程是式④。每一个样本对应的容错空间不同,那么每个样本的η值也不相同。
另外,η值不能过大,无穷大的容错空间对于模型的优化毫无意义。基于此,模型既要最小化参数向量w的模长,又要限制η的大小,因此目标函数为式⑤,C越大,则要求容错空间越小。式⑤对应的正则项是L1正则项,相应的式⑥对应的正则项是L2正则项,与线性回归中的L1和L2正则项格式相似。
图① 图② 图③
① ② ③ ④ ⑤ ⑥
2.1代码实现
首先实现SVM需要对数据进行标准化处理,这是因为SVM的算法中,涉及到样本点之间的距离。从图4-1可以发现。对于ABCD四个样本点,如果,数据的数量级差别不大,决策边界就是line1,如果不同指标的数量级差别太大,就有可能是ABC’D’这种情况。此时决策边界是line2,与line1的斜率明显不同(line3平行于line1),显然d2’小于d2。
图4-1
# 数据获取,以二分类为例,并且为了可视化,只考虑前两个特征
from sklearn import datasets
iris = datasets.load_iris()
x= iris.data
y = iris.target
x = x[y<2,:2]
y = y[y<2]
################################################################
====数据标准化====
from sklearn.preprocessing import StandardScaler
standardScaler = StandardScaler()
standardScaler.fit(X)
X_standard = standardScaler.transform(X)
#################################################################
===调用sklearn中的SVM===
from sklearn.svm import LinearSVC
svc = LinearSVC(C=??)#这里C的值自己选择
svc.fit(X_standard, y)
svc.coef_ #决策边界的参数
svc.intercept_ #决策边界方程对应的b值
#################################################################
====绘制决策边界和两条margin====
def plot_svc_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),
)
X_new = np.c_[x0.ravel(), x1.ravel()]
y_predict = model.predict(X_new)
zz = y_predict.reshape(x0.shape)
from matplotlib.colors import ListedColormap
custom_cmap = ListedColormap(['#EF9A9A','#FFF59D','#90CAF9'])
plt.contourf(x0, x1, zz, linewidth=5, cmap=custom_cmap)
w = model.coef_[0]
b = model.intercept_[0]
# w0*x0 + w1*x1 + b = 0
# => x1 = -w0/w1 * x0 - b/w1
plot_x = np.linspace(axis[0], axis[1], 200)
up_y = -w[0]/w[1] * plot_x - b/w[1] + 1/w[1]
down_y = -w[0]/w[1] * plot_x - b/w[1] - 1/w[1]
up_index = (up_y >= axis[2]) & (up_y <= axis[3])
down_index = (down_y >= axis[2]) & (down_y <= axis[3])
plt.plot(plot_x[up_index], up_y[up_index], color='black')
plt.plot(plot_x[down_index], down_y[down_index], color='black')
(三)多项式与核函数
对于线性不可分问题,一般的方法是给样本特征增加多项式特征。之后进行训练、预测等
====创建数据,以sklearn中的一个月亮形状的数据为例====
from sklearn import datasets
x,y=datasets.make_moons() # 无噪音数据
x,y=datasets.make_moons(noise=0.15,random_state=666) #有噪音的数据,其中noise代表标准差
=========================================================================
from sklearn.preprocessing import PolynomialFeatures,StandardScaler
from sklearn.svm import LinearSVC
from sklearn.pipeline import Pipeline
pipeline=Pipeline([
("poly",PolynomialFeatures(degree=2)),
("std",StandardScaler()),
('svc',LinearSVC(C=1))
])
3.1多项式的核函数
① ②
SVM的目标函数经过变换最终变成上式,之前的多项式问题,首先要给原来的样本增加特征,如果之前有m个样本,所有样本增加多项式特征时候,由X变成了X’‘,那么上式中的XiXj表示的是第 i 个样本和第 j 个样本相互点乘。***核函数的原理***:不是先将数据增维,然后再相乘,而是将送入核函数的样本XiXj经过数学运算直接得到X’‘iX’'j,那么①式就可以转化为②式。也就是说K函数省去了数据变形的步骤。多项式核函数的公式如下,C和d都是超参数。
(一)多项式核函数 (二)线性核函数
如下式给出了核函数的具体过程,以degree等于2,C等于1为例,其中,x和y代表两个向量,每个向量有n个维度,注意:x和y进行点乘。从下式中的变化可知,核函数在计算过程中,已经将原样本X的变形考虑进去了,变形结果如下。可见,K函数的过程兼顾了对样本的变化和样本之间的点乘。
经过以上的分析,我们知道核函数实质上就是求出样本相乘的结果。那么同样的将多项式核函数变形之后可以得到线性核函数(二)
核函数相对于PolynomialFeatures的好处:1、减少计算量,不需要先对数据进行变形。2、减少增维后的数据的存储空间。
3.2代码
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC #注意不是LinearSVC
from sklearn.pipeline import Pipeline
def PolyKearnelSVC(degree,C)
return pipeline([
('std',StandardScaler()),
('kernel',SVC(kernel='poly',degree=degree,C=C))
])
3.3高斯核函数RBF(Radial Basis Function Kernel)
(一)式高斯核函数 高斯函数
高斯核函数如上式所示,它的形式与高斯函数类似,相当于用γ代替了1/2σ2,高斯核函数中仅有一个超参数γ,
**原理:**将原来的数据点首先映射成新的特征向量,之后使新的特征向量点乘的结果。本质是将每一个样本点映射到一个无穷维的特征空间。
。
下面两图说明了核函数能够处理费非线性可分的问题的原理。多项式核函数是依靠增加维度,使线性不可分的数据点变得线性可分。如图3.3.1(a)中是一个一维的数据,两种颜色的样本线性不可分,但是给数据增加一个二次项之后得到图3.3.1(b),显然此时的样本线性可分。
至于高斯核函数的原理,为了便于观察,我们首先将(一)式中的y固定,选定两个地标(landmark),l1和l2,则原样本x可做如下变形。 图3.3.1©图3.3.1(d)
绘制图3.3.1©和图3.3.1(d)的代码
================构造数据=======================
x=np.arange(-4,5,1)
y=np.array((x>=-2)&(x<=2),dtype='int')
======================绘制3.3.1(c)图=============================
plt.scatter(x[y==0],0*x[y==0],s=150)
plt.scatter(x[y==1],0*x[y==1],s=150) # 其中s代表散点的大小
def gauss(x,l):
gamma=1.0
return np.exp(-gamma*(x-l)**2)
l1,l2=-1,1
x_new=np.empty(shape=(len(x),2))
======================将原样本进行变形=================================
for i in range(len(x)):
x_new[i,0]=gauss(x[i],l1)
x_new[i,1]=gauss(x[i],l2)
=========================绘制图3.3.1(d)==========================================
plt.scatter(x_new[y==0,0],x_new[y==0,1],s=100)
plt.scatter(x_new[y==1,0],x_new[y==1,1],s=100)
图3.3.1(a) 图3.3.1(b) 图3.3.1© 图3.3.1(d)
由以上分析可知,对于有两个给定地标landmark的情况下,,每一个远来的样本被映射成一个二维数据,而对于实际的一个m*n维的样本空间,每一个样本都是一个地标,也就是说最终样本会转换mXn=======》mXm维。也就是之前说的将每一个样本映射到无穷维的空间。
==优点:==对于高维度,样本量小的数据,时间成本低
==缺点:==如果样本数过大,则样本由低维映射到高维的时间长
代码实现:
============数据为之前的半月形数据==========
from sklearn.pipeline import Pipeline
from sklearn.preprocesing import StandardScaler
from sklearn.svm import SVC
def RBFKernelSVC(gamma=1.0,C=1.0):
return pipeline([
('std',StandardScaler()),
('rbf',SVC(kernel='rbf',gamma=1.0,C=1.0)) #此处没有C也可以,默认的C值为1.0
])
3.3.1RBF核函数中的gamma对模型的影响
gamma对应于σ的平方的倒数,在高斯函数中,σ越大图像越低平,反之越高瘦,则gamma越大图像越高瘦,gamma越小,图像越低平。
绘制分类的决策边界,下图中γ由0.5增加至100,可以看到,随着gamma增加,在这里,我们可以理解为,在每一个样本点周围形成一个高斯图像,gamma越大,钟形图像越陡越窄,那么不同点周围的钟形图像交叉的面积小,而gamma较小时,钟形图像较宽,不同点的钟形图像相互交叉重叠。可见,gamma值过高时,模型对样本点本身过于敏感,泛化能力差,而gamma值过低时,模型欠拟合。
gamma=0.1 gamma=1 gamma=10 gamma=100
(四)用SVM解决回归问题
在margin范围内尽可能的包含更多的样本。那么margin中间直线就是所要求的回归直线,数学原理是使margin与回归直线的竖直向差距尽可能的小,那么ε就是模型的一个超参数,注意,这里的ε不是margin到直线的距离,而是竖直向的差距,这是因为对回归模型的衡量结果就是判断预测值与观测值的差距大小
代码实现
=========================获取数据==============================
from sklearn import datasets
digit=datasets.load_boston()
x=digit.data
y=digit.target
===========================scikit_learn==================================
from sklearn.svm import LinearSVR #用线型SVM解决回归问题
from sklearn.svm import SVR #非线性SVM解决回归问题
from sklearn.preprocesing import StandardScaler
from sklearn.pipeline import Pipeline
pipeline=Pipeline([
('std',StandardScaler()),
('linear',LinearSVR(epsilon=1.0))
])
pipeline.fit(x_train,y_train)
pipeline.score(x_test,y_test)
以上为自己的学习笔记,学习内容来自于慕课课程:https://coding.imooc.com/class/169.html