【Python机器学习】支持向量机——在复杂数据上应用核函数

news2025/1/23 12:55:21

上图中,数据中存在某种可以识别的模式,其中一个问题就是:我们能否想线性情况一样,利用强大的工具来捕捉数据中的这种模式?

利用核函数将数据映射到高维空间

在上图中,数据点处于一个圆中,人类的大脑能够意识到这一点,但是对于分类器而言,它只能识别分类器的结果是大于0还是小于0。如果只在x和y轴构成的坐标系中插入直线进行分类的话,我们并不会得到理想的结果。我们或许可以对园中的数据进行某种形式的转换,从而得到某些新的变量来表示数据。在这种情况下,我们就更容易得到大于0或者小于0的测试结果。在这个例子中,我们将数据从一个特征空间转换到另一个特征空间。在新空间下,我们可以很容易利用已有的工具对数据进行处理。数学家们喜欢将这一过程称之为从一个特征空间到另一个特征空间的映射。通常情况下,这种映射会降低维特征空间映射到高维空间。

这种从某个特征空间到另一个特征空间的映射是通过核函数来实现的。我们可以把核函数想象成一个包装器或者是接口,它能把数据从某个很难处理的形式转换成另一个比较容易处理的形式。距离计算的方法有很多种,经过空间转换之后,我们可以从高维空间中解决线性问题,这也就等价于在低维空间解决非线性问题。

SVM优化中一个特别好的地方就是:所有的运算都可以写成内积(点积)的形式。向量的内积指的是两个向量相乘,之后得到单个标量或者数值。我们可以把内积运算替换成核函数,而不必做简化处理。将内积替换成核函数的方式被称为核技巧或者核“变电”

核函数并不仅仅应用于支持向量机,很多其他的机器学习算法也都用到核函数。

径向基核函数

径向基函数是SVM中常用的一个核函数。径向基函数是一个采用向量作为自变量的函数,能够基于向量距离运算输出一个标量。这个距离可以是从<0,0>向量或者其他向量开始计算的距离。

径向基函数的高斯版本的具体公式为:

k(x,y)=exp\left ( \frac{-\left \| x-y \right \|^{2}}{2\sigma ^{2}} \right )

其中,\sigma是用户定义的用于确定达到率或者说函数值跌落到0的速度参数。

上述高斯核函数将数据从其特征空间映射到更高维的空间,具体来说这里是映射到一个无穷维的空间。高斯核函数只是一个常用的核函数,使用者并不需要确切地理解数据到底是如何表现的,而且使用高斯核函数还会得到一个理想的结果。上面的例子中,数据点基本都在一个圆内。对于这个例子,我们可以直接检查原始数据,并意识到只要度量数据点到圆心的距离即可。然而如果碰到了一个不是这种形式的新数据集,那么就会陷入困境。在该数据集上,使用高斯核函数可以得到恨到的记过,当然该函数也可以用于许多其他的数据集,并且也能得到低错误率的结果。

修改optStruct类:

def kernelTrans(X,A,kTup):
    m,n=shape[X]
    K=mat(zeros((m,1)))
    if kTup[0]=='lin':
        K=X*A.T
    elif kTup[0]=='rbf':
        for j in range(m):
            deltaRow=X[j,:]-A
            K[j]=deltaRow*deltaRow.T
        K=exp(K/(-1*kTup[1]**2))
    else:
        raise NameError('Houston We Have a Problem That Kernel is not recognized')
    return K

class optStruct:
    def __init__(self,dataMatIn,classLabels,C,toler,kTup):
        self.X=dataMatIn
        self.labelMat=classLabels
        self.C=C
        self.tol=toler
        self.m=shape(dataMatIn)[0]
        self.alphas=mat(zeros((self.m,1)))
        self.b=0
        #误差缓存
        self.eCache=mat(zeros((self.m,2)))
        self.K=mat(zeros((self.m,self.m)))
        for i in range(self.m):
            self.K[:,i]=kernelTrans(self.X,self.X[i,:],kTup)

kTup是一个包含核函数信息的元素。在初始化方法结束时,矩阵K先被构建,然后再通过调用函数kernelTrans()进行填充。全局的K值只需计算一次。然后,当想要使用核函数时,就可以对它进行调用。这些省去了很多冗余的计算开销。

