支持向量机(SVM)----sklearn库的应用

支持向量机(SVM)----sklearn库的应用

本文主要实现sklearn库中的支持向量机SVM模型,希望能够帮助到大家。

维度升级及切分图像

线性模型在低维空间中可能非常受限,因为线和平面的灵活度十分有限。

有一种方法可以让线性模型更加灵活,就是添加更多的特征,例如添加特征的交互项或者多项式,专业术语即维度升级

先看一下如下的数据集

from sklearn.datasets import make_blobs            #导入斑点(blobs)数据集
import matplotlib.pyplot as plt
import mglearn

X, y = make_blobs(centers=4, random_state=8)          #生成4团斑点数据
y = y%2                                               #通过取余操作,将原来的4个类别(0,1,2,3)转化为2个类别(0,1)

mglearn.discrete_scatter(X[:,0], X[:,1], y)           #用画布的形式展示所有数据的位置信息,包含三个参数(特征1、2,标签)

plt.xlabel('Feature 0')
plt.ylabel('Feature 1')                               #特征名称

Text(0, 0.5, 'Feature 1')

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AerG7y4I-1663125077906)(output_5_1.png)]

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

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.legend()                                          #标出说明标签

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vHOGUHxn-1663125077909)(output_7_2.png)]

可以看到,对于该数据集,无法使用往常的线性模型对数据集进行有效分类。

现在对输入特征进行扩展,比如说添加第二个特征的平方 f e a t u r e 1 2 feature_1^2 feature12作为一个新特征。

现将每个数据点表示为三维数据( f e a t u r e 0 , f e a t u r e 1 , f e a t u r e 1 2 feature_0,feature_1,feature_1^2 feature0,feature1feature12),而不是二维数据点( f e a t u r e 0 , f e a t u r e 1 feature_0, feature_1 feature0,feature1),这个新的表示可以化成下图:

import numpy as np                          #导入numpy数组
#导入3d图形的绘制工具
from mpl_toolkits.mplot3d import Axes3D, axes3d
import matplotlib.pyplot as  plt

X_new = np.hstack([X, X[:,1:]**2])          #hstack合并数据,在X的数据集上再追加一列,为X[:,1:]的平方,此时数据为三维数据

figure = plt.figure()                       #绘制面板对象
ax = Axes3D(figure, elev=-152, azim=-26)    #3d可视化
mask = y == 0                               #把数据集中所有 y = 0的点赋值给 mask变量,返回值是bool类型的列表

ax.scatter(X_new[mask,0], X_new[mask,1], X_new[mask,2], c='b', cmap=mglearn.cm2, s = 60)                  #绘制所有类别为0的数据点
ax.scatter(X_new[~mask,0], X_new[~mask,1], X_new[~mask,2], c='r', marker='^',cmap=mglearn.cm2, s = 60)   #绘制所有类别为1的数据点

ax.set_xlabel('feature 0')
ax.set_ylabel('feature 1')
ax.set_zlabel('feature 1 ** 2')        #绘制坐标轴标签

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oThgaRkr-1663125077911)(output_10_2.png)]

可以看到,我们已经将数据集中的二维数据成功转化为了三维数据。

在数据的新表示中,现在可以用线性模型(三维空间中的平面)将这两个类别分开。我们可以用线性模型拟合扩展后的数据来验证这一点,如下

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)                                #3d显示
#numpy.linspace()为均分函数, 用于绘制超平面需要,即把n到m的距离均分s份 
xx = np.linspace(X_new[:,0].min()-2, X_new[:,0].max()+2, 50)            #将第一个维度从最小值到最大值均分为50份   
yy = np.linspace(X_new[:,1].min()-2, X_new[:,1].max()+2, 50)            #将第二个维度从最小值到最大值均分为50份   

