当前位置: 首页 > news >正文

【Python机器学习】支持向量机——SMO高效优化算法

最小化的目标函数、优化过程中必须要遵循的额约束条件。不久之前,人们使用二次规划求解工具来解决上述最优化问题,这种工具是一种用于在线性约束下优化具有多个变量的二次目标函数的软件,而这些二次规划求解工具需要强大的计算能力支撑,另外在实现上也十分复杂。所有需要做的围绕优化的事情就是训练分类器,一旦得到alpha的最优值,我们就得到了分隔超平面并能够将之用于数据分类。

platt的SMO算法

SMO表示序列最小优化。platt的SMO算法时将大优化问题分解为多个小优化问题来求解的。这些小优化问题往往很容易求解,并且对它们进行顺序求解的结果与将它们作为整体来求解的结果是完全一致的。在结果完全相同的同时,SMO算法的求解时间短很多。

SMO算法的目标是求出一系列的alpha和b,一旦求出了这些alpha,就很容易计算出权重向量w并得到分隔超平面。

SMO算法的工作原理是:每次循环中选择两个alpha进行优化处理。一旦找到一对合适的alpha,那么就增大其中一个同时减少另一个。这里所谓的合适是指两个alpha必须要符合一定的条件,条件之一就是这两个alpha必须要在间隔边界之外,第二个条件则是这两个alpha还没有进行过区间化处理或者不在边界上。

应用简化版SMO算法处理小规模数据集

首先在数据集上遍历每一个alpha,然后在剩下的alpha集合中随机选择另一个alpha,从而构建alpha对。这里有一点非常重要,就是我们要同时改变两个alpha,之所以这样做是因为我们有一个约束条件:

\sum _{i}\cdot label^{(i)}=0

由于改变一个alpha可能会导致改约束条件失效,因此我们总是同时改变两个alpha。

构建一个辅助函数,用于在某个区间范围内随机选择一个整数,同时,我们还需要另一个辅助函数,用于在数值太大时对其进行调整:

def loadDataSet(fileName):dataMat=[]labelMat=[]fr=open(fileName)for line in fr.readlines():lineArr=line.strip().split('\t')dataMat.append([float(lineArr[0]),float(lineArr[1])])#标签labelMat.append(float(lineArr[2]))return dataMat,labelMat
def selectJrand(i,m):j=iwhile(j==i):j=int(random.uniform(0,m))return j
def clipAlpha(aj,H,L):#用于调整大于H或小于L的alpha值if aj>H:aj=Hif L>aj:aj=Lreturn aj

运行验证:

dataArr,labelArr=loadDataSet('testSet.txt')
print(labelArr)

这类可以看出来,类别标签都是-1和1,而不是0和1.

下面是SMO第一个版本的伪代码:

创建一个alpha向量并将其初始化为0向量

当迭代次数小于最大迭代次数时(外循环):

    对数据集中的每个数据向量(内循环):

        如果该数据向量可以被优化:

            随机选择另外一个数据向量

            同时优化这两个向量

            如果两个向量都不能被优化,退出内循环

    如果所有向量都没被优化,增加迭代数目,继续下一次循环

下面是实现过程:

def smoSimple(dataMatIn,classLabels,C,toler,maxIter):#输入参数分别为:数据集、类别标签、常数C、容错率、退出前最大的循环次数#转换为mat矩阵,得到列向量dataMatrix=mat(dataMatIn)labelMat=mat(classLabels).transpose()b=0m,n=shape(dataMatrix)#alpha列矩阵,初始化为0alphas=mat(zeros((m,1)))#遍历数据集的次数,当iter=maxIter时,函数结束运行并退出iter=0while (iter<maxIter):#用来记录alpha是否已经进行优化。alphaPairsChanges=0for i in range(m):fXi=float(multiply(alphas,labelMat).T*(dataMatrix*dataMatrix[i,:].T))+b#误差Ei=fXi-float(labelMat[i])#如果误差很大,可以对该数据实例对应的alpha值进行优化#另外,如果alpha小于0或者大于C将被调整为0或C,一旦他们等于这两个值,就不值得强化了if ((labelMat[i]*Ei<-toler) and (alphas[i]<C)) or ((labelMat[i]*Ei>toler) and (alphas[i]>0)):#如果alpha可以更改,进入优化过程j=selectJrand(i,m)#随机选择第二个alphafXj=float(multiply(alphas,labelMat).T*(dataMatrix*dataMatrix[j,:].T))+b# 继续计算误差值Ej=fXj-float(labelMat[j])#通过copy()实现alphaIold=alphas[i].copy()alphaJold=alphas[j].copy()#保证alpha在0与C之间if (labelMat[i]!=labelMat[j]):L=max(0,alphas[j]-alphas[i])H=min(C,C+alphas[j]-alphas[i])else:L=max(0,alphas[j]+alphas[i]-C)H=min(C,alphas[j]+alphas[i])if L==H:print('L==H')continue#eta为最优修改量,如果eta=0,需要退出循环的当前迭代过程。eta=2.0*dataMatrix[i,:]*dataMatrix[j,:].T-dataMatrix[i,:]*dataMatrix[i,:].T-dataMatrix[j,:]*dataMatrix[j,:].Tif eta>=0:print('eta>=0')continuealphas[j]=alphas[j]-labelMat[j]*(Ei-Ej)/etaalphas[j]=clipAlpha(alphas[j],H,L)if (abs(alphas[j]-alphaJold)<=0.00001):print('J没有足够移动')continue#对i进行修改,修改量与j相同,但方向相反alphas[i]=alphas[i]+labelMat[j]*labelMat[i]*(alphaJold-alphas[j])#设置常数项b1=b-Ei-labelMat[i]*(alphas[i]-alphaIold)*dataMatrix[i,:]*dataMatrix[i,:].T-labelMat[j]*(alphas[j]-alphaJold)*dataMatrix[i,:]*dataMatrix[j,:].Tb2=b-Ej-labelMat[i]*(alphas[i]-alphaIold)*dataMatrix[i,:]*dataMatrix[j,:].T-labelMat[j]*(alphas[j]-alphaJold)*dataMatrix[j,:]*dataMatrix[j,:].Tif (0<alphas[i]) and (C>alphas[i]):b=b1elif (0<alphas[j]) and (C>alphas[j]):b=b2else:b=(b1+b2)/2.0alphaPairsChanges=alphaPairsChanges+1if alphaPairsChanges==0:iter=iter+1else:iter=0return b,alphas

