使用支持向量机SVM进行分类
图中的点分为了红色矩形和蓝色圆形两大类,SVM的目标是找出一条直线,可以将这两类点区分开来。和线性回归类似,可以看到,这样的直线理论上会有多条。为了从其中的筛选出一个的解,就像最小二乘法一样,我们需要引入一个可以量化的指标来描述不同直线的分类效果。
在SVM中就是通过引入分类间隔这个指标来进行评估,在上图中,中间的绿色实线是用于分类的直线,两边的虚线构成了分类间隔,在分类间隔上的样本点所构成的向量,就叫做支持向量了。
为何只考虑了分类间隔上的点呢,是因为往往就是在分类直线附件的点容易造成误判,而距离很远的点,即使不同的分类直线,其分类的效果也是相等的。所以定义了分类间隔来量化分类直线的效果。分类间隔越大,该分类直线的效果就越好。
以上只是线性可分时的情况,对于线性不可分的情况,就无法直接使用分类间隔了,此时的做法是通过核函数来升维,如下图所示
在二维平面上,红色点和绿色点无法通过一条直线隔开,此时的基本思想是升维,在高维寻找一个分类的平面。升维的方法是通过核函数,所谓核函数,就是对原有变量的一个组合函数,在下图中通过两个变量乘积的这一核函数来进行升维
升维之后在三维空间来寻找一个分类的平面,此时依然是通过分类间隔来评估分类平面的效果。可以看到,不同的核函数会扩展出不同维度的空间,对分类平面的求解会造成直接影响。
对于机器学习模型的求解,核心是最值问题,根据条件的不同,可以划分为3大类场景
1. 无约束条件的最值求解
2. 等式约束条件下的最值求解
3. 不等式约束条件下的最值求解
每种场景有对应的不同解法,对于无约束的最值求解,直接导数为零即可,比如最小二乘法;对于等式约束的最值求解,通常采用拉格朗日乘数法;对于不等式约束下的最值求解,则采用KKT条件和拉格朗日乘数法的结合;而SVM就属于第三种场景。
在scikit-learn中,提供了方便的接口来调用SVM模型,代码如下
>>> import numpy as np
>>> import matplotlib.pyplot as plt
>>> from sklearn import svm
>>> from sklearn.datasets import make_blobs
>>> X, y = make_blobs(n_samples=40, centers=2, random_state=6)
>>> clf = svm.SVC(kernel='linear', C=1000)
>>> clf.fit(X, y)
SVC(C=1000, kernel='linear')
>>> plt.scatter(X[:, 0], X[:, 1], c=y, s=30, cmap=plt.cm.Paired)
<matplotlib.collections.PathCollection object at 0x114A3FE8>
>>> ax = plt.gca()
>>> xlim = ax.get_xlim()
>>> ylim = ax.get_ylim()
>>> xx = np.linspace(xlim[0], xlim[1], 30)
>>> yy = np.linspace(ylim[0], ylim[1], 30)
>>> YY, XX = np.meshgrid(yy, xx)
>>> xy = np.vstack([XX.ravel(), YY.ravel()]).T
>>> Z = clf.decision_function(xy).reshape(XX.shape)
>>> ax.contour(XX, YY, Z, colors='k', levels=[-1, 0, 1], alpha=0.5,
... linestyles=['--', '-', '--'])
<matplotlib.contour.QuadContourSet object at 0x114B5208>
>>> ax.scatter(clf.support_vectors_[:, 0], clf.support_vectors_[:, 1], s=100,
... linewidth=1, facecolors='none', edgecolors='k')
<matplotlib.collections.PathCollection object at 0x114A3FD0>
>>>
>>> plt.show()
输出结果如下
这里展示了一个最基本的线性可分的数据,并且画出了对应的分割线和分隔间隔。对于线性不可分的数据,函数的使用方法也是一样的。对于二分类问题,除了最常见的逻辑回归外,SVM也是一个值得一试的模型。