'''
X, Y = np.meshgrid(x, y) 代表的是将x中每一个数据和y中每一个数据组合生成很多点,
然后将这些点的x坐标放入到X中,y坐标放入Y中,并且相应位置是对应的
'''
XX, YY = np.meshgrid(xx, yy)                                            #生成了较大密度的XX, YY,分别代表数据集的第一纬度、第二维度数据
ZZ = (coef[0] * XX + coef[1] * YY + intercept)/-coef[2]                #生成数据集的第三维度z的所有数据点
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)                  #绘制所有类别为0的数据点
ax.scatter(X_new[~mask,0], X_new[~mask,1], X_new[~mask,2], c='r', marker='^',cmap=mglearn.cm2, s = 60)   #绘制所有类别为1的数据点

ax.set_xlabel('feature 0')
ax.set_ylabel('feature 1')
ax.set_zlabel('feature 1 ** 2')        #绘制坐标轴标签

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-msQJ4ZKR-1663125077912)(output_12_2.png)]

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

它不是一条直线,而是一个椭圆,如下图

ZZ = YY ** 2
# ravel() 函数将数组多维度拉成一维数组
dec = linear_svm_3d.decision_function(np.c_[XX.ravel(), YY.ravel(), ZZ.ravel()])       #决策函数

#绘制三维等高线图,不同点在于contour() 是绘制轮廓线,contourf()会填充轮廓
plt.contourf(XX, YY, dec.reshape(XX.shape), levels=[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')
Text(0, 0.5, 'Feature 1')

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cGMW0ThX-1663125077913)(output_14_1.png)]

支持向量的图像

支持向量一般为距离决策超平面较近的一些数据点,如下图

from sklearn.svm import SVC                          #导入支持向量机分类器

X, y = mglearn.tools.make_handcrafted_dataset()       #导入数据集

svm = SVC(kernel='rbf', C=10, gamma=0.1).fit(X, y)    #初始化支持向量机分类器,核函数为高斯核、C正则程度为10、gamma初始化0.1

mglearn.plots.plot_2d_separator(svm, X, eps=.5)       #绘图分界线
mglearn.discrete_scatter(X[:,0], X[:,1], y)           #绘制所有数据点

sv = svm.support_vectors_     #画出支持向量

#dual_coef_.ravel()内存放的是一个列表(lambda * y_i)
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')
Text(0, 0.5, 'Feature 1')

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aNyuKARQ-1663125077915)(output_17_1.png)]

不同参数下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(['class0', 'class1', 'sv class0', 'sv class1'], ncol=4, loc=(.9, 1.2))
<matplotlib.legend.Legend at 0x196ce93ffd0>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eNwrxoBp-1663125077917)(output_20_1.png)]

如上图,可以发现以下规律

从左到右,参数gamma的值从0.1增加到10。gamma值较小,说明高斯核的半径较大,许多点都被看做比较靠近。这一点可以在图中看出,左侧的图决策边界非常平滑,越向右的点决策边界更关注单个点。小的gamma值表示决策边界变化很慢,生成的是复杂度较低的模型,而大的gamma值则会生成更为复杂的模型。

从上到下,将参数C的值从0.1增加到1000。与线性模型相同,C值很小,说明模型非常受限,每个数据点的影响范围非常有限。而增大C之后这些点对模型的影响变大,使得决策边界发生弯曲来将这些点正确分类。

调用支持向量机分类器SVC预测乳腺癌数据集

初预测
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split

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支持向量机分类器
svc.fit(X_train, y_train)                           #训练数据集

print(svc.score(X_train, y_train))                  #输出预测的训练集与测试集评分
print(svc.score(X_test, y_test))


0.903755868544601
0.9370629370629371

预测并不是特别完美。

虽然SVM的表现通常很好,但它对参数的设定和数据的缩放非常敏感。特别地,它要求所有特征具有相似的变化范围。

现在来看下每个特征的最小值与最大值,绘制在对数坐标上

