【ML】支持向量机SVM及Python实现(详细)

from sklearn.preprocessing import StandardScaler
from matplotlib.colors import ListedColormap
from sklearn.svm import SVC


### 2.1 加载数据样本



加载样本数据及其分类标签

iris = datasets.load_iris()
X = iris.data[:, [2, 3]] #按花瓣划分
#X = iris.data[:,[0,1]] #按花萼划分
y = iris.target

print(‘Class labels:’, np.unique(y)) # 分类标签列表 [0 1 2]

np.unique(arr): arr为一维数组/列表,结果返回一个列表,去除arr中重复的元素,并从小到大排序



> 
> **解释:**
> 
> 
>         加载鸢尾花数据集load\_iris(),数据集中包含150行(150个样本),前四列用于识别鸢尾花的属性,第五列推测出的鸢尾花类别Setosa,Versicolour,Virginica三种,三种类别分别用0、1、2表示,每个样本构成形如[0花萼长度 1宽度 2花瓣长度 3宽度 4鸢尾花类别]。
> 
> 
>         .data为加载鸢尾花的四个属性,.data[:,[2,3]]表示加载所样本的索引第2、3列,即加载所有样本花瓣的两个属性。
> 
> 
>         .target为加载鸢尾花的分类标签,前50个样本为0类、中间50个样本为1类、后50个样本为2类。
> 
> 
>         np.unique(y)可以去除y中重复的元素,并按元素从小到大返回一个列表,该列表表示所有分类标签。
> 
> 
>         所以:
> 
> 
>         X:本次实验所用到的样本的特征集合;
> 
> 
>         y:X数据集中的样本所对应的分类标签;
> 
> 
> 


### 2.2 划分训练集和测试集



#? 划分70%训练集和30%测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=1, stratify=y)
“”"
train_test_split()函数: 用于将数据集划分为训练集train和测试集test
X: 待划分的样本特征集
y: 数据集X对应的标签
test_size: 0~1表示测试集样本占比、整数表示测试集样本数量
random_state: 随机数种子。在需要重复实验的时候保证得到一组一样的随机数据。每次填1(其他参数一样),每次得到的随机数组一样;每次填0/不填,每次都不一样
stratify=y: 划分数据集时保证每个类别在训练集和测试集中的比例与原数据集中的比例相同
“”"

print(‘Labels counts in y:’, np.bincount(y)) # 原数据集中各分类标签出现次数 [50 50 50]
print(‘Labels counts in y_train:’, np.bincount(y_train)) # 训练集中各分类标签出现次数 [35 35 35]
print(‘Labels counts in y_test:’, np.bincount(y_test)) # 测试集中各分类标签出现次数 [15 15 15] 35:15=7:3

np.bincount(arr): 返回一个数组array,长度=max(arr[i])+1,array[i]=count(arr[i])。(长度=arr中最大元素值+1,每个元素值=它当前索引值在arr中出现的次数)



> 
> **解释:**
> 
> 
>         train\_test\_split()函数用于划分训练集和测试集。
> 
> 
>         X表示待划分的样本特征集;y表示划分出的样本结果;test\_size=0.3表示划分30%的测试集和70%的训练集;random\_state=1是随机数种子为1,可以保证重复实验的时候每次得到的随机数组是一样的;stratify=y可以使训练集train和测试集test中的数据分类比例与原数据集比例y保持一致。
> 
> 
>         下面分别表示打印输出原数据集中各分类标签出现次数:[50 50 50];训练集中各分类标签出现次数:[35 35 35];测试集中各分类标签出现次数:[15 15 15]。
> 
> 
>         所以:
> 
> 
>         X\_train:数据的训练集;
> 
> 
>         X\_test:数据的测试集;
> 
> 
>         y\_train:X\_train对应的分类标签;
> 
> 
>         y\_test:X\_test对应的分类标签;
> 
> 
> 


### 2.3 标准化



标准化训练集和测试集

