【初中生讲机器学习】4. 支持向量机算法怎么用?一个实例带你看懂!

创建时间:2024-02-02
最后编辑时间:2024-02-03
作者:Geeker_LStar

你好呀~这里是 Geeker_LStar 的人工智能学习专栏,很高兴遇见你~
我是 Geeker_LStar,一名初三学生,热爱计算机和数学,我们一起加油~!
⭐(●’◡’●) ⭐
那就让我们开始吧!

上一篇【初中生讲机器学习】3. 支持向量机(SVM)一万字详解!超全超详细超易懂!当中,我们已经详细了解了支持向量机算法以及它背后的数学原理,但是上一篇文章中没有给出实例代码,so 这一篇主要就通过一个实例来看看支持向量机算法应该怎么实现,有哪些要点~

完整代码见文末~

实例:利用支持向量机对鸢尾花进行分类。
(神奇,我这学期的作文里貌似三次写到鸢尾花诶)

话不多说,首先,我们导入各种需要的库(or 需要的函数方法 or 数据集)。

'''第一步,导入各种需要的库'''
import matplotlib.pyplot as plt    # 用于数据可视化
import matplotlib as mpl
from sklearn import svm    # 引入封装好的 SVM 算法
from sklearn.datasets import load_iris    # 引入鸢尾花数据集,共 150 组数据
from sklearn.model_selection import train_test_split    # 划分训练集和测试集的函数方法
from sklearn.metrics import accuracy_score    # 评判测试准确度的函数方法
import numpy as np    # 进行科学计算

matplotlib,进行数据可视化的库。
numpy 用于进行科学计算。
scikit learn,即 sklearn 库,是机器学习中非常重要的一个库,它封装了大量常用算法,如分类、回归、降维、聚类等,并且提供一些常用数据集,其中就包括本例中用到的鸢尾花数据集。

接着,我们需要对鸢尾花数据集有一个了解,先加载它,然后输出一些它的特征。

iris = load_iris()    # 加载数据集
print(iris.target)    # 数据标签(分类结果标签)
print(iris.target_names)    # 三种鸢尾花的名字
print(iris.feature_names)    # 四个分类特征的名字

这是输出结果,可以看到,数据集中的鸢尾花一共有三类 150 个,每一类有 50 个。分类标准是【萼片长度】【萼片宽度】【花瓣长度】【花瓣宽度】。

[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 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 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 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2
 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
 2 2]
['setosa' 'versicolor' 'virginica']
['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']

再来看一下每一个鸢尾花数据是怎么表示的(没错其实就是四维向量,因为四个特征嘛),以及它们对应的数据标签。

X = iris.data    # 输入数据(150 个四维向量),样本特征,[n_samples * n_features] 的二维数组
print(X.shape, X)    # X.shape,输出 X 数组的行数和列数
y = iris.target    # 数据标签 or 分类结果(共三种每种 50 个数据)
print(y.shape, y)

输出如下(一部分),大意是:输入数据一共 150 个,每个都是一个四维向量,对应的数据标签是 0 或 1 或 2。