#加入axis参数,当axis=0时会分别取每一列的最大值或最小值,axis=1时,
#会分别取每一行的最大值或最小值,且将所有取到的数据放在一个一维数组中。
#X_train.min(axis=0)即找出每一列的最小值,X_train.min(axis=1)即找出每一行的最小值
plt.plot(X_train.min(axis=0), 'o', label='min')
plt.plot(X_train.min(axis=1), '^', label='max')
plt.legend(loc=4)
plt.xlabel('Feature index')
plt.xlabel('Feature magnitude')
plt.yscale('log')

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c6fwWbh5-1663125077919)(output_27_0.png)]

从这张图中可看出,特征的最小值具有完全不同的数量级,这对于其它模型来说可能是小问题,但对核SVM却有极大影响。

现在对数据集进行预处理。

数据预处理(缩放)

解决这个问题的一种办法就是对每个特征就行缩放,使其大致位于同一范围。

核SVM常用的缩放方法就是将所有特征缩放到0和1之间,现在来进行缩放

min_on_training = X_train.min(axis=0)                               #计算训练集中每个特征的最小值

range_on_training = (X_train - min_on_training).max(axis=0)           #计算训练集中每个特征的范围(最大值-最小值)

#减去最小值,然后除以范围,这样数据集的每个特征都会在0~1之间
X_train_scaled = (X_train - min_on_training)/range_on_training

#输出所有进行缩放后的数据
X_train_scaled
array([[0.23044157, 0.32157676, 0.21940433, ..., 0.31484671, 0.30277942,
        0.09858323],
       [0.20062473, 0.42116183, 0.19452699, ..., 0.06965208, 0.34042973,
        0.06677161],
       [0.62232003, 0.76929461, 0.60403566, ..., 0.56079917, 0.19850187,
        0.07431457],
       ...,
       [0.11619102, 0.35726141, 0.11077327, ..., 0.17402687, 0.17524147,
        0.17263545],
       [0.12963226, 0.35311203, 0.11706171, ..., 0.        , 0.06780997,
        0.06919848],
       [0.21434995, 0.59004149, 0.21235575, ..., 0.33251808, 0.10782574,
        0.21172767]])

可以看到,它们均位于0~1之间,再输出每个特征的最大值与最小值

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)))          #输出每个特征的最大值
Minimum 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.]
Maximum 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.]

现在同样对测试集的数据进行缩放

X_test_scaled = (X_test - min_on_training)/range_on_training                #利用训练集的最小值和范围对数据集做相同的变换
再预测
svc = SVC()                                         #定义SVC支持向量机分类器
svc.fit(X_train_scaled, y_train)                    #训练进行缩放后的数据集

print(svc.score(X_train_scaled, y_train))                  #输出预测的训练集与测试集评分
print(svc.score(X_test_scaled, y_test))
0.9835680751173709
0.972027972027972

可以看到,无论是训练集还是测试集,预测的准确度有了明显的提高。

但是训练集与测试集的预测结果较接近,可能出现了欠拟合的状态。

参数调节

现在尝试调节正则化参数C来拟合更为复杂的模型。

svc = SVC(C=30)                                   #定义SVC支持向量机分类器,增大参数C,提高模型的复杂度(但要适度,过度增加会导致过拟合)
svc.fit(X_train_scaled, y_train)                  #训练进行缩放后的数据集

print(svc.score(X_train_scaled, y_train))         #输出预测的训练集与测试集评分
print(svc.score(X_test_scaled, y_test))
0.9906103286384976
0.986013986013986

可以发现,在本次测试中,增加参数C明显地提高了预测地准确度,得到了98.6%的准确度。

优、缺点及总结

核支持向量机是非常强大的模型,在各种数据集上的表现均较好。

