支持向量机(Support Vector Machine, SVM)是一种二分类模型,目标是寻找一个标准(称为超平面)对样本数据进行分割,分割的原则是确保分类最优化(类别之间的间隔最大)。
当数据集较小时,使用支持向量机进行分类非常有效。
支持向量机是最好的现成分类器之一,“现成”是指分类器不加修改即可直接使用。
在对原始数据分类的过程中,可能无法使用线性方法实现分割。支持向量机在分类时,把无法线性分割的数据映射到高维空间,然后在高维空间找到分类最优的线性分类器。
Python支持向量机的库: sk-learn , LIBSVM等
OpenCV也提供了对支持向量机的支持
用于划分不同类别的直线,就是分类器。
构造分类器时,非常重要的一项工作就是找到最优分类器。
找到支持向量机:在已有数据中,找到离分类器最近的点,确保它们离分类器尽可能地远。
离分类器最近的点到分类器的距离称为间隔(margin)。希望间隔尽可能地大,这样分类器在处理数据时,就会更准确。
离分类器最近的那些点叫作支持向量(support vector)。 决定了分类器所在的位置。
将不可分变为可分
支持向量机会将不那么容易分类的数据通过函数映射变为可分类的。
支持向量机在处理数据时,如果在低维空间内无法完成分类,就会自动将数据映射到高维空间,使其变为(线性)可分的。简单地讲,就是对当前数据进行函数映射操作。
例如: 在分类时,通过函数f的映射,让左图中本来不能用线性分类器分类的数据变为右图中线性可分的数据。
同时: 支持向量机能够通过核函数有效地降低计算复杂度。
实际上支持向量机可以处理任何维度的数据。在不同的维度下,支持向量机都会尽可能寻找类似于二维空间中的直线的线性分类器。
例如,在二维空间,支持向量机会寻找一条能够划分当前数据的直线;在三维空间,支持向量机会寻找一个能够划分当前数据的平面(plane);在更高维的空间,支持向量机会尝试寻找一个能够划分当前数据的超平面(hyperplane)。
一般情况下,把能够可以被一条直线(更一般的情况,即一个超平面)分割的数据称为线性可分的数据,所以超平面是线性分类器。
“支持向量机”是由“支持向量”和“机器”构成的。
支持向量机是一种基于关键点的分类算法。
在使用支持向量机模块时,需要先使用函数cv2.ml.SVM_create()生成用于后续训练的空分类器模型。
语法格式:
svm = cv2.ml.SVM_create()
获取了空分类器svm后,针对该模型使用svm.train()函数对训练数据进行训练
语法格式
训练结果= svm.train(训练数据,训练数据排列格式,训练数据的标签)
例如: 用于训练的数据为data,其对应的标签为label,每一条数据按行排列,对分类器模型svm进行训练,所使用的语句为:
返回值 = svm.train(data, cv2.ml.ROW_SAMPLE, label)
完成对分类器的训练后,使用svm.predict()函数即可使用训练好的分类器模型对测试数据进行分类,其语法格式为:
(返回值,返回结果) = svm.predict(测试数据)
OpenCV支持对多个参数的自定义,例如:可以通过setType()函数设置类别,通过setKernel()函数设置核类型,通过setC()函数设置支持向量机的参数C ( 惩罚系数,即对误差的宽容度,默认值为0 )。
题目: 已知员工的笔试成绩、面试成绩及对应的等级表现,根据新入职员工的笔试成绩、面试成绩预测其可能的表现。
首先构造一组随机数,并将其划分为两类,然后使用OpenCV自带的支持向量机模块完成训练和分类工作,最后将运算结果显示出来。
具体步骤:
生成模拟数据
模拟生成入职一年后表现为A级的员工入职时的笔试和面试成绩。
构造20组笔试和面试成绩都分布在[95, 100)区间的数据对:
a = np.random.randint(95,100, (20, 2)).astype(np.float32)
上述模拟成绩,在一年后对应的工作表现为A级。
模拟生成入职一年后表现为B级的员工入职时的笔试和面试成绩。
构造20组笔试和面试成绩都分布在[90, 95)区间的数据对:
b = np.random.randint(90,95, (20, 2)).astype(np.float32)
上述模拟成绩,在一年后对应的工作表现为B级。
最后,将两组数据合并,并使用numpy.array对其进行类型转换:
data = np.vstack((a, b))
data = np.array(data, dtype='float32')
构造分组标签
为对应表现为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')
训练
用支持向量机模块对已知的数据和其对应的标签进行训练:
svm = cv2.ml.SVM_create()
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()
将测试数据及预测分类结果显示出来:
print(test)
print(p2)
完整程序
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 准备数据
a = np.random.randint(95,100, (20, 2)).astype(np.float32)
b = np.random.randint(90,95, (20, 2)).astype(np.float32)
data = np.vstack((a, b))
data = np.array(data, dtype='float32')
# 建立分组标签,0代表A级,1代表B级
aLabel=np.zeros((20,1))
bLabel=np.ones((20,1))
label = np.vstack((aLabel, bLabel))
label = np.array(label, dtype='int32')
# 训练
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')
(p1, p2) = svm.predict(test) # test 是 [[数据1],[数据2]] 结构的
# 结果
print(test)
print("res1",p2[0])
print("res2",p2[1])
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()