(150, 4) [[5.1 3.5 1.4 0.2]
 [4.9 3.  1.4 0.2]
 [4.7 3.2 1.3 0.2]
 [4.6 3.1 1.5 0.2]

(150,) [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 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 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 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2
 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
 2 2]

哦?这样不够直观?看不出这 150 组数据在分布上有什么特点?没事,咱有 matplotlib,画个图嘛!
errr,我们分别以前两个特征(萼片长宽)和后两个特征(花瓣长宽)为特征画图。画完图其实可以看出一些东西,不过这里先不透露。

# 以前两个特征(花萼长度、花萼宽度)绘图
X = iris.data[:, :2]    # 切片操作,选取前两个特征
plt.scatter(X[y == 0, 0], X[y == 0, 1], color = "red", marker = "o")
plt.scatter(X[y == 1, 0], X[y == 1, 1], color = "green", marker = "+")
plt.scatter(X[y == 2, 0], X[y == 2, 1], color = "blue", marker = "x")
plt.xlabel('sepal length', fontsize=20)
plt.ylabel('sepal width', fontsize=20)
plt.title('Iris names', fontsize=30)
plt.show()

这是这些鸢尾花的萼片长宽的分布图,不难发现,通过萼片长宽可以比较好的将第一种鸢尾花(红色)和第二三种(绿/蓝色)区分开,但是第二种和第三种之间却不太好区分。

萼片长宽分布

再来看看花瓣长宽的情况。

# 以后两个特征(花瓣长度、花瓣宽度)绘图(发现后两个特征能够更好地区分三类鸢尾花)
X = iris.data[:, 2:]
plt.scatter(X[y == 0, 0], X[y == 0, 1], color = "red", marker = "o")
plt.scatter(X[y == 1, 0], X[y == 1, 1], color = "green", marker = "+")
plt.scatter(X[y == 2, 0], X[y == 2, 1], color = "blue", marker = "x")
plt.xlabel('petal length', fontsize=20)
plt.ylabel('petal width', fontsize=20)
plt.title('Iris names', fontsize=30)
plt.show()

分布图长这样,不难看出,可以通过花瓣长宽特征将三种鸢尾花大致分开,【只按照花瓣特征分】比【只按照萼片特征分】的效果更好(为什么提到这个,因为后面要写相关代码~)。

花瓣长宽分布

ok,现在我们对整个数据集已经有了大致的了解,可以利用支持向量机来分类啦!

通常来讲,用 SVM 分类可以按照这个顺序进行,其中 2、3 可以反过来:

  1. 获取所需数据集(全部特征 or 某个或某几个特征(切片))
  2. 定义支持向量机(svm.SVC())
  3. 划分训练集和测试集(train_test_split())
  4. 利用训练集进行训练(fit())
  5. 测试,预测测试集的输出结果(predict())
  6. 计算测试准确率并输出,模型评价(accuracy_score())
  7. 绘制结果(如果需要)

那我们就按照这个步骤来吧!先来最简单的,用全部特征进行分类,先训练再测试。

第一步,获取所需数据集,这两行代码的意思上面已经解释过:

X = iris.data
y = iris.target

第二步,定义支持向量机,解释一下其中的一些参数,这些参数的详细讲解都在上一篇:

  • kernel:核函数类型,“linear” 表示线性核函数,“poly” 表示多项式核函数,“rbf” 表示高斯核函数(径向基函数)。
  • C:惩罚项,默认值为 1。C 的值很关键,过小会导致模型的泛化能力弱(过拟合),过大又会导致欠拟合。
  • gamma:核函数的核系数,一般情况下默认为 1/n_features。
  • probability:是否支持输出样本属于不同类的概率,True 表示支持。
svm1 = svm.SVC(kernel="rbf", C=1, gamma="auto", probability=True)

第三步,划分训练集和测试集
train_test_split() 用于划分训练集和测试集,其中,test_size 指测试集数据量占数据总量的百分比,0.3 即有 30% 的数据用于测试,其余数据用于训练;random_state 是随机数种子,改变它可以获得不同的数据划分,通常在交叉验证中使用。

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=218)

第四步,利用训练集进行训练
fit() 方法,用于训练支持向量机,也就是拟合

svm2.fit(X_train, y_train)

第五步,测试,预测测试集的输出结果
训练完 SVM,就让它去预测一下测试集的数据吧。
predict() 函数用于预测。

y_predict = svm2.predict(X_test)

第六步,计算测试准确率并输出,也就是模型评价:
accuracy_score() 函数计算模型预测的准确率,是评价模型性能的一项参考指标,与之类似的参考指标还有召回率、ROC 曲线、AUC 值等,这些在第二篇中讲过~(sklearn 库也提供其他参考指标的函数方法,但是本例中用不到)。

print("准确率:", accuracy_score(y_test, y_predict))

ok!此时一个 SVM 的训练+测试就完成了!我这里的准确率是 95.6%。

如果对准确率不满意,可以尝试调整惩罚系数 C,也可以尝试换一种核函数,或者提高训练集的占比使模型得到更充分的训练,等等。

ok,走了一遍基础流程,其实 SVM 的训练并不难的()下面我们来看看如果我们想按照某些特征进行分类(比如之前提到的按照萼片长宽分类),并且想更直观地看到这个超平面是怎么划分的,我们应该怎么做。

其实大体上没什么变化,只不过在获取数据的时候需要做一个切片处理,语法和 Python 当中的列表切片是一样的。

X2 = iris.data[:, :2]    # :2 表示取前两个特征,即萼片长和萼片宽

别的代码和上面完全一样,为了和上面进行区分,把 svm 和 X 的角标改了一下:

X2 = iris.data[:, :2]    # :2 表示取前两个特征,即萼片长和萼片宽
svm3 = svm.SVC(kernel="rbf", C=3, gamma="auto")
X2_train, X2_test, y2_train, y2_test = train_test_split(X2, y, test_size=0.3, random_state=218)
svm3.fit(X2_train, y2_train)
y2_predict = svm3.predict(X2_test)
print("准确率:", accuracy_score(y2_test, y2_predict))
draw1(svm3, X2)    # 绘图

你可能发现了,这段代码里定义了一个用于绘图的 draw 函数,这个函数蛮关键的,我们拆解着来写。

first,明确需求,我们希望通过前两个特征(萼片长宽)进行分类,并将结果可视化,也就是要画出决策超平面,直观地看出萼片长宽在哪一部分的花会被分到哪一类

先把最终结果放在这,这样后面拆解每一步就会变得好理解~