当计算矩阵K时,该过程多次调用了kernelTrans()。该函数有3个输入参数:2个数值型变量和1个元组。元组kTup给出的是核函数的信息。元组的第一个参数是描述所用核函数类型的第一个字符串,其他2个参数都是核函数可能需要的可选参数。该函数首先构建出了一个列向量,然后检查元组以确定核函数的类型。这里只给出了2中类型,但是依然可以很容易地通过添加elif语句来扩展到更多选项。

在线性核函数的情况下,内积计算在“所有数据集”和“数据集中的一行”这两个输入之间展开。在径向基核函数的情况下,在for循环中对于矩阵的每个元素计算高斯函数的值。而在for循环结束之后,我们将计算过程应用到整个向量上去。值得一提的是,在NumPy矩阵中,除法符号意味着对矩阵元素展开计算而不像在MATLAB中一样计算矩阵的逆。

最后,如果遇到一个无法识别的元组,程序就会抛出异常,因为在这种情况下不希望程序再继续运行,这一点非常重要。

修改innerL()函数和calcEK()函数:


def innerL(i,oS):
    Ei=calcEk(oS,i)
    if ((oS.labelMat[i]*Ei<-oS.tol) and (oS.alphas[i]<oS.C)) or ((oS.labelMat[i]*Ei>oS.tol) and (oS.alphas[i]>0)):
        # 如果alpha可以更改,进入优化过程
        j,Ej=selectJ(i,oS,Ei)
        #随机选择第二个alpha
        alphaIold = oS.alphas[i].copy()
        alphaJold = oS.alphas[j].copy()
        # 保证alpha在0与C之间
        if (oS.labelMat[i]!=oS.labelMat[j]):
            L=max(0,oS.alphas[j]-oS.alphas[i])
            H=min(oS.C,oS.C+oS.alphas[j]-oS.alphas[i])
        else:
            L=max(0,oS.alphas[j]+oS.alphas[i]-oS.C)
            H=min(oS.C,oS.alphas[j]+oS.alphas[i])
        if L==H:
            print('L==H')
            return 0
        # eta为最优修改量,如果eta=0,需要退出循环的当前迭代过程。
        eta=2.0*oS.K[i,j]-oS.K[i,i]-oS.K[j,j]
        if eta>=0:
            print('eta>0')
            return 0
        oS.alphas[j]=oS.alphas[j]-oS.labelMat[j]*(Ei-Ej)/eta
        oS.alphas[j]=clipAlpha(oS.alphas[j],H,L)
        updateEk(oS,j)
        if (abs(oS.alphas[j]-alphaJold)<0.00001):
            print('j mot moving enough')
            return 0
        oS.alphas[i]=oS.alphas[i]+oS.labelMat[j]*oS.labelMat[i]*(alphaJold-oS.alphas[j])
        updateEk(oS,i)
        # 设置常数项
        b1 = oS.b - Ei - oS.labelMat[i] * (oS.alphas[i] - alphaIold) * oS.K[i,i] - oS.labelMat[j] * (
                    oS.alphas[j] - alphaJold) * oS.K[i, j]
        b2 = oS.b - Ej - oS.labelMat[i] * (oS.alphas[i] - alphaIold) * oS.K[i, j] - oS.labelMat[j] * (
                    oS.alphas[j] - alphaJold) * oS.K[j, j]
        if (0<oS.alphas[i]) and (oS.C>oS.alphas[i]):
            oS.b=b1
        elif (0<oS.alphas[j]) and (oS.C>oS.alphas[j]):
            oS.b=b2
        else:
            oS.b=(b1+b2)/2.0
        return 1
    else:
        return 0


def calcEk(oS,k):
    #对于给定的alpha值,计算E值并返回
    fXk=float(multiply(oS.alphas,oS.labelMat).T*oS.K[:,k]+oS.b)
    Ek=fXk-float(oS.labelMat[k])
    return Ek

在测试中使用核函数

下面:构造一个对文章开头数据进行有效分类的分类器,该分类器使用了径向基核函数。前面提到的径向基函数有一个用户定义的输入\sigma。首先,我们需要确定它的大小,然后利用该核函数构建一个分类器。

代码实现:

