企业网站制作步骤,网页制作与设计,搬瓦工如何搭建做网站,wordpress 自动上传插件小伙伴们大家好~o(#xffe3;▽#xffe3;)ブ#xff0c;我是菜菜#xff0c;这里是我的sklearn课堂第7期#xff0c;今天分享的内容是支持向量机#xff08;上#xff09;#xff0c;下周还有下篇哦~我的开发环境是Jupyter lab#xff0c;所用的库和版本大家参考▽)ブ我是菜菜这里是我的sklearn课堂第7期今天分享的内容是支持向量机上下周还有下篇哦~我的开发环境是Jupyter lab所用的库和版本大家参考Python 3.7.1你的版本至少要3.4以上Scikit-learn 0.20.1 你的版本至少要0.20Numpy 1.15.4, Pandas 0.23.4, Matplotlib 3.0.2, SciPy 1.1.0本文主要内容1 概述1.1 支持向量机分类器是如何工作的1.2 支持向量机原理的三层理解1.3 sklearn中的支持向量机2 sklearn.svm.SVC2.1 线性SVM用于分类2.1.1 线性SVM的损失函数2.1.3 线性SVM决策过程的可视化2.3 非线性SVM与核函数2.3.1 重要参数kernel degree gamma1 概述支持向量机SVM也称为支持向量网络是机器学习中获得关注最多的算法没有之一。它源于统计学习理论是我们除了集成算法之外接触的第一个强学习器。它有多强呢从算法的功能来看SVM几乎囊括了我们前六周讲解的所有算法的功能从分类效力来讲SVM在无论线性还是非线性分类中都是明星般的存在从实际应用来看SVM在各种实际问题中都表现非常优秀。它在手写识别数字和人脸识别中应用广泛在文本和超文本的分类中举足轻重因为SVM可以大量减少标准归纳standard inductive和转换设置transductive settings中对标记训练实例的需求。同时SVM也被用来执行图像的分类并用于图像分割系统。实验结果表明在仅仅三到四轮相关反馈之后SVM就能实现比传统的查询细化方案query refinement schemes高出一大截的搜索精度。除此之外生物学和许多其他科学都是SVM的青睐者SVM现在已经广泛被用于蛋白质分类现在化合物分类的业界平均水平可以达到90%以上的准确率。在生物科学的尖端研究中人们还使用支持向量机来识别用于模型预测的各种特征以找出各种基因表现结果的影响因素。从学术的角度来看SVM是最接近深度学习的机器学习算法。线性SVM可以看成是神经网络的单个神经元虽然损失函数与神经网络不同非线性的SVM则与两层的神经网络相当非线性的SVM中如果添加多个核函数则可以模仿多层的神经网络。而从数学的角度来看SVM的数学原理是公认的对初学者来说难于上青天的水平对于没有数学基础和数学逻辑熏陶的人来说探究SVM的数学原理本身宛如在知识的荒原上跋涉。当然了没有算法是完美的比SVM强大的算法在集成学习和深度学习中还有很多很多。但不可否认它是我们目前为止接触到的最强大的算法。接下来的两周我们将一起来探索SVM的神秘世界。1.1 支持向量机分类器是如何工作的支持向量机所作的事情其实非常容易理解。先来看看下面这一组数据的分布这是一组两种标签的数据两种标签分别由圆和方块代表。支持向量机的分类方法是在这组分布中找出一个超平面作为决策边界使模型在数据上的分类误差尽量接近于小尤其是在未知数据集上的分类误差泛化误差尽量小。关键概念超平面在几何中超平面是一个空间的子空间它是维度比所在空间小一维的空间。 如果数据空间本身是三维的则其超平面是二维平面而如果数据空间本身是二维的则其超平面是一维的直线。在二分类问题中如果一个超平面能够将数据划分为两个集合其中每个集合中包含单独的一个类别我们就说这个超平面是数据的“决策边界”。决策边界一侧的所有点在分类为属于一个类而另一侧的所有点分类属于另一个类。如果我们能够找出决策边界分类问题就可以变成探讨每个样本对于决策边界而言的相对位置。比如上面的数据分布我们很容易就可以在方块和圆的中间画出一条线并让所有落在直线左边的样本被分类为方块在直线右边的样本被分类为圆。如果把数据当作我们的训练集只要直线的一边只有一种类型的数据就没有分类错误我们的训练误差就会为0。但是对于一个数据集来说让训练误差为0的决策边界可以有无数条。但在此基础上我们无法保证这条决策边界在未知数据集测试集上的表现也会优秀。对于现有的数据集来说我们有 和 两条可能的决策边界。我们可以把决策边界 向两边平移直到碰到离这条决策边界最近的方块和圆圈后停下形成两个新的超平面分别是 和 并且我们将原始的决策边界移动到 和 的中间确保 到 和 的距离相等。在 和 中间的距离叫做 这条决策边界的边际(margin)通常记作 。对 也执行同样的操作然后我们来对比一下两个决策边界。现在两条决策边界右边的数据都被判断为圆左边的数据都被判断为方块两条决策边界在现在的数据集上的训练误差都是0没有一个样本被分错。我们引入和原本的数据集相同分布的测试样本红色所示平面中的样本变多了此时我们可以发现对于 而言依然没有一个样本被分错这条决策边界上的泛化误差也是0。但是对于 而言却有三个方块被误人类成了圆二有两个圆被误分类成了方块这条决策边界上的泛化误差就远远大于 了。这个例子表现出拥有更大边际的决策边界在分类中的泛化误差更小这一点可以由结构风险最小化定律来证明SRM。如果边际很小则任何轻微扰动都会对决策边界的分类产生很大的影响。边际很小的情况是一种模型在训练集上表现很好却在测试集上表现糟糕的情况所以会“过拟合”。所以我们在找寻决策边界的时候希望边际越大越好。支持向量机就是通过找出边际最大的决策边界来对数据进行分类的分类器。也因此支持向量分类器又叫做最大边际分类器。这个过程在二维平面中看起来十分简单但将上述过程使用数学表达出来就不是一件简单的事情了。1.2 支持向量机原理的三层理解目标是找出边际最大的决策边界听起来是一个十分熟悉的表达这是一个最优化问题而最优化问题往往和损失函数联系在一起。和逻辑回归中的过程一样SVM也是通过最小化损失函数来求解一个用于后续模型使用的重要信息决策边界。1.3 sklearn中的支持向量机注意除了特别表明是线性的两个类LinearSVC和LinearSVR之外其他的所有类都是同时支持线性和非线性的。NuSVC和NuSVC可以手动调节支持向量的数目其他参数都与最常用的SVC和SVR一致。注意OneClassSVM是无监督的类。除了本身所带的类之外sklearn还提供了直接调用libsvm库的几个函数。Libsvm是台湾大学林智仁(Lin Chih-Jen)教授等人开发设计的一个简单、易于使用和快速有效的英文的SVM库它提供了大量SVM的底层计算和参数选择也是sklearn的众多类背后所调用的库。目前LIBSVM拥有C、Java、Matlab、Python、R等数十种语言版本每种语言版本都可以在libsvm的官网上进行下载https://www.csie.ntu.edu.tw/~cjlin/libsvm/2 sklearn.svm.SVCclass sklearn.svm.SVC(C1.0, kernel’rbf’, degree3, gamma’auto_deprecated’, coef00.0, shrinkingTrue, probabilityFalse, tol0.001, cache_size200, class_weightNone, verboseFalse, max_iter-1, decision_function_shape’ovr’, random_stateNone)2.1 线性SVM用于分类2.1.1 线性SVM的损失函数要理解SVM的损失函数我们先来定义决策边界。假设现在数据中总计有N个训练样本每个训练样本 可以被表示为 其中 是 这样的一个特征向量每个样本总共含有n个特征。二分类标签 的取值是{-1, 1}。如果n等于2则有 分别由我们的特征向量和标签组成。此时我们可以在二维平面上以 为横坐标 为纵坐标y为颜色来可视化我们所有的N个样本我们让所有紫色点的标签为1红色点的标签为-1。我们要在这个数据集上寻找一个决策边界在二维平面上决策边界超平面就是一条直线。二维平面上的任意一条线可以被表示为 我们将此表达式变换一下 其中[a, -1]就是我们的参数向量 就是我们的特征向量 是我们的截距。注意这个表达式长得非常像我们线性回归的公式 线性回归中等号的一边是标签回归过后会拟合出一个标签而决策边界的表达式中却没有标签的存在全部是由参数特征和截距组成的一个式子等号的一边是0。在一组数据下给定固定的w和b这个式子就可以是一条固定直线在w和b不确定的状况下这个表达式 就可以代表平面上的任意一条直线。如果在和固定时给定一个唯一的的取值这个表达式就可以表示一个固定的点。在SVM中我们就使用这个表达式来表示我们的决策边界。我们的目标是求解能够让边际最大化的决策边界所以我们要求解参数向量和截距。如果在决策边界上任意取两个点 并带入决策边界的表达式则有 将两式相减可以得到 一个列向量的转至乘以另一个列向量可以获得两个向量的点积(dot product)表示为 。两个向量的点击为0表示两个向量的方向式互相垂直的。 与是一条直线上的两个点相减后的得到的向量方向是由 指向 所以 的方向是平行于他们所在的直线——我们的决策边界的。而 与 相互垂直所以参数向量 的方向必然是垂直于我们的决策边界。此时我们有了我们的决策边界。任意一个紫色的点就可以被表示为 由于紫色的点所代表的标签y是1所以我们规定p0。同样的对于任意一个红色的点而言我们可以将它表示为 由于红色点所表示的标签y是-1所以我们规定r0。由此如果我们有新的测试数据 则 的标签就可以根据以下式子来判定 核心误区p和r的符号注意在这里p和r的符号是我们人为规定的。在一些博客或教材中会认为p和r的符号是由原本的决策边界上下移动得到。这是一种误解。如果k和k是由原本的决策边界平移得到的话紫色的点在决策边界上方 应该要向上平移直线向上平移的话是增加截距也就是说应该写作 那k在等号的右边怎么可能是一个大于0的数呢同理向下平移的话应该是截距减小所以k也不可能是一个小于0的数。所以p和r的符号不完全是平移的结果。有人说“直线以上的点带入直线为正直线以下的点带入直线为负”是直线的性质这又是另一种误解。假设我们有穿过圆点的直线yx我们取点(x,y) (0,1)这个在直线上的点为例如果直线的表达式写作y - x 0则点(0,1)带入后为正1如果我们将直线的表达式写作x-y 0则带入(0,1)后结果为-1。所以一个点在直线的上方究竟会返回什么样的符号是跟直线的表达式的写法有关的不是直线上的点都为正直线下的点都为负。可能细心的小伙伴会发现我们规定了k和k的符号与标签的符号一致所以有人会说k和k的符号由所代表的点的标签的符号决定。这不是完全错误的但这种说法无法解释为什么我们就可以这样规定。并且标签可以不是{-1,1}可以是{0, 1}可以是{1,2}两个标签之间并不需要是彼此的负数标签的取值其实也是我们规定的。那k和k的符号到底是依据什么来定的呢数学中很多过程都是可以取巧的来看以下过程。记得我们的决策边界如果写成矩阵可以表示为紫色点 毫无疑问是在决策边界的上方的此时我将决策边界向上移动形成一条过 的直线。根据我们平移的规则直线向上平移是在截距后加一个正数则等号的右边是一个负数假设这个数等于-3则有 另等式两边同时乘以可以注意到我们的参数向量由[a,-1]变成了[-a,1] 变成了 但参数向量依旧可以被表示成 只是它是原来的负数了截距依旧可以被表示成 只是如果它原来是正它现在就是负数了如果它原本就是负数那它现在就是正数了。在这个调整中我们通过将向上平移时产生的负号放入了参数向量和截距当中这不影响我们求解只不过我们求解出的参数向量和截距的符号变化了但决策边界本身没有变化。所以我们依然可以使用原来的字母来表示这些更新后的参数向量和截距。通过这种方法我们让 中的k大于0。我们让k大于0的目的是为了它的符号能够与我们的标签的符号一致都是为了后续计算和推导的简便。有了这个理解剩下的推导就简单多了。我们之前说过决策边界的两边要有两个超平面这两各超平面在二维空间中就是两条平行线而他们之间的距离就是我们的边际。这而决策边界位于这两条线的中间所以这两条平行线必然是对称的。我们另这两条平行线被表示为两个表达式同时除以k则可以得到这就是我们平行于决策边界的两条线的表达式。此时我们可以让这两条线分别过两类数据中距离我们的决策边界最近的点这些点就被称为“支持向量”而决策边界永远在这两条线的中间所以可以被调整。我们另紫色类的点为 红色类的点为 则我们可以得到两个式子相减则有如下图所示 可表示为两点之间的连线而我们的边际d是平行于 w 的所以我们现在相当于是得到了三角型中的斜边并且知道一条直角边的方向。在线性代数中向量有这样的性质向量a除以向量b的模长||b||可以得到向量a在向量b的方向上的投影的长度。所以我们另上述式子两边同时除以||w||则可以得到还记得我们想求什么吗最大边界所对应的决策边界那问题就简单了要最大化d就求解的w最小值。极值问题可以相互转化我们可以把求解w的最小值转化为求解以下函数的最小值之所以要在模长上加上平方是因为模长的本质是一个距离所以它是一个带根号的存在我们对它取平方是为了消除根号其实模长的本质是向量w的l2范式还记得l2范式公式如何写的小伙伴必定豁然开朗。我们的两条虚线表示的超平面是数据边缘所在的点。所以对于任意样本 我们可以把决策函数写作整理一下我们可以把两个式子整合成于是我们就得到了我们SVM的损失函数到这里我们就完成了对SVM第一层理解的第一部分线性SVM做二分类的损失函数。我们最小化这个损失函数来求解w的值。【完整版】2.1.2 用拉格朗日对偶函数求解线性SVM2.1.3 线性SVM决策过程的可视化我们可以使用sklearn中的式子来为可视化我们的决策边界和决策边界平行的两个超平面。导入需要的模块from sklearn.datasets import make_blobs
from sklearn.svm import SVC
import matplotlib.pyplot as plt
import numpy as np实例化数据集可视化数据集X,y make_blobs(n_samples50, centers2, random_state0,cluster_std0.6)
plt.scatter(X[:,0],X[:,1],cy,s50,cmaprainbow)
plt.xticks([])
plt.yticks([])
plt.show()定义画决策边界的函数#首先要有散点图
plt.scatter(X[:,0],X[:,1],cy,s50,cmaprainbow)
ax plt.gca() #获取当前的子图如果不存在则创建新的子图
xlim ax.get_xlim()
ylim ax.get_ylim() #默认创建(0.0, 1.0)范围内的横纵坐标
#要画决策边界必须要有网格
axisx np.linspace(xlim[0],xlim[1],30)
axisy np.linspace(ylim[0],ylim[1],30)
axisy,axisx np.meshgrid(axisy,axisx)
#将特征向量转换为特征矩阵的函数
#核心是将两个特征向量广播以便获取y.shape * x.shape这么多个坐标点的横坐标和纵坐标
xy np.vstack([axisx.ravel(), axisy.ravel()]).T
#获取y.shape * x.shape这么多个坐标点
#其中ravel()是降维函数vstack能够将多个结构一致的一维数组按行堆叠起来
#xy就是已经形成的网络它是遍布在整个画布上的密集的点
a np.array([1,2,3])
b np.array([7,8])
#两两组合会得到多少个坐标
#答案是6个分别是 (1,7),(2,7),(3,7),(1,8),(2,8),(3,8)
v1,v2 np.meshgrid(a,b)
v1
v2
v np.vstack([v1.ravel(), v2.ravel()]).T
#建模通过fit计算出对应的决策边界
clf SVC(kernel linear).fit(X,y)
P clf.decision_function(xy).reshape(axisx.shape)
#重要接口decision_function返回每个输入的样本所对应的到决策边界的距离
#然后再将这个距离转换为axisx的结构
#画决策边界和平行于决策边界的超平面
ax.contour(axisx,axisy,P,colorsk,levels[-1,0,1],alpha0.5,linestyles[--,-,--])
ax.set_xlim(xlim)
ax.set_ylim(ylim)#将上述过程包装成函数
def plot_svc_decision_function(model,axNone):if ax is None:ax plt.gca()xlim ax.get_xlim()ylim ax.get_ylim()x np.linspace(xlim[0],xlim[1],30)y np.linspace(ylim[0],ylim[1],30)Y,X np.meshgrid(y,x) xy np.vstack([X.ravel(), Y.ravel()]).TP model.decision_function(xy).reshape(X.shape)ax.contour(X, Y, P,colorsk,levels[-1,0,1],alpha0.5,linestyles[--,-,--]) ax.set_xlim(xlim)ax.set_ylim(ylim)
#则可以写作
clf SVC(kernel linear).fit(X,y)
plt.scatter(X[:,0],X[:,1],cy,s50,cmaprainbow)
plot_svc_decision_function(clf)我们目前所有的例子都是基于数据是线性可分的状况来说明的。如果数据是线性不可分呢比如说from sklearn.datasets import make_circles
X,y make_circles(100, factor0.1, noise.1)
X.shape
y.shape
plt.scatter(X[:,0],X[:,1],cy,s50,cmaprainbow)
plt.show()试试看用我们已经定义的函数来划分这个数据的决策边界clf SVC(kernel linear).fit(X,y)
plt.scatter(X[:,0],X[:,1],cy,s50,cmaprainbow)
plot_svc_decision_function(clf)明显现在线性SVM已经不适合于我们的状况了我们无法找出一条直线来划分我们的数据集让直线的两边分别是两种类别。这个时候如果我们能够在原本的X和y的基础上添加一个维度r变成三维我们可视化这个数据来看看添加维度让我们的数据如何变化。#定义一个由x计算出来的新维度r
r np.exp(-(X**2).sum(1))
rlim np.linspace(min(r),max(r),0.2)
from mpl_toolkits import mplot3d
#定义一个绘制三维图像的函数
#elev表示上下旋转的角度
#azim表示平行旋转的角度
def plot_3D(elev30,azim30,XX,yy):ax plt.subplot(projection3d)ax.scatter3D(X[:,0],X[:,1],r,cy,s50,cmaprainbow)ax.view_init(elevelev,azimazim)ax.set_xlabel(x)ax.set_ylabel(y)ax.set_zlabel(r)plt.show()plot_3D()#如果放到jupyter notebook中运行
from sklearn.svm import SVC
import matplotlib.pyplot as plt
import numpy as np
from sklearn.datasets import make_circles
X,y make_circles(100, factor0.1, noise.1)
plt.scatter(X[:,0],X[:,1],cy,s50,cmaprainbow)
def plot_svc_decision_function(model,axNone):if ax is None:ax plt.gca()xlim ax.get_xlim()ylim ax.get_ylim()x np.linspace(xlim[0],xlim[1],30)y np.linspace(ylim[0],ylim[1],30)Y,X np.meshgrid(y,x) xy np.vstack([X.ravel(), Y.ravel()]).TP model.decision_function(xy).reshape(X.shape)ax.contour(X, Y, P,colorsk,levels[-1,0,1],alpha0.5,linestyles[--,-,--])ax.set_xlim(xlim)ax.set_ylim(ylim)
clf SVC(kernel linear).fit(X,y)
plt.scatter(X[:,0],X[:,1],cy,s50,cmaprainbow)
plot_svc_decision_function(clf)
r np.exp(-(X**2).sum(1))
rlim np.linspace(min(r),max(r),0.2)
from mpl_toolkits import mplot3d
def plot_3D(elev30,azim30,XX,yy):ax plt.subplot(projection3d)ax.scatter3D(X[:,0],X[:,1],r,cy,s50,cmaprainbow)ax.view_init(elevelev,azimazim)ax.set_xlabel(x)ax.set_ylabel(y)ax.set_zlabel(r)plt.show()
from ipywidgets import interact,fixed
interact(plot_3D,elev[0,30],azip(-180,180),Xfixed(X),yfixed(y))
plt.show()此时我们的数据在三维空间中我们的超平面就是一个二维平面。明显我们可以用一个平面将两类数据隔开这个平面就是我们的超平面。我们刚才做的计算r并将r作为数据的第三维度来讲数据升维的过程被称为“核变换”即是将数据投影到高维空间中以寻找能够将数据完美分割的超平面而在高维空间中计算来找出超平面的函数就叫做核函数。在SVM中这个功能由参数“kernel”控制。之前我们一直使用这个参数但是没有给大家解释我们使用的是“linear线性核函数只能用于线性的情况。刚才我们使用的计算r的方法其实是高斯径向基核函数在参数”kernel“中输入”rbf“就可以使用。我们来看看模型找出的决策边界时什么样clf SVC(kernel rbf).fit(X,y)
plt.scatter(X[:,0],X[:,1],cy,s50,cmaprainbow)
plot_svc_decision_function(clf)核函数是我们处理非线性问题的关键。2.3 非线性SVM与核函数2.3.1 重要参数kernel degree gamma线性核多项式核SigmoidHyperbolic Tangent核函数高斯径向基rbf函数直观地伽玛参数定义了单个训练样例的影响达到了多远低值意味着“远”高值意味着“接近”。 伽马参数可以被视为由模型选择的样本作为支持向量的影响半径的倒数。 C参数将训练样例的错误分类与决策表面的简单性进行交换。 低C使得决策表面平滑而高C旨在通过给予模型自由选择更多样本作为支持向量来正确地对所有训练示例进行分类。从技术上讲伽玛参数是RBF核的标准偏差高斯函数的倒数其用作两点之间的相似性度量。 直观地小的伽马值定义具有大方差的高斯函数。 在这种情况下即使彼此相距很远也可以认为两个点相似。 另一方面大的伽马值意味着定义具有小方差的高斯函数并且在这种情况下两个点被认为是相似的只要它们彼此接近。 关于调整参数。 我认为您的方法没有任何问题。 我还使用网格搜索来查找Cgamma和epsilon值。当伽玛非常小时模型太受约束无法捕捉数据的复杂性或“形状”。 任何选定支持向量的影响区域将包括整个训练集。 得到的模型的行为类似于线性模型其中包含一组超平面这些超平面将任意一对两类的高密度中心分开。同步视频在这里哦【机器学习】菜菜的sklearn课堂【全85集】Python进阶_哔哩哔哩 (゜-゜)つロ 干杯~-bilibiliwww.bilibili.com完整版目录