下图中,背景色块相交的地方就是决策超平面(其实就是一条线),不同的色块代表花萼长宽在不同范围的鸢尾花会被分到不同的类(一个色块就是一类)。

花萼分类结果

其实这块主要是数据处理 and 可视化,并且这种可视化套路其实是通用的,后面的文章中会讲 KNN(K 最近邻)算法,它的实例也可以用这一套可视化流程。

首先,花萼长宽的分布都在一定范围内,我们可以用它们的最小值和最大值作为 xy 轴的起止点,如下。

# 获取坐标值的范围
x1_min, x1_max = X[:, 0].min(), X[:, 0].max()
x2_min, x2_max = X[:, 1].min(), X[:, 1].max()
# 坐标轴范围
plt.xlim(x1_min, x1_max)
plt.ylim(x2_min, x2_max)

接着,问题来了,怎么找到决策线?上图中那些表示分类的背景色块是怎么画出来的?

这个思路很好:色块其实就是一个个点密集分布组成的,我们可以在坐标系中取很多很多点(为了保证精确度,这些点之间的间隔应该相等且足够小),用已经训练好的模型预测这些点会被分到哪一类。对于分到不同类的点,用不同的颜色在坐标系中画出它们。这样这些密集的点就会形成一个“色块”,不同颜色的色块也就代表了不同的类。
(对之所以高亮这一部分就是我觉得这个思路真的太棒了!)

来写写。

first,我们要取一堆间隔足够小的点,比如在横纵坐标最小值和最大值之间都均等取 200 个值,这样一共就选取了 200*200 = 40000 个点,这么多点足以让坐标系看起来被填满了。

# 生成坐标系中的网格点(2D)
# 200j,复数,即在这个范围中取 200 个点
x1, x2 = np.mgrid[x1_min:x1_max:200j, x2_min:x2_max:200j]

second,目前的 x1、x2 都还只是单独的横坐标和单独的纵坐标,用 stack() 函数把它们重新组合一下,新的数组是 40000 个点的坐标。

# 构造测试点(坐标点)并输出其坐标
# stack() 方法,将两个二维数组合并成一个新的二维数组
grid_test = np.stack((x1.flat, x2.flat), axis=1)
print('坐标点的坐标数据:\n', grid_test)

输出是这样的,可以看到和图中的坐标范围是一致的。

坐标点的坐标数据:
 [[1.        0.1      ]
 [1.        0.1120603]
 [1.        0.1241206]
 ...
 [6.9       2.4758794]
 [6.9       2.4879397]
 [6.9       2.5      ]]

上一篇中提到了函数间隔,它反映点到决策超平面的距离,函数间隔大于等于 1 说明分类正确,越大说明越可能是这一类。

这里获得输出构造的坐标点的函数间隔(可以看出它们应该分到哪一类),用 decision_function() 函数,然后输出坐标点预测结果。

and then 输出一下原始数据集中的数据被分到每一类的概率,用 predict_proba() 函数。

其实这些可以不用输出,但是为了更详细地知道每个函数都干了什么,我把输出结果放在代码后面了。

# decision_function 多分类情况
# 输出样本到决策超平面的距离(函数间隔),反映属于每个分类的可能性
# 第 n 个数是属于第 n 类的可能性
# 数越大,说明越有可能属于这个分类
z = svm.decision_function(grid_test)
print('坐标点到超平面的距离(函数间隔):\n', z)
# 预测并输出分类结果,得到 [0, 0, ..., 2, 2]
grid_hat = svm.predict(grid_test)
print('坐标点预测结果:\n', grid_hat)
# 预测并输出测试集中的数据属于每个类别的概率
probably = svm.predict_proba(X)
print('测试数据的预测概率:\n', probably)

输出结果:

坐标点到超平面的距离(函数间隔):
 [[ 2.21808359 -0.18477028  0.86886414]
 [ 2.21824232 -0.18491925  0.86865134]
 [ 2.21838742 -0.18505706  0.86845955]
 ...
 [-0.18169166  0.85623648  2.22058861]
 [-0.18145152  0.85663691  2.22031407]
 [-0.18120477  0.85704722  2.22003204]]
 坐标点预测结果:
 [0 0 0 ... 2 2 2]