但对样本个数的缩放表现不好,当预测值较低时,可以尝试对数据进行缩放再进行预测,另外在调节参数C和gamma时也应谨慎小心。

  • 7
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
### 回答1: 可以使用以下代码调用sklearn中的支持向量机: ```python from sklearn import datasets from sklearn import svm # 加载数据集 iris = datasets.load_iris() # 创建支持向量机分类器 clf = svm.SVC() # 训练模型 clf.fit(iris.data, iris.target) ``` 在这个例子中,我们加载了鸢尾花数据集,并使用支持向量机分类器训练了模型。你可以根据自己的需求修改数据集和模型参数。 ### 回答2: scikit-learn(sklearn)是一个用于机器学习的Python,其中包含了许多实现了各种机器学习算法的工具。其中的支持向量机(Support Vector Machine,SVM)算法是一种常用的监督学习算法。 调用sklearn中的支持向量机方法可以用以下几个步骤完成: 1. 导入所需的和模块,在代码的开头添加以下行: ```python from sklearn import svm ``` 2. 准备好用于训练和测试的数据集。数据集应包含特征向量和相应的目标变量。例如,可以将特征向量存储在一个名为"X"的变量中,目标变量存储在一个名为"y"的变量中。 3. 创建支持向量机分类器的实例。可以使用`svm.SVC()`来创建一个基于支持向量机的分类器,或者使用`svm.SVR()`来创建一个基于支持向量机的回归器。 4. 使用训练数据拟合模型。将训练数据集的特征向量和目标变量作为参数传递给`fit()`方法。 5. 使用训练好的模型进行预测。可以使用`predict()`方法传入测试数据集的特征向量,返回模型对应的预测值。 下面是一个简单的示例代码: ```python from sklearn import svm # 准备训练数据 X = [[0, 0], [1, 1]] y = [0, 1] # 创建支持向量机分类器实例 clf = svm.SVC() # 拟合模型 clf.fit(X, y) # 准备测试数据 test_data = [[0.5, 0.5], [0.2, 0.8]] # 预测测试数据的类别 predictions = clf.predict(test_data) print(predictions) ``` 在这个例子中,我们首先导入了`svm`模块,然后准备了一个简单的训练数据集X和y。接下来,我们创建了一个支持向量机分类器实例clf,并使用`fit()`方法拟合模型。最后,我们准备了一个测试数据集test_data,并使用`predict()`方法预测其所属的类别。最后打印出了预测结果。 通过上述步骤,就可以调用sklearn中的支持向量机方法来进行分类或回归任务。具体的模型参数和方法可以根据实际需求进行调整和定制。 ### 回答3: 支持向量机(SVM)是机器学习中一种常用的分类算法,可以使用sklearn进行调用和应用。 首先,我们需要导入sklearn中的SVM模块: ```python from sklearn import svm ``` 接下来,我们可以通过创建一个SVM分类器对象来对数据进行训练和预测: ```python clf = svm.SVC() # 创建SVM分类器对象 clf.fit(X_train, y_train) # 使用训练数据进行训练 y_pred = clf.predict(X_test) # 使用训练好的模型进行预测 ``` 在上述代码中,X_train是训练数据集的特征向量,y_train是对应的训练标签,X_test是测试数据集的特征向量,y_pred是预测结果。在.fit()方法中,模型使用训练数据进行训练,而.predict()方法则使用训练好的模型对测试数据进行预测。 除了默认的线性核函数,我们还可以使用其他的核函数,例如径向基函数(RBF): ```python clf = svm.SVC(kernel='rbf') # 使用径向基函数作为核函数 ``` 在实际应用中,还可以根据需要设定其他参数,例如正则化参数C、惩罚因子gamma等,以优化模型的性能和准确度: ```python clf = svm.SVC(C=0.8, gamma=0.1) # 设定正则化参数C为0.8,设定惩罚因子gamma为0.1 ``` 调用sklearn中的支持向量机模型,可以方便地实现对数据的分类和预测,提高模型的准确性和泛化能力。注意,在使用SVM算法时,数据的预处理和特征工程同样重要,对数据进行合适的处理可以提高模型的性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Gaolw1102

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值