def testRbf(k1=1.3):
    dataArr, labelArr = loadDataSet('testSetRBF.txt')
    # print(labelArr)
    b, alphas = smoP(dataArr, labelArr, 200, 0.0001, 10000,('rbf',k1))
    dataMat=mat(dataArr)
    labelMat=mat(labelArr).transpose()
    svInd=nonzero(alphas.A>0)[0]
    sVs=dataMat[svInd]
    labelSV=labelMat[svInd]
    print('there are %d Support Vectors' % shape(sVs)[0])
    m,n=shape(dataMat)
    errorCount=0
    for i in range(m):
        kernelEval=kernelTrans(sVs,dataMat[i,:],('rbf',k1))
        predict=kernelEval.T*multiply(labelSV,alphas[svInd])+b
        if sign(predict)!=sign(labelArr[i]):
            errorCount=errorCount+1
    print('错误率:',(float(errorCount)/m))
    dataArr,labelArr=loadDataSet('testSetRBF2.txt')
    errorCount=0
    dataMat = mat(dataArr)
    labelMat = mat(labelArr).transpose()
    m, n = shape(dataMat)
    for i in range(m):
        kernelEval=kernelTrans(sVs,dataMat[i,:],('rbf',k1))
        predict=kernelEval.T*multiply(labelSV,alphas[svInd])+b
        if sign(predict)!=sign(labelArr[i]):
            errorCount=errorCount+1
    print('错误率:',(float(errorCount)/m))

函数中只有一个可选的参数,是高斯径向基函数中的一个用户定义变量。整个代码先从文件中读取数据集,然后在该数据集上运行platt SMO算法,其中核函数类型为rbf。

优化过程结束后,在后面的矩阵数学运算中建立了数据的矩阵副本,并且找出那些非零的alpha值,从而得到所需要的支持向量;同时,也就得到了这些支持向量和alpha的类别标签值。这些值仅仅是需要分类的值。

整个代码中最重要的是for循环最开始的两行,它们给出了如何利用核函数进行分类。首先利用结构化方法中使用过的kernelTrans(),得到转换后的数据。然后,再用其与前面的alpha及类别标签值求积。

运行结果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1978091.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《零散知识点 · 自定义 HandleMapping》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…

[独家原创] CPO-RBF多特征分类预测 优化宽度+中心值+连接权值 (多输入单输出)Matlab代码

[独家原创] CPO-RBF多特征分类预测 优化宽度中心值连接权值 &#xff08;多输入单输出&#xff09;Matlab代码 目录 [独家原创] CPO-RBF多特征分类预测 优化宽度中心值连接权值 &#xff08;多输入单输出&#xff09;Matlab代码效果一览基本介绍程序设计参考资料 效果一览 基本…

算法--初阶

1、tips 1.1、set求交集 {1,2,3} & {2,3} & {1,2} {2} 其实就是位运算&#xff0c; 只有set可以这样使用&#xff0c; list没有这种用法 {1,2,3} | {2,3, 4} | {1,2} {1, 2, 3, 4} 并集 1.2、*与** * 序列(列表、元组)解包&#xff0c;如果是字典&#xff0c;那…

15.75.【C语言】表达式求值

目录 一.整型提升 1.定义 2. 一.整型提升 1.定义 C语言中整型算术运算总是至少以缺省&#xff08;默认&#xff09;整型类型的精度来进行的。为了获得这个精度&#xff0c;表达式中的字符和短整型操作数在使用之前被转换为普通整型&#xff0c;这种转换称为整型提升 2.整型提…

C++初学者指南-5.标准库(第二部分)--移除元素算法

C初学者指南-5.标准库(第二部分)–移除元素算法 文章目录 C初学者指南-5.标准库(第二部分)--移除元素算法remove / remove_ifremove_copy / remove_copy_ifunique / unique_copyerase / erase_if相关内容 不熟悉 C 的标准库算法&#xff1f; ⇒ 简介 remove / remove…

还有谁分不清Oracle认证里的OCA、OCP、OCM?

在IT行业&#xff0c;Oracle认证是许多专业人士提升技能和职业竞争力的重要途径。 Oracle认证是一套由Oracle公司提供的全球认可的专业资格认证体系&#xff0c;旨在证明个人在Oracle数据库及相关技术领域的专业技能和知识水平。 Oracle认证作为数据库认证中的天花板&#xff0…

目标检测——GDXray数据集转为YOLO格式

关于该数据集的介绍可以看我写的另一篇博客&#xff1a;链接 论文题目&#xff1a;《GDXray: The Database of X-ray Images for Nondestructive Testing》论文链接&#xff1a;https://link.springer.com/article/10.1007/s10921-015-0315-7 Github链接&#xff1a; https:…

JavaScript小本本|JavaScript 对象方法定义的演变