测试数据的预测概率:
 [[0.95790549 0.0183466  0.02374791]
 [0.95790549 0.0183466  0.02374791]
 [0.95498744 0.01979717 0.02521539]
 [0.95897025 0.01779033 0.02323941](这里省略了后面的)

重要的逻辑都说完了,剩下就是画图的事情了,画图部分的代码的功能注释里都写了~

# 使得 grid_hat 和 x1 的数组形式一致
grid_hat = grid_hat.reshape(x1.shape)
cm_light = mpl.colors.ListedColormap(['#A0FFA0', '#FFA0A0', '#A0A0FF'])
cm_dark = mpl.colors.ListedColormap(['g', 'b', 'r'])
# pcolormesh 绘制背景颜色块(前面取坐标点并获得它们的分类结果就是为了这个)
# 用于区分坐标系中的哪一部分会被分到哪一类
# cmap 自定义颜色(用亮色绘制背景,用暗色绘制测试集中的数据点)
# 绘制测试集中的点
plt.pcolormesh(x1, x2, grid_hat, cmap=cm_light)
plt.scatter(X[:, 0], X[:, 1], c=np.squeeze(y), edgecolor='k', s=50, cmap=cm_dark)
plt.scatter(X_test[:, 0], X_test[:, 1], s=120, facecolor='none', zorder=10)
# 坐标轴标签
plt.xlabel(iris_feature[0], fontsize=20)
plt.ylabel(iris_feature[1], fontsize=20)
# 坐标轴范围
plt.xlim(x1_min, x1_max)
plt.ylim(x2_min, x2_max)
# 坐标轴标题
plt.title('Iris classification based on SVM', fontsize=30)
# 绘图
plt.grid()
plt.show()

ok!画图函数已经完成,完整代码:

# 定义绘图函数(以前两个特征作为分类依据)
def draw1(svm, X):
    iris_feature = 'sepal length', 'sepal width', 'petal length', 'petal width'    # 四个特征
    # 获取坐标值的范围
    x1_min, x1_max = X[:, 0].min(), X[:, 0].max()
    x2_min, x2_max = X[:, 1].min(), X[:, 1].max()
    # 生成坐标系中的网格点(2D)
    # 200j,复数,即在这个范围中取 200 个点
    x1, x2 = np.mgrid[x1_min:x1_max:200j, x2_min:x2_max:200j]
    # 构造测试点(坐标点)
    # stack() 方法,将两个二维数组合并成一个新的二维数组,并且数组 1 中的第 i 项和数组 2 中的第 i 项合并为新数组的第 i 项
    # 输出构造的点的坐标
    grid_test = np.stack((x1.flat, x2.flat), axis=1)
    print('坐标点的坐标数据:\n', grid_test)
    # decision_function 多分类情况
    # 输出样本到决策超平面的距离(函数间隔),反映属于每个分类的可能性
    # 第 n 个数是属于第 n 类的可能性
    # 数越大,说明越有可能属于这个分类
    z = svm.decision_function(grid_test)
    print('坐标点到超平面的距离(函数间隔):\n', z)
    # 预测并输出分类结果,得到 [0, 0, ..., 2, 2]
    grid_hat = svm.predict(grid_test)
    print('坐标点预测结果:\n', grid_hat)
    # 预测并输出测试集中的数据属于每个类别的概率
    probably = svm.predict_proba(X)
    print('测试数据的预测概率:\n', probably)
    # 使得 grid_hat 和 x1 的数组形式一致
    grid_hat = grid_hat.reshape(x1.shape)
    cm_light = mpl.colors.ListedColormap(['#A0FFA0', '#FFA0A0', '#A0A0FF'])
    cm_dark = mpl.colors.ListedColormap(['g', 'b', 'r'])
    # pcolormesh 绘制背景颜色块(前面取坐标点并获得它们的分类结果就是为了这个)
    # 用于区分坐标系中的哪一部分会被分到哪一类
    # cmap 自定义颜色(用亮色绘制背景,用暗色绘制测试集中的数据点)
    # 绘制测试集中的点
    plt.pcolormesh(x1, x2, grid_hat, cmap=cm_light)
    plt.scatter(X[:, 0], X[:, 1], c=np.squeeze(y), edgecolor='k', s=50, cmap=cm_dark)
    plt.scatter(X_test[:, 0], X_test[:, 1], s=120, facecolor='none', zorder=10)
    # 坐标轴标签
    plt.xlabel(iris_feature[0], fontsize=20)
    plt.ylabel(iris_feature[1], fontsize=20)
    # 坐标轴范围
    plt.xlim(x1_min, x1_max)
    plt.ylim(x2_min, x2_max)
    # 坐标轴标题
    plt.title('Iris classification based on SVM', fontsize=30)
    # 绘图
    plt.grid()
    plt.show()

最后得到的准确率是 73% 左右,和我们从图中直观看出来的是差不多的,即只按照花萼长宽进行分类的结果并不很好

按照花瓣长宽分类和按照花萼长宽分类完全是一个道理,最后画出的图长这样,准确率在 97% 左右,说明对于鸢尾花,花瓣的特征更加鲜明,作为分类依据会更好。

按花瓣长宽分类的结果

还有一个有趣的结果——按照四个特征分类的准确率居然比只按照花瓣长宽两个特征分类的准确率低(至少在本文的 “实验条件” 下是这样的),可能是因为花萼长宽中的部分数据特征不够鲜明或者有噪声数据(比如某朵花变异了之类的)。

这也说明在训练模型的时候,特征的选取有时并不是越多越好,选取特征的时候需要考虑特征是否鲜明、区分度高。如果特征选取不当,可能会对模型的性能造成负面影响。

ok!以上就是本文的全部内容啦!完整代码:

# 利用支持向量机(SVM)对鸢尾花进行分类,一共分成三类
# Scikit learn 是机器学习中常见的第三方模块,封装了常用算法,包括回归、降维、分类、聚类等
# 鸢尾花数据集:共 150 组数据,每组数据 4 个特征(四维向量)
# matplotlib 用于数据可视化
# numpy 用于科学计算

'''第一步,导入各种需要的库'''
import matplotlib.pyplot as plt    # 用于数据可视化
import matplotlib as mpl
from sklearn import svm    # 引入封装好的 SVM 算法
from sklearn.datasets import load_iris    # 引入鸢尾花数据集,共 150 组数据
from sklearn.model_selection import train_test_split    # 分割训练集和测试集的函数方法
from sklearn.metrics import accuracy_score    # 评判测试准确度的函数方法
import numpy as np    # 进行科学计算

'''第二步,输出数据集的各种信息并绘制散点图(直观分类)'''
iris = load_iris()    # 加载数据集
print(iris.target)    # 数据标签(分类结果标签)
print(iris.target_names)    # 三种鸢尾花的名字
print(iris.feature_names)    # 四个分类特征的名字
X = iris.data    # 输入数据(150 个四维向量),样本特征,[n_samples * n_features] 的二维数组
print(X.shape, X)    # X.shape,输出 X 数组的行数和列数
y = iris.target    # 数据标签 or 分类结果(共三种每种 50 个数据)
print(y.shape, y)
# 以前两个特征(花萼长度、花萼宽度)绘图
X = iris.data[:, :2]    # 切片操作,选取前两个特征
plt.scatter(X[y == 0, 0], X[y == 0, 1], color = "red", marker = "o")
plt.scatter(X[y == 1, 0], X[y == 1, 1], color = "green", marker = "+")
plt.scatter(X[y == 2, 0], X[y == 2, 1], color = "blue", marker = "x")
plt.xlabel('sepal length', fontsize=20)
plt.ylabel('sepal width', fontsize=20)
plt.title('Iris names', fontsize=30)
plt.show()
# 以后两个特征(花瓣长度、花瓣宽度)绘图(发现后两个特征能够更好地区分三类鸢尾花)
X = iris.data[:, 2:]
plt.scatter(X[y == 0, 0], X[y == 0, 1], color = "red", marker = "o")
plt.scatter(X[y == 1, 0], X[y == 1, 1], color = "green", marker = "+")
plt.scatter(X[y == 2, 0], X[y == 2, 1], color = "blue", marker = "x")
plt.xlabel('petal length', fontsize=20)
plt.ylabel('petal width', fontsize=20)
plt.title('Iris names', fontsize=30)
plt.show()

'''第三步,尝试用不同的方式进行训练'''
# 步骤:
# 1. 获取所需数据集(全部特征 or 某个或某几个特征(切片))
# 2. 定义支持向量机(svm.SVC())
# 3. 划分训练集和测试集(train_test_split())
# 4. 利用训练集进行训练(fit())
# 5. 测试,预测测试集的输出结果(predict())
# 6. 计算测试准确率并输出(accuracy_score())

# svm.SVC() 函数是实现 SVM 算法的封装方法之一
# kernel:核函数类型,linear 代表线性,poly 代表多项式,rbf 代表径向基
# C:惩罚系数
# gamma:核函数中的核系数,默认为 1/n_features(特征数的倒数)

'''第一类:不分训练集和测试集,用全部特征进行分类'''
X = iris.data
svm1 = svm.SVC(kernel="rbf", C=1, gamma="auto", probability=True)
svm1.fit(X, y)    # 用全部特征进行训练
print("训练得分:", svm1.score(X, y))
print("预测:", svm1.predict([[7, 5, 2, 0.5], [7.5, 4, 7, 2]]))
print('\n')

'''第二类:分训练集和测试集,训练集训练完后用测试集测试,用全部特征进行分类'''
# test_size 表示训练数据在数据集中的占比,0.2 表示 20%
# random_state 表示随机数种子,改变该值可获得不同的分割方法
svm2 = svm.SVC(kernel="rbf", C=3, gamma="auto", probability=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=218)
svm2.fit(X_train, y_train)    # 用训练集进行训练
y_predict = svm2.predict(X_test)    # 用测试集进行测试
print("准确率:", accuracy_score(y_test, y_predict))    # 计算准确率(正确的所占百分比)
print('\n')

'''第三类:分训练集和测试集,用不同特征进行分类'''
# 定义绘图函数(以前两个特征作为分类依据)
def draw1(svm, X):
    iris_feature = 'sepal length', 'sepal width', 'petal length', 'petal width'    # 四个特征
    # 获取坐标值的范围
    x1_min, x1_max = X[:, 0].min(), X[:, 0].max()
    x2_min, x2_max = X[:, 1].min(), X[:, 1].max()
    # 生成坐标系中的网格点(2D)
    # 200j,复数,即在这个范围中取 200 个点
    x1, x2 = np.mgrid[x1_min:x1_max:200j, x2_min:x2_max:200j]
    # 构造测试点(坐标点)
    # stack() 方法,将两个二维数组合并成一个新的二维数组,并且数组 1 中的第 i 项和数组 2 中的第 i 项合并为新数组的第 i 项
    # 输出构造的点的坐标
    grid_test = np.stack((x1.flat, x2.flat), axis=1)
    print('坐标点的坐标数据:\n', grid_test)
    # decision_function 多分类情况
    # 输出样本到决策超平面的距离(函数间隔),反映属于每个分类的可能性
    # 第 n 个数是属于第 n 类的可能性
    # 数越大,说明越有可能属于这个分类
    z = svm.decision_function(grid_test)
    print('坐标点到超平面的距离(函数间隔):\n', z)
    # 预测并输出分类结果,得到 [0, 0, ..., 2, 2]
    grid_hat = svm.predict(grid_test)
    print('坐标点预测结果:\n', grid_hat)
    # 预测并输出测试集中的数据属于每个类别的概率
    probably = svm.predict_proba(X)
    print('测试数据的预测概率:\n', probably)
    # 使得 grid_hat 和 x1 的数组形式一致
    grid_hat = grid_hat.reshape(x1.shape)
    cm_light = mpl.colors.ListedColormap(['#A0FFA0', '#FFA0A0', '#A0A0FF'])
    cm_dark = mpl.colors.ListedColormap(['g', 'b', 'r'])
    # pcolormesh 绘制背景颜色块(前面取坐标点并获得它们的分类结果就是为了这个)
    # 用于区分坐标系中的哪一部分会被分到哪一类
    # cmap 自定义颜色(用亮色绘制背景,用暗色绘制测试集中的数据点)
    # 绘制测试集中的点
    plt.pcolormesh(x1, x2, grid_hat, cmap=cm_light)
    plt.scatter(X[:, 0], X[:, 1], c=np.squeeze(y), edgecolor='k', s=50, cmap=cm_dark)
    plt.scatter(X_test[:, 0], X_test[:, 1], s=120, facecolor='none', zorder=10)
    # 坐标轴标签
    plt.xlabel(iris_feature[0], fontsize=20)
    plt.ylabel(iris_feature[1], fontsize=20)
    # 坐标轴范围
    plt.xlim(x1_min, x1_max)
    plt.ylim(x2_min, x2_max)
    # 坐标轴标题
    plt.title('Iris classification based on SVM', fontsize=30)
    # 绘图
    plt.grid()
    plt.show()

# 用前两个特征进行分类
X2 = iris.data[:, :2]    # :2 表示取前两个特征,即萼片长和萼片宽
svm3 = svm.SVC(kernel="rbf", C=3, gamma="auto", probability=True)
X2_train, X2_test, y2_train, y2_test = train_test_split(X2, y, test_size=0.3, random_state=218)
svm3.fit(X2_train, y2_train)
y2_predict = svm3.predict(X2_test)
print("准确率:", accuracy_score(y2_test, y2_predict))
draw1(svm3, X2)    # 绘图

print('\n')
# 定义绘图函数(以后两个特征作为分类依据)
def draw2(svm, X):
    iris_feature = 'sepal length', 'sepal width', 'petal length', 'petal width'    # 四个特征
    # 获取坐标值的范围
    x1_min, x1_max = X[:, 0].min(), X[:, 0].max()
    x2_min, x2_max = X[:, 1].min(), X[:, 1].max()
    # 生成坐标系中的网格点(2D)
    # 200j,复数,即在这个范围中取 200 个点
    x1, x2 = np.mgrid[x1_min:x1_max:200j, x2_min:x2_max:200j]
    # 构造测试点(坐标点)
    # stack() 方法,将两个二维数组合并成一个新的二维数组,并且数组 1 中的第 i 项和数组 2 中的第 i 项合并为新数组的第 i 项
    # 输出构造的点的坐标
    grid_test = np.stack((x1.flat, x2.flat), axis=1)
    print('坐标点的坐标数据:\n', grid_test)
    z = svm.decision_function(grid_test)
    print('坐标点到超平面的距离(函数间隔):\n', z)
    # 预测并输出分类结果,得到 [0, 0, ..., 2, 2]
    grid_hat = svm.predict(grid_test)
    print('坐标点预测结果:\n', grid_hat)
    # 预测并输出测试集中的数据属于每个类别的概率
    probably = svm.predict_proba(X)
    print('测试数据的预测概率:\n', probably)
    # 使得 grid_hat 和 x1 的数组形式一致
    grid_hat = grid_hat.reshape(x1.shape)
    cm_light = mpl.colors.ListedColormap(['#A0FFA0', '#FFA0A0', '#A0A0FF'])
    cm_dark = mpl.colors.ListedColormap(['g', 'b', 'r'])
    # pcolormesh 绘制背景颜色块(前面取坐标点并获得它们的分类结果就是为了这个)
    # 用于区分坐标系中的哪一部分会被分到哪一类
    # cmap 自定义颜色(用亮色绘制背景,用暗色绘制测试集中的数据点)
    # 绘制测试集中的点
    plt.pcolormesh(x1, x2, grid_hat, cmap=cm_light)
    plt.scatter(X[:, 0], X[:, 1], c=np.squeeze(y), edgecolor='k', s=50, cmap=cm_dark)
    plt.scatter(X_test[:, 0], X_test[:, 1], s=120, facecolor='none', zorder=10)
    # 坐标轴标签
    plt.xlabel(iris_feature[2], fontsize=20)
    plt.ylabel(iris_feature[3], fontsize=20)
    # 坐标轴范围
    plt.xlim(x1_min, x1_max)
    plt.ylim(x2_min, x2_max)
    # 坐标轴标题
    plt.title('Iris classification based on SVM', fontsize=30)
    # 绘图
    plt.grid()
    plt.show()

# 用后两个特征进行分类
X3 = iris.data[:, 2:]    # 分割出后两个特征
svm4 = svm.SVC(kernel="rbf", C=3, gamma="auto", probability=True)
X3_train, X3_test, y3_train, y3_test = train_test_split(X3, y, test_size=0.3, random_state=218)
svm4.fit(X3_train, y3_train)    # 进行拟合(训练)
y3_predict = svm4.predict(X3_test)    # 预测(测试)
print("准确率:", accuracy_score(y3_test, y3_predict))    # 输出测试准确率
draw2(svm4, X3)

ok!!!!!以上就是支持向量机算法的实例!!

嘿嘿真的非常开心你能够看到这里!!一起加油!

如果有任何 bug 欢迎评论区拷打我!!

本文中所有的代码我都做了认真的分析(and 注释),希望对你有所帮助!我们下篇再见!⭐
——Geeker_LStar

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/368462.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

华为机考入门python3--(5)牛客5-进制转换

分类:数字 知识点: 十六进制转int num int(hex_num, 16) int转十六进制 hex_num hex(num) 题目来自【牛客】 hex_num input().strip() dec_num int(hex_num, 16) print(dec_num) by 软件工程小施同学

python爬虫5

1.selenium交互 无页面浏览器速度更快 #配置好的自己不用管 from selenium import webdriverfrom selenium.webdriver.chrome.options import Optionschrome_options Options()chrome_options.add_argument(‐‐headless)chrome_options.add_argument(‐‐disable‐gpu)# path…

2024美国大学生数学建模E题财产保险的可持续模型详解思路+具体代码季节性时序预测SARIMA天气预测建模

上一篇已经对赛题进行详细分析了,而且大方向和基本的模型已经确定完毕,数据集都已经找到了,现在最重要的就是要分析风暴数据集以及建立时序预测模型,使用气候模型预测的数据,评估气候变化对未来极端天气事件频率和强度…

世界顶级汽车品牌源代码遭泄露 详解源代码凭据安全解决方案

源代码凭据安全,您别忽视 !!! 一、事件回顾 2024年1月29日,RedHunt 实验室的研究员Lohit爆料:某世界顶级的豪华汽车品牌源代码面临泄露风险!人为错误致GitHub令牌事故引发重大安全担忧。 RedHunt Labs在一次互联网扫描时&#x…

顺序表:数据结构的建筑积木

朋友们大家好啊,本节内容我们进入数据结构的第二节,顺序表有关内容,同步我们会学习计组原理与cpp相关知识,求三连啊! 本节我们重点探讨动态顺序表关于插入数据和删除数据的多种情况的分析 顺序表 线性表顺序表静态顺序…

2024年2月4日 十二生肖 今日运势

小运播报:2024年2月4日,星期日,农历腊月廿五 (癸卯年乙丑月戊戌日),法定工作日。 红榜生肖:兔、马、虎 需要注意:牛、鸡、龙 喜神方位:东南方 财神方位:正…

linux中的makefile

(码字不易,关注一下吧w~~w) makefile文件是用来管理项目文件,通过执行make命令,make就会解析并执行makefile文件。 命名:makefile或者Makefile 规则: 目标文件:依赖文件 (tab)命…

Jetpack Compose系列(3)-使用列表

使用列表 在 View 体系中,创建自定义布局必须扩展 ViewGroup 并实现测量和布局函数。在 Compose 中,只需使用 Layout 可组合项编写一个(布局)函数即可。上一篇文章我们详细介绍了Column()和Row()这两各横向布局,这里我们继续介绍其他布局。 …

LeetCode:42. 接雨水

42. 接雨水 1)题目2)思路3)代码4)结果 1)题目 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 示例 1: 输入:height …

