支持向量机(Support vector machine, SVM)是一种二分类模型,是按有监督学习方式对数据进行二元分类的广义线性分类器。
支持向量机经常应用于模式识别问题,如人像识别、文本分类、手写识别、生物信息识别等领域。
SVM 的基本模型是特征空间上间隔最大的线性分类器,还可以通过核函数方法扩展为非线性分类器。
**SVM 的分割策略是间隔最大化,通过寻求结构化风险最小来提高模型的泛化能力,实现经验风险和置信范围的最小化。**SVM 可以转化为求解凸二次规划的问题,学习算法就是求解凸二次规划的最优化算法。
欢迎关注 Youcans 原创系列,每周更新数模笔记
Python数模笔记-PuLP库
Python数模笔记-StatsModels统计回归
Python数模笔记-Sklearn
Python数模笔记-NetworkX
Python数模笔记-模拟退火算法
线性可分,在二维平面上是指可以用一条直线将两个点集完全分开,在三维空间上是指可以用一个平面将两个点集完全分开,扩展到多维空间上就是可以用一个超平面完全分割两个点集。
对于线性可分问题,不是仅存在一个超平面可以完全分割两个点集,而是存在无穷多个完全可分的超平面。显然。可以找到两个这样的超平面:(1)完全分割两个点集;(1)两者相互平行;(2)两者距离最大(图中的两条虚线),这两个超平面上的样本点称为支持向量。
样本集中的样本被分为两类,SVM 学习算法就是寻找最大间隔超平面(maximum-margin hyperplane),使样本集的两类数据点以尽可能宽的间隔被超平面分开,其特征是:(1)两类样本被分割在超平面的两侧;(2)两侧距离超平面最近的样本点到超平面的距离最大。显然,最大间隔超平面就是上述两个支持向量超平面的均值。
顺便说一句,感知机()就是采用错误分类最小的策略求分离超平面,有无穷多个解;线性可分支持向量机以间隔最大化求解最优分离超平面,解是唯一的。
超平面可以用线性方程来描述:
w T x + b = 0 w^Tx + b = 0 wTx+b=0
寻找最大间隔超平面,可以转化为凸二次规划的最优化问题:
m i n 1 2 ∣ ∣ W ∣ ∣ 2 , s . t . y i ( w T x + b ) ≥ 1 min\;\frac{1}{2}||W||^2,\quad s.t.\; y_i(w^Tx + b) \geq 1 min21∣∣W∣∣2,s.t.yi(wTx+b)≥1
SKlearn 的 SVM 模块有很多方法,就是针对凸二次规划问题的最优化的不同算法,将在后文中介绍。
除了线性可分,不就是线性不可分吗?没错,但世界是复杂的,也是丰富多彩的,不一定是非黑即白的。
首先,一个线性不可分问题,但是可以用非线性曲面分割,是非线性可分的问题,这很好理解。其次,一个线性不可分问题,也可能是近似线性可分的。什么是近似线性可分呢?这就需要先说说硬间隔和软间隔。
间隔(margin)是指样本点到超平面的距离。硬间隔(hard margin)是指对给定的样本数据集中所有的样本都能正确分类。
对于线性不可分的样本集,无法满足线性可分支持向量机的不等式约束,也就是不存在对所有样本都能正确分类的超平面。这种情况可能是因为问题本身是非线性的,也可能问题是线性可分的,但个别样本点标记错误或存在误差而导致样本集线性不可分。
因此,我们可以允许对少量的样本分类错误,容忍特异点的存在,而对于去除特异点的样本集是线性可分的,这时称为软间隔(soft margin)。
在凸二次规划问题中引入损失函数和松弛变量 \xi,目标函数为:
m i n 1 2 w T w + C ∑ i = 1 m ξ i , s . t . y i ( w T x i + b ) ≥ 1 − ξ ξ i ≥ 0 min\;\frac{1}{2}w^Tw+C\sum_{i=1}^m \xi_i,\\ s.t.\; y_i(w^Tx_i + b) \geq 1-\xi \\ \xi_i \geq 0 min21wTw+Ci=1∑mξi,s.t.yi(wTxi+b)≥1−ξξi≥0
目标函数包括两部分,一部分是样本点到间隔的距离,另一部分是错误分类的损失函数,C 是惩罚系数。C 值越大,对错误分类的惩罚项越强,说明要求分类的准确性较高;C 值越小,对错误分类的惩罚项越弱,说明要求间隔比较大,而对分类错误比较宽容。
有些线性不可分的问题并不是个别样本的误差或错误,而是由于问题本身是非线性的,这时采用软间隔方法也不能有效地分割。容易想到,如果不能用平面分割样本集,能不能用曲面分割样本集呢?基于核函数的支持向量机,就是使用映射函数将一类非线性可分问题从原始的特征空间映射到更高维的特征空间,转化为高维特征空间的线性可分问题。
通过映射函数 ϕi(x) 构造的超曲面可以用非线性方程来描述:
w T ∗ z + b = 0 , z = ϕ i ( x ) w^T*z+b=0,z=\phi_i(x) wT∗z+b=0,z=ϕi(x)
映射函数 ϕi(x) 对应的核函数 K(x,z) 是一个对称的半正定矩阵:
K ( x , z ) = ϕ ( x ) ⋅ ϕ ( z ) K(x,z)=\phi(x)\cdot\phi(z) K(x,z)=ϕ(x)⋅ϕ(z)
常用的核函数有:线性核函数(Linear),多项式核函数(polynomial)、高斯核函数(RBF)、拉普拉斯核函数(Laplacian)和 Sigmoid核函数(Sigmoid)。
SKlearn 中的支持向量机模块是 sklearn.svm,包括分类算法和回归算法。本文介绍分类算法,包括 SVC、NuSVC 和 LinearSVC 三个类。
LinearSVC 是线性分类支持向量机,不能使用核函数方法处理非线性分类问题。
LinearSVC 算法与 SVC 算法在使用 ‘linear’ 核函数时的结果基本一致,但 LinearSVC 是基于 liblinear 库实现,计算速度更快。
LinearSVC 有多种惩罚参数和损失函数可供选择,可以应用于大样本集(大于10000)训练。
sklearn.svm.LinearSVC 类是线性分类支持向量机的具体实现,官网介绍详见:https://scikit-learn.org/stable/modules/generated/sklearn.svm.LinearSVC.html#sklearn.svm.LinearSVC
sklearn.svm.LinearSVC()
class sklearn.svm.LinearSVC(penalty=‘l2’, loss=‘squared_hinge’, *, dual=True, tol=0.0001, C=1.0, multi_class=‘ovr’, fit_intercept=True, intercept_scaling=1, class_weight=None, verbose=0, random_state=None, max_iter=1000)
LinearSVC() 类的主要参数:
LinearSVC() 类的主要属性:
LinearSVC() 类的主要方法:
LinearSVC 定义训练样本集的输入格式为 (X,y),X 是 n行(样本数)*m列(特征数)的二维数组,y 是样本分类标签。
# skl_SVM_v1a.py
# Demo of linear SVM by scikit-learn
# v1.0a: 线性可分支持向量机模型(SciKitLearn)
# Copyright 2021 YouCans, XUPT
# Crated:2021-05-15
import numpy as np
import matplotlib.pyplot as plt
from sklearn.svm import SVC, LinearSVC
from sklearn.datasets import make_blobs
X, y = make_blobs(n_samples=40, centers=2, random_state=27) # 产生数据集: 40个样本, 2类
modelSVM = SVC(kernel='linear', C=100) # SVC 建模:使用 SVC类,线性核函数
# modelSVM = LinearSVC(C=100) # SVC 建模:使用 LinearSVC类,运行结果同上
modelSVM.fit(X, y) # 用样本集 X,y 训练 SVM 模型
print("\nSVM model: Y = w0 + w1*x1 + w2*x2") # 分类超平面模型
print('截距: w0={}'.format(modelSVM.intercept_)) # w0: 截距, YouCans
print('系数: w1={}'.format(modelSVM.coef_)) # w1,w2: 系数, XUPT
print('分类准确度:{:.4f}'.format(modelSVM.score(X, y))) # 对训练集的分类准确度
# 绘制分割超平面和样本集分类结果
plt.scatter(X[:,0], X[:,1], c=y, s=30, cmap=plt.cm.Paired) # 散点图,根据 y值设置不同颜色
ax = plt.gca() # 移动坐标轴
xlim = ax.get_xlim() # 获得Axes的 x坐标范围
ylim = ax.get_ylim() # 获得Axes的 y坐标范围
xx = np.linspace(xlim[0], xlim[1], 30) # 创建等差数列,从 start 到 stop,共 num 个
yy = np.linspace(ylim[0], ylim[1], 30) #
YY, XX = np.meshgrid(yy, xx) # 生成网格点坐标矩阵 XUPT
xy = np.vstack([XX.ravel(), YY.ravel()]).T # 将网格矩阵展平后重构为数组
Z = modelSVM.decision_function(xy).reshape(XX.shape)
ax.contour(XX, YY, Z, colors='k', levels=[-1, 0, 1], alpha=0.5,
linestyles=['--', '-', '--']) # 绘制决策边界和分隔
ax.scatter(modelSVM.support_vectors_[:, 0], modelSVM.support_vectors_[:, 1], s=100,
linewidth=1, facecolors='none', edgecolors='k') # 绘制 支持向量
plt.title("Classification by LinearSVM (youcans, XUPT)")
plt.show()
# = 关注 Youcans,分享原创系列 https://blog.csdn.net/youcans =
SVM model: Y = w0 + w1*x1 + w2*x2
截距: w0=[-3.89974328]
系数: w1=[[0.72181271 0.34692337]]
分类准确度:1.0000
modelSVM = SVC(kernel=‘linear’, C=100) # SVC 建模:使用 SVC类,线性核函数
modelSVM = LinearSVC(C=100) # SVC 建模:使用 LinearSVC类,运行结果同上
以上程序分别用 SVC()类、LinearSVC()类建模。使用 SVC() 类并选择 ‘linear’ 线性核函数时,模型训练结果与 LinearSVC() 是一致的。但 SVC()类、LinearSVC()类的参数、属性和方法的定义存在差异,例如 LinearSVC()类没有程序中的 support_vectors_ 属性。
SVC 和 NuSVC 都可以使用核函数方法实现非线性分类。
NuSVC 是非线性分类支持向量机,使用核函数方法来处理非线性分类问题,基于 libsvm 库实现。
SVC 和 NuSVC 都可以使用核函数方法实现非线性分类,但参数设置有所区别。对于多类别分类问题,通过构造多个“one-versus-one”的二值分类器逐次分类。
sklearn.svm.NuSVC 类是线性分类支持向量机的具体实现,官网介绍详见:https://scikit-learn.org/stable/modules/generated/sklearn.svm.NuSVC.html#sklearn.svm.NuSVC
sklearn.svm.NuSVC()
class sklearn.svm.NuSVC(*, nu=0.5, kernel=‘rbf’, degree=3, gamma=‘scale’, coef0=0.0, shrinking=True, probability=False, tol=0.001, cache_size=200, class_weight=None, verbose=False, max_iter=- 1, decision_function_shape=‘ovr’, break_ties=False, random_state=None)
NuSVC() 类的主要参数:
需要注意的是,NuSVC() 类的参数有两类:一类是针对模型训练的通用参数,对所有核函数都适用,例如 nu、tol、max_iter;另一类是针对特定的核函数,只对某种核函数有效,并不适用于其它核函数,例如 degree 只适用于 'poly’核函数,coef0 只适用于’poly’ 和 ’sigmoid‘ 核函数,而且在 'poly’ 和 ’sigmoid‘ 核函数中的含义也不相同。
NuSVC() 类的主要属性:
NuSVC() 类的主要方法:
# skl_SVM_v1b.py
# Demo of nonlinear SVM by scikit-learn
# v1.0b: 线性可分支持向量机模型(SciKitLearn)
# Copyright 2021 YouCans, XUPT
# Crated:2021-05-15
import numpy as np
import matplotlib.pyplot as plt
from sklearn.svm import SVC, NuSVC, LinearSVC
from sklearn.datasets import make_moons
# 数据准备:生成训练数据集,生成等高线网格数据
X, y = make_moons(n_samples=100, noise=0.1, random_state=27) # 生成数据集
x0s = np.linspace(-1.5, 2.5, 100) # 创建等差数列,从 start 到 stop,共 num 个
x1s = np.linspace(-1.0, 1.5, 100) # start, stop 根据 Moon 数据范围选择确定
x0, x1 = np.meshgrid(x0s, x1s) # 生成网格点坐标矩阵
Xtest = np.c_[x0.ravel(), x1.ravel()] # 返回展平的一维数组
# SVC 建模,训练和输出
modelSVM1 = SVC(kernel='poly', degree=3, coef0=0.2) # 'poly' 多项式核函数
modelSVM1.fit(X, y) # 用样本集 X,y 训练支持向量机 1
yPred1 = modelSVM1.predict(Xtest).reshape(x0.shape) # 用模型 1 预测分类结果
# NuSVC 建模,训练和输出
modelSVM2 = NuSVC(kernel='rbf', gamma='scale', nu=0.1) #'rbf' 高斯核函数
modelSVM2.fit(X, y) # 用样本集 X,y 训练支持向量机 2
yPred2 = modelSVM2.predict(Xtest).reshape(x0.shape) # 用模型 2 预测分类结果
fig, ax = plt.subplots(figsize=(8, 6))
ax.contourf(x0, x1, yPred1, cmap=plt.cm.brg, alpha=0.1) # 绘制模型1 分类结果
ax.contourf(x0, x1, yPred2, cmap='PuBuGn_r', alpha=0.1) # 绘制模型2 分类结果
ax.plot(X[:,0][y==0], X[:,1][y==0], "bo") # 按分类绘制数据样本点
ax.plot(X[:,0][y==1], X[:,1][y==1], "r^") # XUPT
ax.grid(True, which='both')
ax.set_title("Classification of moon data by LinearSVM")
plt.show()
# = 关注 Youcans,分享原创系列 https://blog.csdn.net/youcans =
modelSVM1 = SVC(kernel=‘poly’, degree=3, coef0=0.2) # ‘poly’ 多项式核函数
modelSVM2 = NuSVC(kernel=‘rbf’, gamma=‘scale’, nu=0.1) #‘rbf’ 高斯核函数
版权说明:
本文中案例问题和数据来自:Sci-Kit Learn 官网:https://scikit-learn.org/stable/modules/svm.html#svm-classification
本文例程参考了Sci-Kit Learn 官网的例程,但作者重写了这些例程。
本文内容为作者原创,并非转载书籍或网络内容。
YouCans 原创作品
Copyright 2021 YouCans, XUPT
Crated:2021-05-09
欢迎关注 Youcans 原创系列,每周更新数模笔记
Python数模笔记-PuLP库(1)线性规划入门
Python数模笔记-PuLP库(2)线性规划进阶
Python数模笔记-PuLP库(3)线性规划实例
Python数模笔记-StatsModels 统计回归(1)简介
Python数模笔记-StatsModels 统计回归(2)线性回归
Python数模笔记-StatsModels 统计回归(3)模型数据的准备
Python数模笔记-StatsModels 统计回归(4)可视化
Python数模笔记-Sklearn (1)介绍
Python数模笔记-Sklearn (2)聚类分析
Python数模笔记-Sklearn (3)主成分分析
Python数模笔记-Sklearn (4)线性回归
Python数模笔记-Sklearn (5)支持向量机
Python数模笔记-模拟退火算法(1)多变量函数优化
Python数模笔记-模拟退火算法(2)约束条件的处理
Python数模笔记-模拟退火算法(3)整数规划问题
Python数模笔记-模拟退火算法(4)旅行商问题