支持向量机2--非线性SVM与核函数
支持向量机是机器学习中获得关注最多的算法之一,支持向量机涵盖有监督学习、无监督学习以及半监督学习。
功能 | |
---|---|
有监督学习 | 线性二分类与多分类(Linear Support Vector Classification) 非线性二分类与多分类(Support Vector Classification, SVC) 普通连续型变量的回归(Support Vector Regression) 概率型连续变量的回归(Bayesian SVM) |
无监督学习 | 支持向量聚类(Support Vector Clustering,SVC) 异常值检测(One-class SVM) |
半监督学习 | 转导支持向量机(Transductive Support Vector Machines,TSVM) |
支持向量机在线性和非线性分类中,效果都非常好。
从学术的角度来看,SVM是最接近深度学习的机器学习算法。线性SVM可以看成是神经网络的单个神经元(虽然损失函数与神经网络不同),非线性的SVM则与两层的神经网络相当,非线性的SVM中如果添加多个核函数,则可以模仿多层的神经网络。
支持向量机的分类方法,是在一组分布中找出一个超平面作为决策边界,使模型在数据上的分类误差尽量接近于零,尤其是在未知数据集上的分类误差(泛化误差)尽量小。
上篇文章支持向量机1中主要介绍线性分类支持向量机求解线性分类问题。但有时分类问题是非线性的,为了能够找出非线性数据的线性决策边界,需要将数据从原始的空间投射到新空间中。是一个映射函数,它代表了某种非线性的变换。使用这种变换,线性SVM的原理可以被很容易推广到非线性情况下,其推导过程和逻辑都与线性SVM一模一样,只不过在定义决策边界之前,我们必须先对数据进行升维度,即将原始的转换成。
如下非线性数据无法用线性模型将正负实例正确分开,直接用性分类支持向量机来求解此类数据,并不能得到正确的解。但可以用一条椭圆曲线(非线性模型)将其正确分开。
非线性问题往往不好求解,所以希望能用解线性分类问题的方法解决这个问题。利用核技巧,将数据从原始的空间投射到新空间中,这种非线性变换,将非线性问题变换成线性问题,通过解变换后的线性问题的方法求解原来的非线性问题。如下右图,将之前椭圆变换成直线,将非线性分类问题变换成分类问题。
设原空间为,新空间为,定义原始空间到新空间的映射:
因此原始空间的椭圆
变换成为新空间中的直线
在变换后的新空间里,直线可以将变换后的正负实例点正确分开。这样原始空间的非线性可分问题就变成了新空间的线性可分问题。
核函数
是一种能够使用数据原始空间中的向量计算来表示升维后的空间中的点积结果的数学方式。
设是输入空间,是特征空间,如果存在一个从到的映射
使得对所有,函数 满足条件
则称为核函数
核函数能够帮助我们解决三个问题:
第一,有了核函数之后,我们无需去担心究竟应该是什么样,因为非线性SVM中的核函数都是正定核函数 (positive definite kernel functions),他们都满足美世定律(Mercer's theorem),确保了高维空间中任意两个向量的点积一定可以被低维空间中的这两个向量的某种计算来表示(多数时候是点积的某种变换)。
第二,使用核函数计算低维度中的向量关系比计算原本的要简单太多了。
第三,因为计算是在原始空间中进行,所以避免了维度诅咒的问题。
核函数在支持向量机中的应用
在线性支持向量机对偶问题的目标函数中的内积可以用核函数来替代
转换成
同样分类决策函数中的内积也可以用核函数替代。
当映射函数是非线性函数时,学习到的含有核函数的支持向量机也是非线性分类模型。
# 文中绘图代码
from sklearn.datasets import make_circles
X,y = make_circles(400, factor=0.2, noise=.1)
# plt.scatter(X[:,0],X[:,1],c=y,s=50,cmap="rainbow")
def plot_svc_decision_function(model,ax=None):
if ax is None:
ax = plt.gca()
xlim = ax.get_xlim()
ylim = ax.get_ylim()
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=["--","-","--"])
ax.set_xlim(xlim)
ax.set_ylim(ylim)
clf = SVC(kernel = "linear").fit(X,y)
plt.figure(figsize=(8,6))
plt.scatter(X[:,0],X[:,1],c=y,s=50,cmap="rainbow")
plot_svc_decision_function(clf)
r = np.exp(-(X**2).sum(1))
rlim = np.linspace(min(r),max(r),0.2)
from mpl_toolkits import mplot3d
def plot_3D(elev=30,azim=30,X=X,y=y):
plt.figure(figsize=(8,8))
ax = plt.subplot(projection="3d")
ax.scatter3D(X[:,0],X[:,1],r,c=y,s=65,cmap='rainbow')
ax.view_init(elev=elev,azim=azim)
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_zlabel("r")
plt.show()
from ipywidgets import interact,fixed
interact(plot_3D,elev=[0,30],azip=(-180,180),X=fixed(X),y=fixed(y))
plt.show()
推荐阅读