实际运行:

dataArr,labelArr=loadDataSet('testSet.txt')
# print(labelArr)
b,alphas=smoSimple(dataArr,labelArr,0.6,0.001,40)
print(b)
print(alphas[alphas>0])

alphas[alphas>0]命令是数组过滤的一个实例,而且它只对NumPy类型有用,却并不适用于Python中的正则表,如果输入alpha>0,那么就会得到一个布尔数组,并且在不等式成立的情况下,其对应值是正确的。于是,在将该布尔数组应用到原始的矩阵当中时,就会得到一个NumPy矩阵,并且其中矩阵仅仅包含大于0的值。

为了得到支持向量的个数,输入:

print(shape(alphas[alphas>0]))
for i in range(100):if alphas[i]>0.0:print(dataArr[i],labelArr[i])

在原始数据集上对这些支持向量画圈后的结果如图:

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 团队关系判定(100分) - 三语言AC题解(Python/Java/Cpp)
  • 程序员面试“八股文”:助力成长还是应试枷锁?
  • ps基础操作1
  • 【c++】自定义函数Rounding (余归函数)
  • 学生管理系统之界面设计
  • python 学习: np.pad
  • 安装pytorch GPU方法
  • C#对象和类型
  • 每日一题——贪心算法
  • 设计模式:模板方法模式:封装不变,扩展可变
  • 使用 Python 对雷达卫星 sar 图像进行降噪的三种方法
  • 使用PasteSpider实现类似Jenkins的功能,让你的2G服务器也可以飞起
  • Scrapy框架在处理大规模数据抓取时有哪些优化技巧?
  • Spring实现自定义注解
  • PHP开发【石头剪刀布小游戏】
  • 5、React组件事件详解
  • electron原来这么简单----打包你的react、VUE桌面应用程序
  • JavaScript实现分页效果
  • JS笔记四:作用域、变量(函数)提升
  • Just for fun——迅速写完快速排序
  • Markdown 语法简单说明
  • PyCharm搭建GO开发环境(GO语言学习第1课)
  • React Transition Group -- Transition 组件
  • SQLServer之创建显式事务
  • vue 配置sass、scss全局变量
  • 关于 Linux 进程的 UID、EUID、GID 和 EGID
  • 基于Javascript, Springboot的管理系统报表查询页面代码设计
  • 判断客户端类型,Android,iOS,PC
  • 前嗅ForeSpider采集配置界面介绍
  • 算法-图和图算法
  • 消息队列系列二(IOT中消息队列的应用)
  • 分布式关系型数据库服务 DRDS 支持显示的 Prepare 及逻辑库锁功能等多项能力 ...
  • ​学习一下,什么是预包装食品?​
  • # 服务治理中间件详解:Spring Cloud与Dubbo
  • # 利刃出鞘_Tomcat 核心原理解析(二)
  • #HarmonyOS:基础语法
  • $.ajax()
  • $forceUpdate()函数
  • (1)虚拟机的安装与使用,linux系统安装
  • (TipsTricks)用客户端模板精简JavaScript代码
  • (web自动化测试+python)1
  • (补充)IDEA项目结构
  • (二)c52学习之旅-简单了解单片机
  • (附源码)计算机毕业设计ssm本地美食推荐平台
  • (排序详解之 堆排序)
  • (杂交版)植物大战僵尸
  • (转)真正的中国天气api接口xml,json(求加精) ...
  • ./和../以及/和~之间的区别
  • .net core使用RPC方式进行高效的HTTP服务访问
  • .NET 编写一个可以异步等待循环中任何一个部分的 Awaiter
  • .net中生成excel后调整宽度
  • //TODO 注释的作用
  • @antv/g6 业务场景:流程图
  • @ComponentScan比较
  • @EnableWebSecurity 注解的用途及适用场景