本文主要用来讲述SVM原理与其在python中的使用,更多应用与实现见其他博客:
机器学习-支持向量机
该图来自于Eren Gogle,由此图可以看出SVM旺盛的生命力。实际上,即使是深度学习非常火热的今天,SVM依然盛行。在一些小样本分类问题上,SVM表现非常好,用深度学习模型可能反而会使问题变得更复杂。
下面将开始介绍SVM算法
支持向量机(SVM)是一类按监督学习方式对数据进行二元分类的广义线性分类器,其决策边界是对学习样本求解的最大边距超平面,可以将问题化为一个求解凸二次规划的问题。与逻辑回归和神经网络相比,支持向量机,在学习复杂的非线性方程时提供了一种更为清晰,更加强大的方式。
具体来说就是在线性可分时,在原空间寻找两类样本的最优分类超平面。在线性不可分时,加入松弛变量并通过使用非线性映射将低维度输入空间的样本映射到高维度空间使其变为线性可分,这样就可以在该特征空间中寻找最优分类超平面。
SVM使用准则:nn 为特征数,mm 为训练样本数。
如果相较于mm而言,nn要大许多,即训练集数据量不够支持我们训练一个复杂的非线性模型,我们选用逻辑回归模型或者不带核函数的支持向量机。
如果nn较小,而且mm大小中等,例如nn在 1-1000 之间,而mm在10-10000之间,使用高斯核函数的支持向量机。
如果nn较小,而mm较大,例如nn在1-1000之间,而大于50000,则使用支持向量机会非常慢,解决方案是创造、增加更多的特征,然后使用逻辑回归或不带核函数的支持向量机。
支持向量机算法可以解决小样本情况下的机器学习问题,简化了通常的分类和回归等问题。
由于采用核函数方法克服了维数灾难和非线性可分的问题,所以向高维空间映射时没有增加计算的复杂性。换句话说,由于支持向量计算法的最终决策函数只由少数的支持向量所确定,所以计算的复杂性取决于支持向量的数目,而不是样本空间的维数。
支持向量机算法利用松弛变量可以允许一些点到分类平面的距离不满足原先要求,从而避免这些点对模型学习的影响。
支持向量机算法对大规模训练样本难以实施。这是因为支持向量机算法借助二次规划求解支持向量,这其中会涉及m阶矩阵的计算,所以矩阵阶数很大时将耗费大量的机器内存和运算时间。
经典的支持向量机算法只给出了二分类的算法,而在数据挖掘的实际应用中,一般要解决多分类问题,但支持向量机对于多分类问题解决效果并不理想。
SVM算法效果与核函数的选择关系很大,往往需要尝试多种核函数,即使选择了效果比较好的高斯核函数,也要调参选择恰当的参数。另一方面就是现在常用的SVM理论都是使用固定惩罚系数C,但正负样本的两种错误造成的损失是不一样的。
由上文可知道SVM(支持向量机)
是通过寻找分类超平面进而最大化类别间隔实现分类;
先来介绍一下SVM算法的分类类型,进而介绍SVM算法中提及的最大间隔,分类超平面,及其实现原理。
(1)线性可分样本集
线性可分样本集:只要我们可以使用一条直线将样本集完全分开
(2)非线性可分样本集
非线性可分样本集:没有办法直接画一条直线,只能用曲线等模式来分开的样本集
下面整体的思路就是由线性可分样本集推到非线性可分的问题
基于线性可分样本集,我们发现只要存在一条直线(一个超平面)可以将类1与类2进行分开。那也就说明实际上有无数条直线(超平面)可以将类1与类2分开。如下图:
那么问题来了:1 选择哪一条直线(超平面)最好呢?
从图中可以得出,在样本统计中,如果我们是允许误差存在的。那么2号线(超平面)的容错度可能更大一点,就是说线2更加robust,这个超平面离直线两边的数据的间隔最大,对训练集的数据的局限性或噪声有最大的“容忍”能力。
接着,问题又来了,怎么取到2号线(2号超平面)的呢?
解答:随机预测出某条线,然后将这条线进行平行移动,直到它交于某一个圈或某几个圈为止;同理,又进行平移,直到交于某几个星为止,这样我们找到两个相交的线,两条相交线的间隔就是最大分类间隔,间隔的中点位置就是2号线位置。如下图:
显然,d越大,也就说明红色实线距离样本点越远,此时容错率也就更高。所以我们的目标为:找分类间隔d最大的线,也就是寻找分类间隔最大的超平面。
训练集线性可分的数学定义
如图,及如上面的图,1条线把图分为两类,在平面上方>0,在平面下方<0
所以,同理可得对于超平面来说线性可分的定义如下:
回顾一下点到平面的距离公式:
平面方程为Ax+By+Cz+D=0;点P的坐标(x0,y0,z0);d为点P到平面的距离公式如下:
关于非线性可分思路的详细推导可以学习:https://blog.csdn.net/u012679707/article/details/80501358
软间隔:假如数据是完全的线性可分的,那么学习到的模型可以称为硬间隔支持向量机。换个说法,硬间隔指的就是完全分类准确,不能存在分类错误的情况。软间隔,就是允许一定量的样本分类错误。
当容忍一些样本分类错误的线性可分模型,我们可以称为近似线性可分。如下图所示:
那为了使样本分类不那么严格,我们引入了松弛因子。构建新的目标函数:
C为常数项,C的右边部分为松弛因子。当常数项越大,松弛因子越小,说明软间隔越小,相反,则软间隔越大。
同时,新的目标函数就是我们讲的“软间隔支持向量机”
对于非线性样本集,不论多么高级的线性分类器,都无法处理。
这时,我们需要引入一个新的概念:核函数
。它可以将样本从原始空间映射到一个更高维的特质空间中,使得样本在新的空间中线性可分。这样我们就可以使用原来的推导来进行计算,只是所有的推导是在新的空间,而不是在原来的空间中进行。
所以在非线性 SVM 中,核函数的选择就是影响 SVM 最大的变量。最常用的核函数有线性核、多项式核、高斯核、拉普拉斯核、sigmoid 核,或者是这些核函数的组合。这些函数的区别在于映射方式的不同。通过这些核函数,我们就可以把样本空间投射到新的高维空间中。
Scikit-learn(sklearn)是一个开源项目,可以免费使用和分发,任何人都可以轻松获取其源代码来查看其背后的原理。
scikit-learn是一个非常流行的工具,也是最有名的 Python机器学习库。它广泛应用于工业界和学术界,网上有大量的教程和代码片段。而SVM也可以在scikit-learn库中选择使用。
http:// scikit-learn.org/stable/documentation
! sudo pip install numpy
! sudo apt-get install python-matplotlib ipython ipython-notebook
! sudo apt-get install python-pandas python-sympy python-nose
! sudo pip install scipy
! sudo pip install -U scikit-learn
# Create SVM classification object
sklearn.svm.SVC(C=1.0, kernel='rbf', degree=3, gamma='auto', coef0=0.0, shrinking=True, probability=False, tol=0.001, cache_size=200, class_weight=None, verbose=False, max_iter=-1, decision_function_shape=None,random_state=None)
参数解析:
- C:惩罚参数。C越大,相当于惩罚松弛变量,希望松弛变量接近0,即对误分类的惩罚增大,趋向于对训练集全分对的情况,这样对训练集测试时准确率很高,但泛化能力弱。C值小,对误分类的惩罚减小,允许容错,将他们当成噪声点,泛化能力较强。
- kernel:核函数,默认是rbf,可以是‘linear’, ‘poly’, ‘rbf’, ‘sigmoid’, ‘precomputed’
- degree:多项式poly函数的维度,默认是3,选择其他核函数时会被忽略。
- gamma:‘rbf’,‘poly’ 和‘sigmoid’的核函数参数。默认是’auto’,则会选择1/n_features
- coef0:核函数的常数项。对于‘poly’和 ‘sigmoid’有用。
- probability:是否采用概率估计。默认为False,布尔类型可选。决定是否启用概率估计。需要在训练fit()模型时加上这个参数,之后才能用相关的方法:predict_proba和predict_log_proba
- shrinking:是否采用shrinking heuristic方法(启发式收缩),默认为true
- tol:停止训练的误差值大小,默认为1e-3
- cache_size:核函数cache缓存大小,默认为200
- class_weigh: t类别的权重,字典形式传递。设置第几类的参数C为weight*C(C-SVC中的C)
- verbose:允许冗余输出
- max_iter:最大迭代次数。-1为无限制。
- decision_function_shape:‘ovo’, ‘ovr’ or None, default=None3
- random_state:数据洗牌时的种子值,int值。主要调节的参数有:C、kernel、degree、gamma、coef0。
采用鸢尾花数据集,这个数据集包含了150个鸢尾花样本,对应3种鸢尾花,各50个样本,以及它们各自对应的4种关于花外形的数据 ,适用于分类任务。
import numpy as np
import matplotlib.pyplot as plt
from sklearn import svm, datasets
# 引用 iris 数据集
iris = datasets.load_iris()
X = iris.data[:, :2] # 选取前两列作为X参数
y = iris.target # 采集标签作为y参数
C = 1.0 # SVM regularization parameter
# 将所得参数进行模型训练
svc = svm.SVC(kernel='linear', C=1, gamma='auto').fit(X, y)
# 建图
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
h = (x_max / x_min)/100
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
np.arange(y_min, y_max, h))
plt.subplot(1, 1, 1) # 将显示界面分割成1*1 图形标号为1的网格
Z = svc.predict(np.c_[xx.ravel(), yy.ravel()]) # np.c按行连接两个矩阵,但变量为两个数组,按列连接
Z = Z.reshape(xx.shape)# 重新构造行列
plt.contourf(xx, yy, Z, cmap=plt.cm.Paired, alpha=0.8)# 绘制等高线
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Paired) # 生成一个scatter散点图。
plt.xlabel('Sepal length') # x轴标签
plt.ylabel('Sepal width') # y轴标签
plt.xlim(xx.min(), xx.max()) # 设置x轴的数值显示范围
plt.title('SVC with linear kernel') # 设置显示图像的名称
plt.savefig('./test1.png') #存储图像
plt.show() # 显示
实现结果如下:
支持向量机是一种分类器。之所以称为”机“是因为它会产生一个二值决策的结果,即它是一种决策”机“。支持向量机是一个二分类器。当其解决多分类问题时需要用额外的方法对其进行扩展。而且SVM的效果也对优化参数和所用核函数中的参数敏感。
参考文章:
https://blog.csdn.net/qq_42192693/article/details/121164645
https://blog.csdn.net/u012679707/article/details/80501358
https://blog.csdn.net/Claire_chen_jia/article/details/110916001