当前位置: 当前位置:首页 > 知识 > 支持向量机(SVM)----sklearn库的应用 正文

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

2024-04-29 20:28:06 来源:口口声声网 作者:知识 点击:605次

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

文章目录

      • 支持向量机(SVM)----sklearn库的支持应用
      • 维度升级及切分图像
      • 支持向量的图像
      • 不同参数下SVM模型划分的图像结果
      • 调用支持向量机分类器SVC预测乳腺癌数据集
        • 初预测
        • 数据预处理(缩放)
        • 再预测
        • 参数调节
      • 优、缺点及总结

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

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

维度升级及切分图像

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

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

先看一下如下的向量数据集

from sklearn.datasets import make_blobs            #导入斑点(blobs)数据集import matplotlib.pyplot as pltimport mglearnX, 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​,feature1​,feature12​),而不是二维数据点( 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, axes3dimport matplotlib.pyplot as  pltX_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.1mglearn.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))

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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_cancerfrom sklearn.model_selection import train_test_splitcancer = 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.9037558685446010.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.98356807511737090.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.99061032863849760.986013986013986

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

优、缺点及总结

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

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

作者:时尚
------分隔线----------------------------
头条新闻
图片新闻
新闻排行榜