admin 管理员组

文章数量: 888397

核支持向量机

核支持向量机(SVM)

《Python机器学习基础教程》2.3.7 读书笔记。

虽然支持向量机可以同时用于分类和回归, 但是这里我们只介绍用于分类的情况,在SVC中实现。类似的概念也适用于支持向量回归,后者在SVR中实现。

1. 线性模型与非线性特征

线性模型在低维空间中可能非常受限,因此添加更多的特征让线性模型更加灵活。

# 加载make_blobs数据集
from sklearn.datasets import make_blobs
import mglearn
import matplotlib.pyplot as plt
X, y = make_blobs(centers=4, random_state=8)
y = y % 2   # 将y分成2类mglearn.discrete_scatter(X[:, 0], X[:, 1], y)
plt.xlabel("Feature 0")
plt.ylabel("Feature 1")
plt.show()


用于分类的线性模型只能用一条直线来划分数据点, 对这个数据无法给出较好的结果。

from sklearn.svm import LinearSVC
linear_svm = LinearSVC().fit(X, y)mglearn.plots.plot_2d_separator(linear_svm, X)
mglearn.discrete_scatter(X[:, 0], X[:, 1], y)
plt.xlabel("Feature 0")
plt.ylabel("Feature 1")
plt.show()


现在我们对输入进行扩展,比如说添加第二个特征的平方作为一个新特征。现在我们将数据点表示为三维点,而不是二维点。

# 添加第二个特征的平方,作为一个新特征
import numpy as np
X_new = np.hstack([X, X[:, 1:] ** 2])from mpl_toolkits.mplot3d import Axes3D, axes3d
figure = plt.figure()
# 3D可视化
ax = Axes3D(figure, elev=-152, azim=-26)
# 首先画出所有y == 0的点, 然后画出所有y == 1的点
mask = y == 0
ax.scatter(X_new[mask, 0], X_new[mask, 1], X_new[mask, 2], c='b',cmap=mglearn.cm2, s=60)
ax.scatter(X_new[~mask, 0], X_new[~mask, 1], X_new[~mask, 2], c='r',marker='^', cmap=mglearn.cm2, s=60)
ax.set_xlabel("feature 0")
ax.set_ylabel("feature 1")
ax.set_zlabel("feature 2")
plt.show()


我们可以用线性模型将这两个类分开

linear_svm_3d = LinearSVC().fit(X_new, y)
coef, intercept = linear_svm_3d.coef_.ravel(), linear_svm_3d.intercept_# 显示线性决策边界
figure = plt.figure()
ax = Axes3D(figure, elev=-152, azim=-26)
xx = np.linspace(X_new[:, 0].min() - 2, X_new[:, 0].max() + 2, 50)
yy = np.linspace(X_new[:, 1].min() - 2, X_new[:, 1].max() + 2, 50)XX, YY = np.meshgrid(xx, yy)   # 生成网格点坐标矩阵
ZZ = (coef[0] * XX + coef[1] * YY + intercept) / -coef[2]
ax.plot_surface(XX, YY, ZZ, rstride=8, cstride=8, alpha=0.3)
ax.scatter(X_new[mask, 0], X_new[mask, 1], X_new[mask, 2], c='b',cmap=mglearn.cm2, s=60)
ax.scatter(X_new[~mask, 0], X_new[~mask, 1], X_new[~mask, 2], c='r', marker='^',cmap=mglearn.cm2, s=60)ax.set_xlabel("feature0")
ax.set_ylabel("feature1")
ax.set_zlabel("feature1 ** 2")
plt.show()


如果将线性SVM模型看作原始特征的函数, 那么它实际上已经不是线性的了。它不是一条直线,而是一个椭圆。

ZZ = YY ** 2
dec = linear_svm_3d.decision_function(np.c_[XX.ravel(), YY.ravel(), ZZ.ravel()])
plt.contourf(XX, YY, dec.reshape(XX.shape), leverls=[dec.min(), 0, dec.max()],cmap=mglearn.cm2, alpha=0.5)
mglearn.discrete_scatter(X[:, 0], X[:, 1], y)
plt.xlabel("Feature 0")
plt.ylabel("Feature 1")
plt.show()

2.理解SVM

在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")
plt.show()

3. SVM调参

gamma用于控制高斯核的宽度,C参数是正则化参数。

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(["class 0", "class 1", "sv class 0", "sv class 1"],ncol=4, loc=(.9, 1.2))
plt.show()


小的gamma值表示决策边界变化很慢,生成的是复杂度较低的模型,而大的gamma值则会生成更为复杂的模型。C值很小,说明模型非常受限,增大C之后,使得决策边界发生弯曲来将这些点正确分类。

我们将RBF核SVM应用到乳腺癌数据上。默认情况下,C=1,gamma=1/n_features:

from sklearn.model_selection import train_test_split
from sklearn.datasets import load_breast_cancer
from sklearn.svm import SVC
import matplotlib.pyplot as plt
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: {:.2f}".format(svc.score(X_train, y_train)))
print("Accuracy on test set: {:.2f}".format(svc.score(X_test, y_test)))
# 我们来看一下每个特征的最小值和最大值,它们绘制在对数坐标上
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 magnitude")
plt.yscale("log")
plt.show()

4.为SVM预处理数据

解决这个问题的一种方法是对每个特征进行缩放,核SVM常用的缩放方法就是将所有特征缩放到0和1之间。

# 计算训练集中每个特征的最小值
min_on_training = X_train.min(axis=0)
# 计算训练集中每个特征的范围(最大值-最小值)
range_on_training=(X_train - min_on_training).max(axis=0)# 减去最小值,然后除以范围
# 这样每个特征都是min=0和max=1
X_train_scaled = (X_train - min_on_training)/range_on_training
print("Minimum for each feature\n{}".format(X_train_scaled.min(axis=0)))
print("Maximum for each feature\n{}".format(X_train_scaled.max(axis=0)))
# 利用训练集的最小值和范围对测试集做相同的变换
X_test_scaled = (X_test - min_on_training)/range_on_training
svc=SVC()
# 拟合SVC
svc.fit(X_train_scaled, y_train)print("Accuracy on training set: {:.3f}".format(svc.score(X_train_scaled, y_train)))
print("Accuracy on test set:{:.3f}".format(svc.score(X_test_scaled, y_test)))

数据缩放作用很大!, 实际模型处于欠拟合,尝试增大C或gamma来拟合更为复杂的模型。例如:

# 增大C,或gamma
svc = SVC(C=1000)
svc.fit(X_train_scaled, y_train)print("Accuracy on training set: {:.3f}".format(svc.score(X_train_scaled, y_train)))
print("Accuracy on test set: {:.3f}".format(svc.score(X_test_scaled, y_test)))

本文标签: 核支持向量机