Jmeter学习系列之四:测试计划元素介绍

测试计划元素 JMeter包含各种相互关联但为不同目的而设计的元素。在开始使用JMeter之前,最好先了解一下JMeter的一些主要元素。 注意:测试计划包含至少一个线程组。 以下是JMeter的一些主要组件: 测试计划(Plan)线程组(Thread Group)控制器…

每日OJ题_算法_模拟③_力扣6. Z 字形变换

目录 力扣6. Z 字形变换 解析代码 力扣6. Z 字形变换 6. Z 字形变换 难度 中等 将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。 比如输入字符串为 "PAYPALISHIRING" 行数为 3 时,排列如下&#xff…

C# 读取文件中的配置信息

文章目录 定义使用文件格式代码 C#读取文件并处理&#xff1b;C# 读取文件中的配置信息。 在有的程序中&#xff0c;需要从本地文件中读取配置信息&#xff0c;以进行初始化。 定义 定义一个静态函数来获取文件信息。StreamReader 类。 /// <summary> /// 读取参数文件…

【Linux Day14 UDP网络通讯】

UDP网络通讯 UDP报文结构&#xff1a; 16位源端口&#xff1a;用于记录发送端的端口号&#xff08;占用两个字节&#xff09;16位目的端口&#xff1a;用于记录接收端的端口号&#xff08;占用两个字节&#xff09;16位UDP长度&#xff1a;确定UDP报文总长度&#xff0c;&…