sc = StandardScaler() # 定义一个标准缩放器
sc.fit(X_train) # 计算均值、标准差
X_train_std = sc.transform(X_train) # 使用计算出的均值和标准差进行标准化
X_test_std = sc.transform(X_test) # 使用计算出的均值和标准差进行标准化
“”"
! StandardScaler()
均值:对每个特征求均值,即对每列求均值
去均值:每个特征的值减去对应特征的均值
标准差:去均值后平方和,然后除以总值的数量,最后开根号
标准分数:去均值、除以标准差

1、中心化:去均值,将整体数据平移,中心为(0,0)
2、缩放:标准分数,进行缩放
标准化:去均值、除以标准差。将数据的分布转为正态分布。每个特征的值 均值=0、方差=1
目的:
将特征表现为标准正态分布数据。
如果某个特征的方差比其他特征大几个数量级,那么它就会在学习算法中占据主导位置,导致学习器不能从其他特征中学习,从而降低精度。
加快梯度下降求解的速度。
“”"



> 
> **解释:**
> 
> 
>         首先定义一个标准缩放器sc,通过sc.fit(X\_train)计算出训练集的均值和标准差,下面的sc.transform()是使用.fit()计算出的均值和标准差对X\_train、X\_test两个数据集进行标准化,标准化的操作为对每个元素去均值再除以标准差,将数据的分布转为正态分布,每个特征的值均值=0、方差=1,标准化的目的是加快梯度下降求解的速度,因为如果某个特征的方差比其他特征大几个数量级,那么它就会在学习算法中占据主导位置,导致学习器不能从其他特征中学习,从而降低精度。
> 
> 
>         所以:
> 
> 
>         X\_train\_std:训练集标准化后的数据;
> 
> 
>         X\_test\_std:测试集标准化后的数据;
> 
> 
> 


### 2.4 绘制决策边界图函数


#### 2.4.1 设置标记生成器和颜色图



#? 绘制决策边界图 函数
def plot_decision_regions(X, y, classifier, test_idx=None, resolution=0.02):
#? 设置标记生成器和颜色图
markers = (‘s’, ‘^’, ‘o’, ‘x’, ‘v’) # 标记生成器
colors = (‘red’, ‘blue’, ‘lightgreen’, ‘gray’, ‘cyan’) # 定义颜色图
cmap = ListedColormap(colors[:len(np.unique(y))])



> 
> **解释:**
> 
> 
>         markers存放的是散点图所需要的标记;
> 
> 
>         colors存放的是做决策曲面和散点图所用到的颜色;
> 
> 
>         cmap表示自定义一个颜色图。
> 
> 
> 
> 


#### 2.4.2 绘制决策曲面



#? 绘制决策曲面
x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1   # x轴范围 x1_min ~ x1_max
x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1   # y轴范围 x2_min ~ x2_max
xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution),   # 生成网络点坐标矩阵
                       np.arange(x2_min, x2_max, resolution))
Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)
Z = Z.reshape(xx1.shape)                        # 对不同分类进行标记
plt.contourf(xx1, xx2, Z, alpha=0.3, cmap=cmap) # 生成边界图
plt.xlim(xx1.min(), xx1.max())
plt.ylim(xx2.min(), xx2.max())


> 
> **解释:**
> 
> 
>         上述操作主要完成绘制决策曲面的操作。下面看一下代码实现细节。
> 
> 
>         x1\_min、x1\_max:表示所绘制后的坐标系横轴的范围;
> 
> 
>         x2\_min、x2\_max:表示所绘制后的坐标系纵轴的范围;
> 
> 
>         xx1、xx2:表示经过.meshgrid()后所生成的坐标系的网格点;
> 
> 
>         Z:表示用已经训练好的svm(下述训练)对网格点进行分类划分,标记网格上不同区域的类别;
> 
> 
>         plt.contourf():表示在网格中生成不同分类的边界图,并使用前面我们已经定义好的颜色及smap进行不同分类区域的颜色填充,alpha表示所填充颜色的透明度。
> 
> 
> 


#### 2.4.3 绘制所有样本散点图



#? 绘制 所有样本 散点图
for idx, cl in enumerate(np.unique(y)):
    plt.scatter(x=X[y == cl, 0],    # 散点的x坐标(分类标签==cl)
                y=X[y == cl, 1],    # 散点的y坐标(分类标签==cl)
                alpha=0.8,          # 散点的透明度
                c=colors[idx],      # 散点的颜色
                marker=markers[idx],# 散点的样式
                label=cl,           # 散点的图例名称
                edgecolor='black')  # 散点的边缘颜色