在微信中阅读&#xff0c;欢迎关注公众号&#xff1a;CodeFit。 创作不易&#xff0c;如果你觉得这篇文章对您有帮助&#xff0c;请不要忘了 点赞、分享 和 关注&#xff0c;为我的 持续创作 提供 动力&#xff01; 欢迎订阅《Vue 3.x 必修课&#xff5c;2024》&#xff1a;htt…

JAVA项目基于SpringBoot的外卖点餐管理系统

目录 一、前言 二、技术介绍 三、系统实现 四、论文参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 随着生活节…

C++20中的模块

大多数C项目使用多个翻译单元(translation units)&#xff0c;因此它们需要在这些单元之间共享声明和定义(share declarations and definitions)。headers的使用在这方面非常突出。模块(module)是一种language feature&#xff0c;用于在翻译单元之间共享声明和定义。它们是某些…

追问试面试系列:Dubbo

欢迎来到Dubbo系列,在面试中被问到Dubbo相关的问题时,大部分都是简历上写了Dubbo,或者面试官想尝试问问你对Dubbo是否了解。 本系列主要是针对面试官通过一个点就使劲儿往下问的情况。 面试官:说说你们项目亮点 好的面试官 我们这个项目的技术亮点在于采用了Spring Cloud…

正点原子imx6ull-mini-Linux驱动之Linux I2C 驱动实验(21)

I2C 是很常用的一个串行通信接口&#xff0c;用于连接各种外设、传感器等器件&#xff0c;在裸机篇已经对 I.MX6U 的 I2C 接口做了详细的讲解。本章我们来学习一下如何在 Linux 下开发 I2C 接口器件 驱动&#xff0c;重点是学习 Linux 下的 I2C 驱动框架&#xff0c;按照指定的…

人工智能深度学习系列—探索Jaccard相似度损失:图像分割领域的新利器

文章目录 1. 背景介绍2. Loss计算公式3. 使用场景4. 代码样例5. 总结 1. 背景介绍 在深度学习的各种应用中&#xff0c;图像分割是一项极具挑战性的任务。Jaccard相似度损失&#xff08;Jaccard Similarity Loss&#xff09;&#xff0c;又称为IoU损失&#xff08;Intersectio…

计算机基本理论与程序运行原理概述

目录 计算机的基本表示方法 计算机的组成 程序运行的原理 指令执行的流水线 编译原理 个人理解 面试题总结 计算机的基本表示方法 计算机系统使用高、低电平来表示逻辑1和0。数据在计算机中的存储、传输和处理均以二进制形式进行。数据通过总线作为电信号进行传输&…

Es6常用的一些数组处理方法

在平时的开发中&#xff0c;我们很多时候用到数组结构数据&#xff0c;那么如何高效处理数组是可以提高开发效率的&#xff0c;现在越来越多人使用es6&#xff0c;那么它的很多方法简化了我们对数据的操作&#xff0c;比如以前数组循环用for循环写比较多的代码&#xff0c;现在…

HTML-07.表格标签

一、要制作的表格如下 二、代码如下 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>表格标签<…

探索数据结构:二叉搜索树的递归与非递归实现

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;数据结构与算法 贝蒂的主页&#xff1a;Betty’s blog 1. 二叉搜索树的介绍 二插入搜索树&#xff08;Binary Search Tree&…

第16课 Scratch入门篇:师生问候-广播版

师生问候-广播版 故事背景&#xff1a; 上节课我们完成了师生问候功能&#xff0c;指令罗列的蛮多&#xff0c;写起来很麻烦&#xff0c;而且阅读起来不容易理解&#xff0c;这节课我们把上节课内容进行优化&#xff0c;引入一个新的指令-广播&#xff0c;广播相当于一个事件的…

DFS之迭代加深+双向DFS+IDA*

迭代加深&#xff1a; 搜索范围一层一层扩大&#xff0c;可以快速某些分支比较深&#xff0c;但是答案比较浅的问题。 https://www.acwing.com/problem/content/172/ 通过观察可以发现&#xff1a; 1.搜索时最坏情况可能搜到100层&#xff0c;比较深&#xff0c;但是答案应…

【Javax.Validation】✈️整合 SpringBoot 实现运行时的参数校验

目录 &#x1f44b;前言 &#x1f440;一、Validation 依赖 &#x1f4eb;二、常见注解 2.1 不需要指定注解参数 2.2 需要声明注解参数 &#x1f49e;️三、项目测试注解使用 3.1 依赖引入 3.2 实体类创建 3.3 创建对外接口 3.4 模拟请求 &#x1f331;四、章末 &#x1f…