React18构建Vite+Electron项目以及打包

一.先创建项目 cnpm create vite 选择React > JavaScript >cd react_vite > cnpm i >npm run dev 二.安装Electron依赖 指定版本相对稳定 cnpm i electron19.0.10 -D cnpm i vite-plugin-electron0.9.3 -D cnpm i electron-builder23.0.1 -D三.创建electron目录…

算法:阿里巴巴找黄金宝箱(II)

一、算法描述 题目描述 一贫如洗的樵夫阿里巴巴在去砍柴的路上&#xff0c;无意中发现了强盗集团的藏宝地&#xff0c;藏宝地有编号从0-N的箱子&#xff0c; 每个箱子上面贴有箱子中藏有金币Q的数量。 从金币数量中选出一个数字集合&#xff0c; 并销毁贴有这些数字的每个箱子&…

242. Valid Anagram(有效的字母异位词)

问题描述 给定两个字符串 s 和 t &#xff0c;编写一个函数来判断 t 是否是 s 的字母异位词。 注意&#xff1a;若 s 和 t 中每个字符出现的次数都相同&#xff0c;则称 s 和 t 互为字母异位词。 问题分析 此问题与383. Ransom Note(赎金信)类似&#xff0c;只是字符变为了…

绝世唐门:霍挂六个十万年魂环,一穿七灭团再现,淘汰赛顺利晋级

