实现机器学习的循序渐进指南V——支持向量机
目录
介绍
SVM模型
优化问题
优化算法
分类
结论与分析
可访问 实现机器学习的循序渐进指南系列汇总,获取本系列完成文章列表。
介绍
支持向量机(SVM)是一种基于特征空间最大边距的分类器。SVM的学习策略是使边际最大,可以转化为凸二次规划问题。在学习SVM算法之前,我先介绍一些术语。
功能边距定义为:对于给定的训练集T和超平面(w,b),超平面(w,b)和样本(xi, yi)之间的功能边距为:
超平面(w,b)和训练集T之间的功能边距是的最小值
功能边距表示分类结果的置信水平。如果超参数(w,b) 按比例变化,例如,(w,b)变为(2w,2b)。虽然超平面没有改变,但功能边距消耗增加了一倍。因此,我们在w上应用一些禁令来定义超平面,例如规范化||w|| = 1。然后,边界称为几何边距:对于给定的训练集T和超平面(w,b),超平面(w,b) 和样本(xi, yi)之间的功能边距为:
类似地,超平面(w,b) 和训练集T之间的几何边距是的最小值
现在,我们可以得出功能边距与几何边距之间的关系:
SVM模型
SVM模型由优化问题,优化算法和分类组成。
优化问题
当数据集可线性分离时,支持向量是最接近超平面的样本,如下所示。
对样品H1和H2是之间的支持向量。在H1和H2之间的距离被称为硬边距。然后,SVM的优化问题是:
当数据集不是线性可分时,训练集中的一些样本不满足函数余量大于或等于1的条件。为了解决这个问题,我们为每个样本(xi, yi)添加一个松弛变量。然后,约束是:
同时,为每个松弛变量添加成本。目标函数是:
其中C是惩罚系数。当C规模很大时,对错误分类的惩罚将会增加,然而对错误分类的惩罚将会减少。然后,SVM的优化问题是:
支撑向量位于边距的边界上或边界和超平面之间,如下所示。在这种情况下,边距为软边距。
当数据集不是线性可分的时,它需要应用内核技巧将数据从原始空间转换为特征空间。内核技巧的函数叫做内核函数,定义如下:
其中是从输入空间到特征空间的映射,即
内核技巧的代码如下所示:
def kernelTransformation(self, data, sample, kernel):sample_num, feature_dim = np.shape(data)K = np.zeros([sample_num])if kernel == "linear": # linear functionK = np.dot(data, sample.T)elif kernel == "poly": # polynomial functionK = (np.dot(data, sample.T) + self.c) ** self.nelif kernel == "sigmoid": # sigmoid functionK = np.tanh(self.g * np.dot(data, sample.T) + self.c)elif kernel == "rbf": # Gaussian functionfor i in range(sample_num):delta = data[i, :] - sampleK[i] = np.dot(delta, delta.T)K = np.exp(-self.g * K)else:raise NameError('Unrecognized kernel function')return K
应用内核技巧后,SVM的优化问题是:
其中是拉格朗日因子。
优化算法
用传统的凸二次规划算法求解SVM优化问题是可行的。但是,当训练集很大时,算法将花费很长时间。为了解决这个问题,Platt提出了一种称为顺序最小优化(SMO)的有效算法。
SMO是一种启发式算法。当所有变量都遵循KKT条件时,优化问题就解决了。否则,选择两个变量并修复其他变量,并用两个变量构造凸二次规划问题。问题有两个变量:一个选择违反KKT条件的alpha,另一个选择由约束决定。表示,是变量,修复。因此,有如下方法计算:
如果确定,则相应地确定。在SMO的每次迭代中,更新两个变量直到问题解决。然后,SVM的优化问题是:
当只有两个变量时,它是一个简单的二次规划问题,如下所示:
因为约束是:
当,
当,因为,。
优化值如下:
其中L和H是对角线的下限和上限,其计算公式为:
未切割的优化值如下:
其中E 1和E 2是预测值g(x)和实际值之间的差值。g(x)定义为:
到目前为止,我们为获得可行的解决办法:
SMO中有两个循环,即外循环和内循环。
在外部循环中,选择违反KKT条件的alpha,即
首先,按照搜索样本。如果所有样本都遵循该条件,则搜索整个数据集。
在内部循环,先搜索,这使得最大。如果所选择的值没有减少,请首先在边距边界上搜索样本。如果选择的值减少,请停止搜索。否则,搜索整个数据集。如果我们在搜索整个数据集后找到可行的,我们将选择一个新的。
在每次迭代中,我们通过如下算式更新b:
为方便起见,我们必须存储的值,其计算方法如下:
搜索和更新代码如下所示:
def innerLoop(self, i):Ei = self.calculateErrors(i)if self.checkKKT(i):j, Ej = self.selectAplha2(i, Ei) # select alpha2 according to alpha1# copy alpha1 and alpha2old_alpha1 = self.alphas[i]old_alpha2 = self.alphas[j]# determine the range of alpha2 L and H in page of 126# if y1 != y2 L = max(0, old_alpha2 - old_alpha1), H = min(C, C + old_alpha2 - old_alpha1)# if y1 == y2 L = max(0, old_alpha2 + old_alpha1 - C), H = min(C, old_alpha2 + old_alpha1)if self.train_label[i] != self.train_label[j]:L = max(0, old_alpha2 - old_alpha1)H = min(self.C, self.C + old_alpha2 - old_alpha1)else:L = max(0, old_alpha2 + old_alpha1 - self.C)H = min(self.C, old_alpha2 + old_alpha2)if L == H:# print("L == H")return 0# calculate eta in page of 127 Eq.(7.107)# eta = K11 + K22 - 2K12K11 = self.K[i, i]K12 = self.K[i, j]K21 = self.K[j, i]K22 = self.K[j, j]eta = K11 + K22 - 2 * K12if eta <= 0:# print("eta <= 0")return 0# update alpha2 and its error in page of 127 Eq.(7.106) and Eq.(7.108)self.alphas[j] = old_alpha2 + self.train_label[j]*(Ei - Ej)/etaself.alphas[j] = self.updateAlpha2(self.alphas[j], L, H)new_alphas2 = self.alphas[j]self.upadateError(j)# update the alpha1 and its error in page of 127 Eq.(7.109)# new_alpha1 = old_alpha1 + y1y2(old_alpha2 - new_alpha2)new_alphas1 = old_alpha1 + self.train_label[i] * self.train_label[j] * (old_alpha2 - new_alphas2)self.alphas[i] = new_alphas1self.upadateError(i)# determine b in page of 130 Eq.(7.115) and Eq.(7.116)# new_b1 = -E1 - y1K11(new_alpha1 - old_alpha1) - y2K21(new_alpha2 - old_alpha2) + old_b# new_b2 = -E2 - y1K12(new_alpha1 - old_alpha1) - y2K22(new_alpha2 - old_alpha2) + old_bb1 = - Ei - self.train_label[i] * K11 * (old_alpha1 - self.alphas[i]) - self.train_label[j] * K21 * (old_alpha2 - self.alphas[j]) + self.bb2 = - Ej - self.train_label[i] * K12 * (old_alpha1 - self.alphas[i]) - self.train_label[j] * K22 * (old_alpha2 - self.alphas[j]) + self.bif (self.alphas[i] > 0) and (self.alphas[i] < self.C):self.b = b1elif (self.alphas[j] > 0) and (self.alphas[j] < self.C):self.b = b2else:self.b = (b1 + b2)/2.0return 1else:return 0
分类
我们可以使用优化的参数进行预测,该参数由下式给出:
for i in range(test_num):kernel_data = self.kernelTransformation(support_vectors, test_data[i, :], self.kernel)probability[i] = np.dot(kernel_data.T, np.multiply(support_vectors_label, support_vectors_alphas)) + self.bif probability[i] > 0:prediction[i] = 1else:prediction[i] = -1
结论与分析
SVM是一种比以前的算法更复杂的算法。在本文中,我们简化了搜索过程,使其更容易理解。最后,让我们将我们的SVM与Sklearn中的SVM进行比较,检测性能如下所示:
检测性能比sklearn更差,这是因为我们的SVM中的SMO比sklearn更简单。
可以在MachineLearning中找到本文中的相关代码和数据集。
有兴趣的小伙伴可以查看上一篇或者下一篇。
原文地址:https://www.codeproject.com/Articles/4064358/Step-by-Step-Guide-to-Implement-Machine-Learning-V
实现机器学习的循序渐进指南V——支持向量机相关推荐
- 实现机器学习的循序渐进指南系列汇总
之前曾尝试翻译了机器学习中的KNN和决策树,最近这段时间陆续看到这个系列的相关文章,并尝试翻译分析.由于此系列文章直接相对零散,所以有了这篇简单的汇总文章,以帮助有兴趣的小伙伴迅速找到想看的文章. 具 ...
- 实现机器学习的循序渐进指南XII——Apriori
目录 介绍 Apriori模型 频繁项集 关联规则 结论与分析 可访问 实现机器学习的循序渐进指南系列汇总,获取本系列完成文章列表. 介绍 Apriori是一种学习频繁项集和关联规则的算法.Aprio ...
- 实现机器学习的循序渐进指南XI——DBSCAN
目录 介绍 DBSCAN模型 开始 聚类算法 参数估计 结论与分析 可访问 实现机器学习的循序渐进指南系列汇总,获取本系列完成文章列表. 介绍 基于密度的噪声应用空间聚类(DBSCAN)是一种基于密度 ...
- 实现机器学习的循序渐进指南X——KMeans
目录 介绍 KMeans模型 KMEANS 平分KMeans KMEANS ++ 结论与分析 可访问 实现机器学习的循序渐进指南系列汇总,获取本系列完成文章列表. 介绍 KMeans是一种简单的聚类算 ...
- 实现机器学习的循序渐进指南VIII——线性回归
目录 介绍 回归模型 线性回归 局部加权线性回归 岭回归 套索(Lasso)回归 逐步线性回归 结论与分析 可访问 实现机器学习的循序渐进指南系列汇总,获取本系列完成文章列表. 介绍 通常存在变量之间 ...
- 实现机器学习的循序渐进指南IX ——树回归
目录 介绍 回归模型 特征选择 回归树的生成 回归 结论与分析 可访问 实现机器学习的循序渐进指南系列汇总,获取本系列完成文章列表. 介绍 在现实世界中,一些关系不是线性的.因此,应用线性回归分析这些 ...
- 实现机器学习的循序渐进指南VII——Blending Stacking
目录 介绍 混合(Blending)模型 混合(Blending)架构 混合(Blending)实现 混合(Blending)分类 堆叠(Stacking)模型 堆叠(Stacking)架构 堆叠(S ...
- 实现机器学习的循序渐进指南VI——AdaBoost
目录 介绍 AdaBoost模型 弱分类器 权重更新 分类 结论与分析 可访问 实现机器学习的循序渐进指南系列汇总,获取本系列完成文章列表. 介绍 AdaBoost是Boosting的一种方法,它基于 ...
- 实现机器学习的循序渐进指南IV——逻辑回归
目录 介绍 逻辑回归模型 参数估计 优化算法 分类 结论与分析 可访问 实现机器学习的循序渐进指南系列汇总,获取本系列完成文章列表. 介绍 逻辑回归是统计学习中的经典方法,它计算条件概率P(Y|X)并 ...
最新文章
- 教你用ERD轻松修改系统登录密码
- 群晖备份linux分区,黑群晖二合一系统无损扩充系统分区方法补充
- 哈希表和有序表的简单介绍
- linux中如何运行html文件路径问题,Linux中如何查询运行文件的全路径的方法
- sublime3使用笔记
- 【转】how can i build fast
- 迎建国七十周年,Linux厂商巡礼之一铭软件
- c/c++中与字符串处理相关的函数
- dubbo学习视频教程
- 基于Proteus的51单片机程序设计及仿真(交通灯控制系统)
- python绘图画猫咪_Turtle库画小猫咪
- 是的你没看错,HTTP3来了
- 推荐使用的热电阻Pt100测温电路
- mysql error 1236_【MySQL】Got fatal error 1236原因和解决方法
- Android 10.0 SystemUI修改状态栏电池图标样式为横屏显示
- java根据身份证获取出生年月日,性别,年龄
- 联想拯救者Y7000P触摸板无法使用
- 阿里云数据库RDS MySQL Serverless测评
- 第二阶段--团队冲刺--第三天
- 学JAVA可从事的工作岗位
热门文章
- python创建包含双引号的字符串代码_python 字符串组成MySql 命令时,字符串含有单引号或者双引号导致出错解决办法...
- mysql配置修改记录_mysql设置修改时间,更新记录当前时间
- 最受欢迎的资源是高质量的GUI工具包
- 如何使用模板生成多个页面_Divi不再只是页面构建器。 使用主题生成器,可以完全设计整个网站。...
- windows 根据进程id获得进程名称 C++
- systemd.generator — systemd unit generators
- Memcached下载与安装
- 汇编中bss,data,text,rodata,heap,stack段的作用
- 深度学习与神经网络概述
- qq html消息,类似于QQ新消息提醒-前端