> 
> **解释:**
> 
> 
>         上述代码所完成的操作为对所有样本按不同的分类在同一坐标系下绘制不同样式的散点图。下面看代码实现细节。
> 
> 
>         X[y==cl,0]:表示取X中类别为cl类型的第一列(索引第0列),作为坐标的横坐标;同理纵坐标为同类别的X中的第二列(索引第1列);alpha=0.8表示控制散点的透明度;c=colors[idx]表示控制散点的颜色,颜色使用自定义好的颜色集colors中相对应的颜色;marker=markers[idx]表示控制散点的样式,使用自定义好的标记器markers中相对应的标记;label=cl表示设置散点对应图例的名称用其索引;edgecolor=’black’表示设置散点边缘颜色为黑色。
> 
> 
> 
> 


#### 2.4.4 绘制测试集样本散点图



#? 绘制 测试样本 散点图
if test_idx:    # 默认test_idx=None 如果未设置该参数,则不绘制测试样本
    X_test, y_test = X[test_idx, :], y[test_idx]

    plt.scatter(X_test[:, 0],       # 散点的横坐标
                X_test[:, 1],       # 散点的纵坐标
                c='y',              # 散点的颜色【黄色】
                edgecolor='black',  # 散点的边缘颜色【黑色】
                alpha=1.0,          # 散点的透明度【1】
                linewidth=1,        # 散点的边缘线宽【1】
                marker='*',         # 散点的样式【圆圈】
                s=150,              # 散点的面积【150】
                label='test set')   # 散点的图例名称【test set】


> 
> **解释:**
> 
> 
>         上述代码完成的操作是对测试集中的样本按不同的分类在同一坐标系下绘制样式为“五角星”的散点图。绘制散点图的操作同理于上面“绘制所有样本散点图”的过程; 
> 
> 
> 


### 2.5 训练线性支持向量机



#? 训练线性支持向量机
svm = SVC(kernel=‘linear’, C=1.0, random_state=1) # 定义线性支持向量分类器 (linear为线性核函数)
svm.fit(X_train_std, y_train) # 根据给定的训练数据拟合训练SVM模型
plot_decision_regions(X_combined_std, y_combined, classifier=svm, test_idx=range(105, 150)) # 绘制决策边界

plt.xlabel(‘petal length [standardized]’) # x轴标签
plt.ylabel(‘petal width [standardized]’) # y轴标签
plt.legend(loc=‘upper left’) # 图例位于左上方
plt.tight_layout() # 使子图填充整个图像区域
#plt.savefig(‘images/03_11.png’, dpi=300)
plt.show()



> 
> **解释:**
> 
> 
>         上述代码训练一个支持向量机,并结果绘图。
> 
> 
>         首先将样本标准化后的训练集和测试集进行一个竖直方向的拼接,所以X\_combined\_std为一个二维的数组,将分类标签的训练集和测试集进行水平方向的拼接。拼接的操作是为了便于下面操作。
> 
> 
>         下面进行训练线性支持向量机svm,首先定义了一个线性支持向量分类器,使用的核函数为线性核函数“linear”,惩罚因子C=1。然后通过svm.fit(X\_train\_std,y\_trian)根据给定的训练数据拟合训练出SVM模型svm。
> 
> 
>         然后调用plot\_decision\_regions()函数绘制决策图。其中实参test\_idx=range(105,150)是因为样本集中训练集与测试集的划分比例为7:3,共有样本数据150个,所以105:45=7:3,所以从索引第105~索引第149共45个样本为测试集,前105个为训练集。
> 
> 
> 下面几行代码为设置图像的一些参数。
> 
> 
> 


### 2.6 测试集进行测试



#? 使用测试集进行数据预测
y_pred = svm.predict(X_test_std) # 用训练好的分类器svm预测数据X_test_std的标签
print(‘Misclassified samples: %d’ % (y_test != y_pred).sum()) # 输出错误分类的样本数
print(‘Accuracy: %.2f’ % svm.score(X_test_std, y_test)) # 输出分类准确率
“”"
! (arr1 != arr2).sum():
arr1、arr2为数组类型
(arr1 != arr2): 输出一个列表,元素为bool类型,两数组对应位置不相等为True
.sum(): 统计列表中True的个数
! svm.score(X_test_std, y_test)
返回给定测试集与对应标签的平均准确率
“”"



