支持向量机【OpenCV&Python】

    技术2022-07-11  87

    支持向量机

    0、引言1、理论基础1.1 分类1.2 分类器1.3 将不可分变为可分1.4 概念总结 2、案例介绍2.1 生成模拟数据2.2 构造分组标签2.3 训练2.4 分类2.5 显示分类结果2.6 完整程序2.7 运行结果

    0、引言

    参考书籍 《OpenCV轻松入门》——面向Python李立宗著,电子工业出版社出版 支持向量机(Support Vector,SVM)是一种二分类模型,目标是寻找一个标准(称为超平面),从而对样本数据进行分割。支持向量机是最好的现成分类器之一,这里所谓的“现成”是指分类器不加修改即可使用。

    分割的原则是确保分类最优化(类别之间的间隔最大)。 当数据集较小时,使用支持向量机分类非常有效。

    在对原始数据进行分类的过程中,可能无法使用线性方法实现分割。支持向量机在分类时,把无法线性分割的数据映射到映射到高维空间,然后在高维空间找到分类最优的线性分类器。

    1、理论基础

    1.1 分类

    某IT企业在2017年通过笔试、面试的形式招聘了一些员工。2018年,企业针对这批员工在过去一年的实际表现进行了测评,将他们的实际表现分别确定为A级(优秀)和B级(良好)。 这批员工的笔试、面试、等级成绩如图1所示。横坐标为笔试成绩,纵坐标为面试成绩,位于右上角的圆点表示测评成绩是A级,位于左下角的小方块表示测评成绩是B级。 图1

    如何根据笔试和面试成绩确定哪些员工可能是未来的优秀员工呢?偷懒的做法是将笔试和面试的标准都定的很高,但是这样会漏掉某些优秀的员工。所以,要合理地确定笔试和面试成绩标准,确保能够高效地找到A类员工。 图2

    1.2 分类器

    在图2中用于划分不同类型的直线。就是分类器。重点在于,寻找最优分类器。 这里,离分类器最近的点到分类器的距离称为间隔(margin)。我们要做的是使间隔尽可能地大,这样分类器在处理数据时就会更加准确。 如图3所示,左下角的间隔最大。

    离分类器最近的点就叫做支持向量(support vector)。正是这些支持向量,决定了分类器所在的位置。 图3

    1.3 将不可分变为可分

    上述的数据十分简单,我们可以使用一条直线(线性分类器)就可以对其划分。

    然而,现实生活中的大部分问题都是十分复杂的,通常情况下,支持向量机会将不那么容易分类的数据通过函数映射变为可分类的。

    支持向量机在处理数据时,如果在低位空间内无法完成分类,就会自动将数据映射到高维空间,使其变成线性可分的。简单来说,就是对当前数据进行映射操作。并且,支持向量机能够通过核函数有效地降低计算复杂度。

    1.4 概念总结

    支持向量机可以处理任何维度的数据。在不同的维度下,支持向量机都会尽可能寻找类似于二维空间中的直线的线性分类器。

    例如,在二维空间,支持向量机会寻找一条能够划分当前数据的直线;在三维空间,支持向量机会寻找一个能够划分当前数据的平面;在更高维的空间,支持向量机会寻找一个能够划分当前数据的超平面(hyperplane)。

    超平面属于线性分类器。

    “支持向量机”是由**“支持向量”和“机器”构成的。 “支持向量”是离分类器最近的那些点,这些点位于“最大间隔”**上。通常情况下,分类仅依靠这些点来完成,而与其他点无关。

    “机器”是指分类器。

    2、案例介绍

    在使用支持向量机模块时,需要先使用函数cv2.ml.SVM-create()生成用于训练的空分类器模型。该函数的语法格式为:svm = cv2.ml.SVM-create()

    获取了空分类器svm后,针对该模型使用svm.train()函数对训练数据进行分类,该函数的语法格式为:训练结果 = svm.train(训练数据,训练数据排列格式,训练数据的标签) 各参数含义如下: **训练数据:**表示原始数据,用来训练分类器; **训练数据排列格式:**原始数据的排列格式有两种,一种是按行排列(cv2.ml.ROW-SAMPLE,每一条训练数据占一行),一种是按列排列(cv2.ml.COL-SAMPLE,每一条训练数据占一列); ****训练数据的标签:**原始数据的标签; 训练结果:**训练结果的返回值。

    完成对分类器的训练后,使用 🎈svm.predict() 🎈函数即可使用训练好的分类器模型对测试数据进行分类,其语法格式为:(返回值,返回结果) = svm.predict(测试数据)

    在实际使用中,可能会根据需要对其中的参数进行调整。例如:可以通过setType()函数设置类别,通过setKernel()函数设置核类型,通过set设置支持向量机的参数C(惩罚系数,挤兑误差的宽容度,默认值为0)

    例1:已知老员工的笔试成=成绩、面试成绩及对应的等级表现,根据新入职员工的笔试成绩、面试成绩预测其可能的表现。

    2.1 生成模拟数据

    ######### 生成模拟数据 # 构造20组笔试成绩和模拟成绩都在[95,100)之间的数据对,在一年后对应的工作表现为A级 a = np.random.randint(95,100,(20,2)).astype(np.float32) # 构造20组笔试成绩和模拟成绩都在[95,100)之间的数据对,在一年后对应的工作表现为B级 a = np.random.randint(95,100,(20,2)).astype(np.float32) # 最后,将两组数据合并,并使用numpy.array对其进行数据类型转换 data = np.vstack((a,b)) data = np.array(data,dtype= 'float32')

    2.2 构造分组标签

    ######### 构造分组标签 # 首先,为对应表现为A级的分布在[95,100)区间的数据,构造标签0 aLabel = np.zeros((20,1)) # 接下来,为对应表现为B级的分布在[90,95)区间的数据,构造标签1 bLabel = np.ones((20,1)) # 最后,将两组标签合并,并使用numpy.array对其进行数据类型转换 label = np.vstack((aLabel,bLabel)) label = np.array(label,dtype='int32')

    2.3 训练

    ####### 训练 # 用ml机器学习模块SVM_create()创建svm svm = cv2.ml.SVM_create() # 属性设置,直接采用默认值即可 # svm.setType(cv2.ml.)SVM_C_SVC # svm type # svm.setKernel(cv2.ml.SVM_lINEAR) # line # svm.setC(0.01) # 训练 result = svm.train(data,cv2.ml.ROW_SAMPLE,label)

    2.4 分类

    ####### 分类 # 生成两个随机的数据对(笔试成绩,面试成绩)用于测试。可以用随机数,也可以直接指定两个数字。 # 这里,我们生成两组笔试成绩和面试成绩差别较大的数据。 test = np.vstack([[98,90],[90,99]]) test = np.array(test,dtype='float32') ######## 使用函数svm.predict()对随机成绩进行分类 (p1,p2) = svm.predict(test)

    2.5 显示分类结果

    ###### 可视化,显示分类结果 # 将训练数据、测试数据在图像上表示出来 plt.scatter(a[:,0],a[:,1],80,'g','o') plt.scatter(b[:,0],b[:,1],80,'b','s') plt.scatter(test[:,0],test[:,1],80,'r','*') plt.show() #### 将测试数据和预测分类显示出来 print (test) print (p2)

    2.6 完整程序

    ###################################################################33 import cv2 import numpy as np import matplotlib.pyplot as plt ######### 第一步,准备数据 # 构造20组笔试成绩和模拟成绩都在[95,100)之间的数据对,在一年后对应的工作表现为A级 a = np.random.randint(95,100,(20,2)).astype(np.float32) # 构造20组笔试成绩和模拟成绩都在[95,100)之间的数据对,在一年后对应的工作表现为B级 b = np.random.randint(95,100,(20,2)).astype(np.float32) # 最后,合并数据,并使用numpy.array对其进行数据类型转换 data = np.vstack((a,b)) data = np.array(data,dtype= 'float32') ######### 第二步,构造分组标签,0代表A级,1代表B级 # 首先,为对应表现为A级的分布在[95,100)区间的数据,构造标签0 aLabel = np.zeros((20,1)) # 接下来,为对应表现为B级的分布在[90,95)区间的数据,构造标签1 bLabel = np.ones((20,1)) # 最后,合并标签,并使用numpy.array对其进行数据类型转换 label = np.vstack((aLabel,bLabel)) label = np.array(label,dtype='int32') ####### 第三步,训练 # 用ml机器学习模块SVM_create()创建svm svm = cv2.ml.SVM_create() # 属性设置,直接采用默认值即可 # svm.setType(cv2.ml.)SVM_C_SVC # svm type # svm.setKernel(cv2.ml.SVM_lINEAR) # line # svm.setC(0.01) # 训练 result = svm.train(data,cv2.ml.ROW_SAMPLE,label) ####### 第四步,预测 # 生成两个随机的数据对(笔试成绩,面试成绩)用于测试。可以用随机数,也可以直接指定两个数字。 # 这里,我们生成两组笔试成绩和面试成绩差别较大的数据。 test = np.vstack([[98,90],[90,99]]) test = np.array(test,dtype='float32') ######## 使用函数svm.predict()对随机成绩进行预测 (p1,p2) = svm.predict(test) ###### 第五步,可视化 # 将训练数据、测试数据在图像上表示出来 plt.scatter(a[:,0],a[:,1],80,'g','o') plt.scatter(b[:,0],b[:,1],80,'b','s') plt.scatter(test[:,0],test[:,1],80,'r','*') plt.show() #### 打印原始测试数据test,预测结果 print (test) print (p2)

    2.7 运行结果

    运行结果1: 运行结果2: 因为我们采用随机方式生成数据,所以每次运行时所生成的数据会有所不同,运行结果也会有所差异。

    Processed: 0.012, SQL: 9