支持向量的定义:在训练过程中,SVM学习每个训练数据对于表示两个类别之间的决策边界的重要性。通常只有一部分训练数据点对于定义决策边界来说很重要:位于类别之间的边界上的那些店,这些点就叫做支持向量。
想要对新样本进行预测,需要测量它与每个支持向量之间的距离以及在训练过程中学到的支持向量的重要性(保存在SVC的dual_coef_属性中)做出来的。下面我们以forge数据集训练SVM为例,对应代码如下:
from sklearn.svm import SVC
import mglearn
x, y = mglearn.tools.make_handcrafted_dataset()
svm = SVC(kernel='rbf', C=10, gamma=0.1).fit(x, y)
mglearn.plots.plot_2d_separator(svm, x, eps=.5)
mglearn.discrete_scatter(x[:, 0], x[:, 1], y)
#画出支持向量
sv = svm.support_vectors_
#支持向量的类别标签有dual_coef_的正负号给出
sv_labels = svm.dual_coef_.ravel() > 0
mglearn.discrete_scatter(sv[:, 0], sv[:, 1], sv_labels, s=15, markeredgewidth=3)
plt.xlabel("Feature 0")
plt.ylabel("feature 1")
运行后结果如下:
RBF核SVM给出的决策边界支持向量
在上述例子中,我们可以看出,SVM给出了非常光滑的曲线,而不是直线的边界。该曲线可以通过调整C值和gamma值来进行改变,我们通过如下示例来看看这两个参数调整后对曲线边界的影响,对应代码如下:
#调整C值和gamma参数对曲线的影响代码
fig, axes = plt.subplots(3, 3, figsize=(15, 10))
for ax, C in zip(axes, [-1, 0, 3]):
for a, gamma in zip(ax, range(-1, 2)):
mglearn.plots.plot_svm(log_C=C, log_gamma=gamma, ax=a)
axes[0, 0].legend(["class0", "calss 1", "sv class 0", "sv class 1"], nocl=4, loc=(.9, 1.2))
运行后对应的结果如下:
在C值和gamma值不同时的决策边界和支持向量机
由上面运行结果可知,由左到右,C值不变,gamma值逐渐增大,在gamma较小时,高斯核的半径较大,许多点都被看作是比较靠近,这是所有点都基本上归为一类。而随着gamma值增大,高斯核半径变小,这个时候更加关注单个点。小的gamma表示决策边界变化很慢,生成复杂度较低的模型,而大的gamma代表更为复杂的模型。
从上到下,C值变大,gamma值保持不变,在C值很小时,说明模型非常受限,每个数据点的影响力也非常受限。C值很小的时候,边界看起来几乎是直线的,误分类的点对边界几乎没有影响,而当C值增大后这些点对模型的影响变大,使得边界发生变化来将这些点正确分类。
下面我们将RBF核SVM应用到乳腺癌数据集上。代码如下(采用默认值C=1, gamma=1/n_features):
from sklearn.svm import LinearSVC
from sklearn.datasets import load_breast_cancer
from sklearn.svm import SVC
cancer = load_breast_cancer()
x_train, x_test, y_train, y_test = train_test_split(cancer.data, cancer.target, random_state=0)
svc = SVC()
svc.fit(x_train, y_train)
print("Accuracy on training set: {:.3f}".format(svc.score(x_train, y_train)))
print("Accuracy on test set: {:.3f}".format(svc.score(x_test, y_test)))
运行后结果如下:
Accuracy on training set: 1.000
Accuracy on test set: 0.629
从运行结果来看,在默认情况下,训练集精度十分完美,但是测试集精度却很低,说明存在较大的过拟合,我们将其对应的最大值和最小值绘制出来,对应代码如下:
plt.plot(x_train.min(axis=0), 'o', label="min")
plt.plot(x_train.max(axis=0), '^', label="max")
plt.legend(loc=4)
plt.xlabel("feature index")
plt.ylabel("feature magnitede")
plt.yscale("log")
运行结果如下:
乳腺癌数据集的特征范围
由图我们可以看出,乳腺癌数据集的特征具有完全不同的数量级,这样对其他模型来说可能关系不大,但是对于SVM确有吉大的影响。
SVM预处理数据:
为了解决SVM不同数量及的特征对SVM的影响,我们采用了数据缩放,使其大致位置都处在大致范围。核SVM常用的缩放方法就是将所有的特征缩放到0-1之间,下面我们看看如何通过人工的方法来做到这一点,对应代码如下:
#计算训练集中每个特征的最小值
min_on_train = x_train.min(axis=0)
#计算训练集中每个特征的范围(最大值-最小值)
range_on_train = (x_train - min_on_train).max(axis=0)
#减去最小值,然后除以范围,这样每个特征都是min=0和max=1
x_train_scaled = (x_train - min_on_train)/range_on_train
#将处理后的结果打印出来
print("min for each feature\n{}".format(x_train_scaled.min(axis=0)))
print("max for each feature\n{}".format(x_train_scaled.max(axis=0)))
#利用训练集的最小值和范围对测试集做相同的交换
x_test_scaled = (x_test - min_on_train)/range_on_train
svc = SVC()
svc.fit(x_train_scaled, y_train)
print("Accuracy on train_scaled set: {:.3f}".format(svc.score(x_train_scaled, y_train)))
print("Accuracy on test_scaled set: {:.3f}".format(svc.score(x_test_scaled, y_test)))
运行后结果如下:
min for each feature
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.]
max for each feature
[1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
1. 1. 1. 1. 1. 1.]
Accuracy on train_scaled set: 0.948
Accuracy on test_scaled set: 0.951
由于上述的训练集和测试集精度结果非常接近,所以该模型现在处于欠拟合状态。此时,我们可以通过调整C或gamma来拟合更为复杂的模型(增大C或gamma值),对应代码如下:
svc = SVC(C=100)
svc.fit(x_train_scaled, y_train)
print("Accuracy on train_scaled_C set: {:.3f}".format(svc.score(x_train_scaled, y_train)))
print("Accuracy on test_scaled_C set: {:.3f}".format(svc.score(x_test_scaled, y_test)))
运行后结果为:
Accuracy on train_scaled_C set: 0.986
Accuracy on test_scaled_C set: 0.965
由此可见,当C=100的时候,得到了较为完美的测试和训练集精度。
核支持向量机的优点、缺点以及参数:
该模型是非常强大的模型,在各种数据集上都能够表现出不错的精度。SVM允许决策边界很复杂,即使数据特征只有几个。它在低维和高维数据集(数据特征很少或很多)上的表现都很好,不过对应本个数的缩放表现不好。在样本数小于10000时表现不错,不过超过这个数字后面临挑战。
SVM的另一个缺点是,与处理数据和调参都需要非常小心,这也是为什么如今很多应用中用的都是基于树的模型,比如随机森林梯度提升(需要很少的预处理,甚至不需要预处理)。另外,SVM模型很难检查,我们很难知道为什么要这么预测,且很难将模型向非专家解释。
其重要的参数为正则化参数C、核的选择以及核相关参数。虽然我们主要讲的是RBF核,但是scikit-learn中海油其他选择,RBF核只有一个参数gamma,它是高斯核宽度的倒数。gamma和C控制都是模型复杂度,较大的值都是对应更为复杂的模型。因此,这两个参数的设置通常都是强烈相关的,应该同时调节。
关于核支持向量机的内容分享我们今天就说到这里,下节我们将学习深度学习之神经网络。
本文内容主要参考资料《pythong机器学习基础教程》