原理
SVM是支持向量机的缩写,可用于解决分类或者回归问题。
我们前面讲过逻辑回归一类的算法,其特征如下
主要是通过一个决策面/决策边界将数据分类,但是我们可能会遇到决策边界不唯一的情况,我们将这称之为不适定问题
2
这时候要是出现一个新的数据,对于不同的决策边界,其分类结果可能会出现差异
3
SVM就是希望找到一个最优的决策边界,其实不难想象,最“中间”的那条线应该就是我们要去寻找的,具体的一些变量已经在图中画出
另外我们也要注意到,数据有时候并不会如此规整地分布,有时候误差或者噪音也会出现,如果我们完完全全将两个类别直接分开,这是Hard Margin SVM;如果对于这一两个噪音,我们希望忽视他们的存在,虽然降低了原始数据的准确率,但是换来了我们更加重视的模型泛化能力,这是Soft Margin SVM。
我们先来看Hard Margin SVM
- 其实从上面的图以及分析我们不难得出一个结论,要想找到最优化的决策边界,我们希望margin或者d参数要尽可能的大,因为这时候我们得到的决策边界方向是最优的。
- 所以SVM目标在这里就变成了最大化margin,即最大化d
- 回忆高中数学知识中的直线间距公式,我们可推导出
直线距离
其中||w||表示w的模,也就是更号下wi的平方和
如图,我们首先确定了我们的目标直线为图中函数式给出的那一条,也就是最中间的那一条
题图
对于两个类别中的数据点,他们都必须距离这个决策边界d以上的大小,于是我们得到两个不等式作为限制条件
st
我们同除d进行化简
化简1
这时候其实我们可以接着化简,因为分母就是一个数,我们只需要改改w和b即可
化简2
这时候图中三条直线便可以这样表示出来
直线距离2
我们未来将式子更好看方便,我们将wd还是记做w,bd还是记做b,但是这时候的式子意义上和之前的式子已然不同
化简3
类似于直接逻辑回归的化简,我们再进行如下变换
化简4
我们回过头来看我们的目标
目标
总结起来就是:
总结
其中st表示条件
我们再来分析Soft Margin SVM以及正则化
还是我们上面所提及的,之所以需要soft margin,是因为部分偏差误差数据,我们如果过于在意是否正确分出来,可能会导致过拟合,而我们更应该在意的是模型的泛化能力,所以我们需要做出一个拥有一定容错能力的SVM。
1
-
所谓容错能力,即意味着我们需要对之前的限制条件进行一定的宽松处理
我们将st变为:
soft
那么我们如何去限制引入的参数不至于过大呢,因为如果过大那么容错过大势必引起模型的识别率降低。
-
我们再将目标改变一下
目标改变
这时候新的总结为:(其中C是用来调节两部分的重要程度)
总结
其实这里的目标也可以这样:
正则
标准化处理
类似于knn,SVM在使用前也需要进行数据标准化处理
当一方单位很大时
当两方单位相同时
所以我们需要进行标准化处理
使用sklearn进行实现
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
iris= datasets.load_iris()
x=iris.data
y=iris.target
x=x[y<2,:2]#只选取两个类别,同时为了便于可视化只选取两个特征
y=y[y<2]
plt.scatter(x[y==0,0],x[y==0,1],color='red')
plt.scatter(x[y==1,0],x[y==1,1],color='blue')
plt.show
得到散点图
原始数据
#使用SVM算法进行分类
#先进行标准化
from sklearn.preprocessing import StandardScaler
standardScaler=StandardScaler()
standardScaler.fit(x)
x_standand=standardScaler.transform(x)
#使用线性svm
from sklearn.svm import LinearSVC#C表示分类
svc=LinearSVC(C=1e9)
svc.fit(x_standand,y)
结果1
绘制代码有些复杂,能力有限不做写出
C值很大时的结果
svc2=LinearSVC(C=0.01)
svc2.fit(x_standand,y)
svc2.score(x_standand,y)
我们调整C值,得到新的结果
结果2
C值较小时的结果
正如我们上面所分析的,减小C值可以使得容错率上升,虽然会降低一定的准确率,但是提到了模型泛化能力
SVM中使用多项式特征
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn import datasets
x,y=datasets.make_moons()
x,y=datasets.make_moons(noise=0.15)
plt.scatter(x[y==0,0],x[y==0,1])
plt.scatter(x[y==1,0],x[y==1,1])
我们可以得到这个数据集的大小为:
大小
数据集未添加噪音前的散点图为
原始散点图
加噪后
#使用多项式特征的SVM
from sklearn.preprocessing import PolynomialFeatures,StandardScaler
from sklearn.svm import LinearSVC
from sklearn.pipeline import Pipeline
def PolynomialSVC(degree,C=1):
return Pipeline([
("poly",PolynomialFeatures(degree=degree)),
("std_scaler",StandardScaler()),
("linearSVC",LinearSVC(C=C))
])
poly_svc=PolynomialSVC(degree=3)
poly_svc.fit(x,y)
poly_svc.score(x,y)
这时候我们利用sklearn中的LinearSVC进行处理,其中利用了管道
结果3
得到的score非常高
我们还可以使用多项式核函数进行处理
#使用多项式核函数的SVM
from sklearn.preprocessing import PolynomialFeatures,StandardScaler
#from sklearn.svm import LinearSVC
from sklearn.pipeline import Pipeline
from sklearn.svm import SVC
def PolynomialKernelSVC(degree,C=1.0):
return Pipeline([
#("poly",PolynomialFeatures(degree=degree)),
("std_scaler",StandardScaler()),
("kernelSVC",SVC(kernel="poly",degree=degree,C=C))#kernl参数设置为poly时可以达到多项式特征效果
])
poly_kernel_svc=PolynomialKernelSVC(degree=3)
poly_kernel_svc.fit(x,y)
poly_kernel_svc.score(x,y)
结果4
这个核函数计算的结果和前面使用poly计算的结果却是不同的,我们接着来了解核函数
核函数
我们前面得到了目标优化的函数以及条件不等式,我们可以继续转换成等价条件
等价于
回顾之前,我们是如何进行多项式分类的呢,我们是在原来数据的基础上,加上了一个多项式项,然后变成新的x'。
原来的办法
而核函数的思想是,我们可以通过一个函数运算,使得x(i),x(j)经过函数运算之后的结果直接就是x'(i)*x'(j)
核函数办法
这里的K函数即为核函数
多项式核函数
定义为: 多项式核函数,这里为二次原理
d阶的多项式核函数,d为degree
前面我们传了kernel=poly,同时degree设为3,即使用的是三阶的多项式核函数
线性核函数
高斯核函数
高斯核函数是SVM中使用最多的核函数
gamma是唯一的超参数
-
高斯核函数将每一个样本点映射到一个无穷维的特征空间
依靠升维使得原本线性不可分的数据线性可分
一维
二维
如图,我们通过升维使得原本线性不可分的数据变得线性可分
高斯核函数就是这个原理
举个例子:
高斯核函数将一维映射到二维
映射后
实际上,有多少个样本,高斯函数中就会有多少个地表点,也就是y有多少个取值,x映射到多少维
映射
由于样本数是可以无穷个,所以说,可以映射成无穷维
高斯函数分布
我们可以很容易得到gamma和sitea的关系,进而又图像我们们可以得出结论
- gamma越大,高斯分布越窄;
- gamma越小,高斯分布越宽
我们下面利用sklearn来看一下:
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
from sklearn.pipeline import Pipeline
def RBFKernelSVC(gamma=1.0):
return Pipeline([
#("poly",PolynomialFeatures(degree=degree)),
("std_scaler",StandardScaler()),
("rbfSVC",SVC(kernel="rbf",gamma=gamma))#kernl参数设置为poly时可以达到多项式特征效果
])
svc=RBFKernelSVC(gamma=1)
svc.fit(x,y)
svc.score(x,y)
决策边界gamma=1
准确率gamma=1
svc100=RBFKernelSVC(gamma=100)
svc100.fit(x,y)
svc100.score(x,y)
决策边界gamma=100
准确率gamma=100
于是我们得出结论,gamma过大时会过拟合,gamma过小时也会欠拟合,这里欠拟合的图就不贴出来了
使用SVM解决回归问题
希望数据尽可能的在线之间,与前述分类问题相反import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
boston= datasets.load_boston()
x=boston.data
y=boston.target
from sklearn.model_selection import train_test_split
x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.2,random_state=6)
#实际上这里size默认是0.2
from sklearn.svm import LinearSVR
from sklearn.svm import SVR
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
def StandardLinearSVR(epsilon=1.0):
return Pipeline([
#("poly",PolynomialFeatures(degree=degree)),
("std_scaler",StandardScaler()),
("linearSVR",LinearSVR(epsilon=epsilon))
])
svr=StandardLinearSVR()
svr.fit(x_train,y_train)
svr.score(x_test,y_test)
结果
网友评论