Hello,小伙伴们&#xff0c;我是拾荒君。 国漫《斗罗大陆2绝世唐门》第32期超前爆料&#xff0c;霍雨浩开局便释放六个十万年魂环&#xff0c;以绝对的气场碾压天灵学院代表队。首次参与高级魂师大赛&#xff0c;霍雨浩便大放异彩秀出超级霍挂&#xff0c;此等操作就连当初的唐…

【Linux】wait()和waitpid()函数

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;Linux系列专栏&#xff1a;Linux基础 &#x1f525; 给大家…

Acwing第 141 场周赛

A题 签到模拟即可 B题 单独考虑每一个a[i]&#xff0c;如果i要是答案需要指针移动多少次&#xff0c;然后算完&#xff0c;排个序&#xff0c;指针移动最少的就是答案。 #include <bits/stdc.h> #define int long long #define rep(i,a,b) for(int i (a); i < (…

利用VPN设备漏洞入侵!新型勒索软件CACTUS攻击手法分析

近期&#xff0c;亚信安全应急响应中心截获了利用VPN设备已知漏洞传播的新型勒索软件CACTUS&#xff0c;该勒索于2023年3月首次被发现&#xff0c;一直保持着活跃状态。CACTUS勒索软件通过Fortinet VPN的已知漏洞进行入侵&#xff08;黑客首先获取到VPN账号&#xff0c;再通过V…