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

news2024/12/27 16:22:14

创建时间: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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【八大排序】冒泡排序 | 快速排序 + 图文详解!!

📷 江池俊: 个人主页 🔥个人专栏: ✅数据结构冒险记 ✅C语言进阶之路 🌅 有航道的人,再渺小也不会迷途。 文章目录 交换排序一、冒泡排序1.1 算法步骤 动图演示1.2 冒泡排序的效率分析1.3 代码实现1.4 …

HSRP配置指南

实验大纲 第 1 部分:验证连通性 步骤 1:追踪从 PC-A 到 Web 服务器的路径 步骤 2:追踪从 PC-B 到 Web 服务器的路径 步骤 3:观察当 R3 不可用时,网络的行为 第 2 部分:配置 HSRP 主用和 备用路由器 步…

【Crypto | CTF】BUUCTF rsarsa1

天命:第二题RSA解密啦,这题比较正宗 先来看看RSA算法 这道题给出了 p,q,E,就是给了两个质数和公钥 有这三个东西,那就可以得出私钥了 最后把私钥和质数放进去解密即可得到解密后的明文 from gmpy2 impor…

公交最短距离-算法

题目 给定一个一维数组,其中每一个元素表示相邻公交站之间的距离,比如有四个公交站A,B,C,D,对应的距离数组为,1,2,3,4,如下图示 给定目标站X和Y,求他们之间最短的距离 解题 遍历一次整个数组,…

考研/计算机二级数据结构刷题之顺序表

目录 第一题 顺序表的初始化,销毁,头插,尾插,头删,尾删,指定位置插入,指定删除以及打印 第二题 移除元素 题目链接: OJ链接 题目详解:移除元素 第三题:删…

回溯法:回溯法通用模版汇总以及模版应用

从一个问题开始 给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。 示例: 输入: n 4, k 2 输出: [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4] ] 很容易想到 用两个for循环就可以解决。 如果n为100,k为50呢,那就50层for循…

问题:测风站应设置在平直的巷道中,其前后()范围内不得有障碍物和拐弯等局部阻力。 #微信#媒体

问题:测风站应设置在平直的巷道中,其前后()范围内不得有障碍物和拐弯等局部阻力。 参考答案如图所示

U盘里的东西刚存进去就没了怎么回事?怎么办

U盘里的东西刚存进去就没了怎么办?U盘是我们平时常用的存储设备之一,但有时候会出现一些问题。其中之一就是将东西存进去后,发现数据竟然消失了。这是一个令人困扰的问题,可能会导致我们的重要文件丢失。在本文中,我们…

RT-Thread线程管理(使用篇)

layout: post title: “RT-Thread线程管理” date: 2024-1-26 15:39:08 0800 tags: RT-Thread 线程管理(使用篇) 之后会做源码分析 线程是任务的载体,是RTT中最基本的调度单位。 线程执行时的运行环境称为上下文,具体来说就是各个变量和数据&#xff0c…

利用OpenCV实现物流与生产线自动化的革命性突破

背景介绍: 在当今高度自动化的时代,物流和生产线上的每一个环节都关乎企业的核心竞争力。传统的生产方式往往依赖于人工检测和操作,这不仅效率低下,而且容易出错。为了解决这一问题,越来越多的企业开始寻求利用计算机视…

流畅的Python(七)-函数装饰器和闭包

一、核心要义 主要解释函数装饰器的工作原理,包括最简单的注册装饰器和较复杂的参数化装饰器。同时,因为装饰器的实现依赖于闭包,因此会首先介绍闭包存在的原因和工作原理。 二、代码示例 1、变量作用域规则 #!/usr/bin/env python # -*-…

记录一次使用ant design 中 ConfigProvider来修改样式导致样式改变的问题(Tabs嵌套Tabs)

一 说明 继之前的一篇文章:antd5 Tabs 标签头的文本颜色和背景颜色修改 后,发现在被修改后的Tab中继续嵌套Tabs组件,这个新的Tabs组件样式跟外层Tabs样式也是一致的,如下图所示: 二 原因 在修改外层tabs样式时&…

学习Spring的第十三天

非自定义bean注解开发 设置非自定义bean : 用bean去修饰一个方法 , 最后去返回 , spring就把返回的这个对象,放到Spring容器 一 :名字 : 如果bean配置了参数 , 名字就是参数名 , 如果没有 , 就是方法名字 二 : 如果方法产生对象时 , 需要注入数据 , 在方法参数设置即可 , …

iOS 包含行间距计算富文本size

在一次开发过程中,发现带有行间距的富文本计算高度,会有不准确的情况,富文本内容明明很长,但是计算出的高度只有不到20像素,导致整个cell的高度计算异常。 需求上是文字固定宽度,最多显示3行,超…

【Simulink系列】——动态系统仿真 之 简单系统

引入 不同的系统具有不同的输入与输出。一般来说,输入输出数目越多,系统越复杂。最简单的系统只要一个输入一个输出(SISO),且其任意时刻的输出只与当前时刻的输入有关。 一、简单系统定义 对于满足下列条件的系统&a…

android 网络拦截器统一处理请求参数和返回值加解密实现

前言 项目中遇到参数加密和返回结果加密的业务 这里写一下实现 一来加深记忆 二来为以后参考铺垫 需求 项目在开发中涉及到 登陆 发验证码 认证 等前期准备接口 这些接口需要单独处理 比如不加密 或者有其他的业务需求 剩下的是登陆成功以后的业务需求接口 针对入参和返回值…

【Android新版本兼容】onBackPressed()方法被弃用的解决方案

提示:此文章仅作为本人记录日常学习使用,若有存在错误或者不严谨得地方欢迎指正。 文章目录 一、使用 AndroidX API 实现预测性返回手势1.1 添加依赖1.2 启用返回手势1.3 注册OnBackPressedCallback()方法来处理返回手势 一、使用 AndroidX API 实现预测…

【MIT 6.S081】2020, 实验记录(5),Lab: lazy allocation

目录 Task 1: Eliminate allocation from sbrk()Task 2: Lazy allocationTask 3: Lazytests and Usertests 在学习了 page fault 这一节课后,了解了操作系统是如何结合 page table 和 trap 利用 page fault 来实现一系列的神奇的功能。这个 lab 就是在 XV6 中实现 l…

前端面试拼图-数据结构与算法

摘要:总结一些前端算法题,持续更新! 一、数据结构与算法 时间复杂度-程序执行时需要的计算量(CPU) 空间复杂度-程序执行时需要的内存空间 前端开发:重时间,轻空间 1.把一个数组旋转k步 arr…

CSS的复合选择器

一,什么是复合选择器 常用的复合选择器有:后代选择器、子选择器、并集选择器和伪类选择器。 二,后代选择器(用空格)(重点) 后代选择器也称包含选择器,可以选择父元素里面的子元素。写法就是外层标签在前面,内层标签写后面,中间要有空格隔开。当标签发生嵌套时,内层…