> 
> **解释:**
> 
> 
>         svm.predict(X\_test\_std):对已经训练好的支持向量机对测试集X\_test\_std进行测试。所以:
> 
> 
>         y\_pred:存放对测试集X\_test\_std的预测分类结果;
> 
> 
>         (y\_test != y\_pred).sum():对经过支持向量机分类的结果进行统计分类错误的个数;
> 
> 
>         snm.score(X\_test\_std,y\_test):返回给定测试集X\_test\_std与对应标签的平均准确率。
> 
> 
> 


## 三、实验结果分析


### 3.1 终端输出


运行代码得到终端输出结果为: 



终端输出结果:
Class labels: [0 1 2]
Labels counts in y: [50 50 50]
Labels counts in y_train: [35 35 35]
Labels counts in y_test: [15 15 15]
Misclassified samples: 1
Accuracy: 0.98



> 
> **解释:**
> 
> 
>         分类的标签有:[0 1 2];
> 
> 
>         y中标签的个数统计:[50 50 50];
> 
> 
>         y\_train中标签个数统计:[35 35 35];
> 
> 
>         y\_test中标签个数统计:[15 15 15];
> 
> 
>         对测试集y\_test错分类的样本有:1个;
> 
> 
>         svm的分类准确率为:0.98;
> 
> 
> 


### 3.2 训练好的支持向量机SVM的决策面


![](https://img-blog.csdnimg.cn/direct/254df5120d6a45fb970bd96aaa0ee284.png)


上图为支持向量机svm的决策面的分布的情况,从最终的决策面的位置可以看到,**红色区域为一类,蓝色区域为一类,绿色区域为一类**,**红正方形、蓝三角形、绿圆圈**分别为三类别的样本的分布情况,可以看到决策面对这些样本的划分情况还是能够区分开来不同类别的。


下面查看测试集X\_test在三个不同区域的分布情况。


### 3.3 SVM对测试集的分类分布结果


![](https://img-blog.csdnimg.cn/direct/415adf0b7b6f4af5b71075e9422eaaca.png)


上图为测试集X\_test在三个不同区域(三种类别)的分布情况,其中**黄色五角星**为测试样本的图例,能够看到决策面对测试集能够很明显的划分出不同类,结合图4-1的终端输出结果可以看到测试集划分的正确率为98%,可以很好的划分出正确结果。


## 四、整体总结


支持向量机如果想划分效果很好,就需要找到**支持向量**的分布,再就是找到最大间隔的分离超平面,解决好上诉两个问题就基本可以实现支持向量机。


## 五、总代码




import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from matplotlib.colors import ListedColormap
from sklearn.svm import SVC

#? 加载样本数据及其分类标签
iris = datasets.load_iris()
X = iris.data[:, [2, 3]] #按花瓣划分
#X = iris.data[:,[0,1]] #按花萼划分
y = iris.target

print(‘Class labels:’, np.unique(y)) # 分类标签列表 [0 1 2]

np.unique(arr): arr为一维数组/列表,结果返回一个列表,去除arr中重复的元素,并从小到大排序

#? 划分70%训练集和30%测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=1, stratify=y)
“”"
train_test_split()函数: 用于将数据集划分为训练集train和测试集test
X: 待划分的样本特征集
y: 数据集X对应的标签
test_size: 0~1表示测试集样本占比、整数表示测试集样本数量
random_state: 随机数种子。在需要重复实验的时候保证得到一组一样的随机数据。每次填1(其他参数一样),每次得到的随机数组一样;每次填0/不填,每次都不一样
stratify=y: 划分数据集时保证每个类别在训练集和测试集中的比例与原数据集中的比例相同
“”"
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Python工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Python开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以扫码获取!!!(备注Python)

onvert/46506ae54be168b93cf63939786134ca.png)

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以扫码获取!!!(备注Python)

img
  • 35
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值