机器学习——支持向量机(SVM)之核函数(kernel)
对于线性不可分的数据集,可以利用核函数(kernel)将数据转换成易于分类器理解的形式。
如下图,如果在x轴和y轴构成的坐标系中插入直线进行分类的话, 不能得到理想的结果,或许我们可以对圆中的数据进行某种形式的转换,从而得到某些新的变量来表示数据。在这种表示情况下,我们就更容易得到大于0或者小于0的测试结果。在这个例子中,我们将数据从一个特征空间转换到另一个特征空间,在新的空间下,我们可以很容易利用已有的工具对数据进行处理,将这个过程称之为从一个特征空间到另一个特征空间的映射。在通常情况下,这种映射会将低维特征空间映射到高维空间。
这种从某个特征空间到另一个特征空间的映射是通过核函数来。
SVM优化中一个特别好的地方就是,所有的运算都可以写成内积(inner product)的形式。向量的内积指的就是两个向量相乘,之后得到单个标量或者数值。我们可以把内积运算替换成核函数,而并不必做简化处理。将内积替换成核函数的方法被称之为核技巧(kernel trick)或者核“变电”(kernel substation)。
径向基核函数
径向基核函数是SVM中常用的一个核函数。径向基函数是一个采用向量作为自变量的函数,能够基于向量距离运算输出一个标量。
- '''#######********************************
- 以下是有核函数的版本
- '''#######********************************
- class optStruct:
- def __init__(self,dataMatIn, classLabels, C, toler, kTup): # Initialize the structure with the parameters
- 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))) #first column is valid flag
- self.K = mat(zeros((self.m,self.m)))
- for i in range(self.m):
- self.K[:,i] = kernelTrans(self.X, self.X[i,:], kTup)
- def calcEk(oS, k): #计算误差
- fXk = float(multiply(oS.alphas,oS.labelMat).T*oS.K[:,k] + oS.b)
- Ek = fXk - float(oS.labelMat[k])
- return Ek
- def selectJ(i, oS, Ei): #用于选择第2个循环(内循环)的alpha值,内循环中的启发式方法
- maxK = -1; maxDeltaE = 0; Ej = 0
- oS.eCache[i] = [1,Ei] #set valid #choose the alpha that gives the maximum delta E
- validEcacheList = nonzero(oS.eCache[:,0].A)[0]
- if (len(validEcacheList)) > 1:
- for k in validEcacheList: #loop through valid Ecache values and find the one that maximizes delta E
- if k == i: continue #跳过本身
- Ek = calcEk(oS, k)
- deltaE = abs(Ei - Ek)
- if (deltaE > maxDeltaE): #选取具有最大步长的j
- maxK = k; maxDeltaE = deltaE; Ej = Ek
- return maxK, Ej
- else: #in this case (first time around) we don't have any valid eCache values
- j = selectJrand(i, oS.m)
- Ej = calcEk(oS, j)
- return j, Ej
- def updateEk(oS, k): #alpha改变后,更新缓存
- Ek = calcEk(oS, k)
- oS.eCache[k] = [1,Ek]
- #内部循环的代码和简版的SMO代码很相似
- def innerL(i, oS):
- Ei = calcEk(oS, i)
- #判断每一个alpha是否被优化过,如果误差很大,就对该alpha值进行优化,toler是容错率
- 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)):
- j,Ej = selectJ(i, oS, Ei) #使用启发式方法选取第2个alpha,选取使得误差最大的alpha
- alphaIold = oS.alphas[i].copy(); alphaJold = oS.alphas[j].copy();
- #保证alpha在0与C之间
- if (oS.labelMat[i] != oS.labelMat[j]): #当y1和y2异号,计算alpha的取值范围
- L = max(0, oS.alphas[j] - oS.alphas[i])
- H = min(oS.C, oS.C + oS.alphas[j] - oS.alphas[i])
- else: #当y1和y2同号,计算alpha的取值范围
- 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是alpha[j]的最优修改量,eta=K11+K22-2*K12,也是f(x)的二阶导数,K表示核函数
- eta = 2.0 * oS.K[i,j] - oS.K[i,i] - oS.K[j,j] #changed for kernel
- #如果二阶导数-eta <= 0,说明一阶导数没有最小值,就不做任何改变,本次循环结束直接运行下一次for循环
- if eta >= 0: print "eta>=0"; return 0
- oS.alphas[j] -= oS.labelMat[j]*(Ei - Ej)/eta #利用公式更新alpha[j],alpha2new=alpha2-yj(Ei-Ej)/eta
- oS.alphas[j] = clipAlpha(oS.alphas[j],H,L) #判断alpha的范围是否在0和C之间
- updateEk(oS, j) #在alpha改变的时候更新Ecache
- print "j=",j
- print oS.alphas.A[j]
- #如果alphas[j]没有调整,就忽略下面语句,本次循环结束直接运行下一次for循环
- if (abs(oS.alphas[j] - alphaJold) < 0.00001): print "j not moving enough"; return 0
- oS.alphas[i] += oS.labelMat[j]*oS.labelMat[i]*(alphaJold - oS.alphas[j])#update i by the same amount as j
- updateEk(oS, i) #在alpha改变的时候更新Ecache
- print "i=",i
- print oS.alphas.A[i]
- #已经计算出了alpha,接下来根据模型的公式计算b
- 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]
- #根据公式确定偏移量b,理论上可选取任意支持向量来求解,但是现实任务中通常使用所有支持向量求解的平均值,这样更加鲁棒
- 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 #如果有任意一对alpha发生改变,返回1
- else: return 0
- #完整版Platt SMO的外循环
- def smoP(dataMatIn, classLabels, C, toler, maxIter,kTup=('lin', 0)):
- oS = optStruct(mat(dataMatIn),mat(classLabels).transpose(),C,toler, kTup)
- iter = 0
- entireSet = True; alphaPairsChanged = 0
- while (iter < maxIter) and ((alphaPairsChanged > 0) or (entireSet)): #有alpha改变同时遍历次数小于最大次数,或者需要遍历整个集合
- alphaPairsChanged = 0
- #首先进行完整遍历,过程和简化版的SMO一样
- if entireSet:
- for i in range(oS.m):
- alphaPairsChanged += innerL(i,oS) #i是第1个alpha的下标
- print "完整遍历, 迭代次数: %d i:%d, 成对改变的次数 %d" % (iter,i,alphaPairsChanged)
- iter += 1
- #非边界遍历,挑选其中alpha值在0和C之间非边界alpha进行优化
- else:
- nonBoundIs = nonzero((oS.alphas.A > 0) * (oS.alphas.A < C))[0] #然后挑选其中值在0和C之间的非边界alpha进行遍历
- for i in nonBoundIs:
- alphaPairsChanged += innerL(i,oS)
- print "非边界, 迭代次数: %d i:%d, 成对改变的次数 %d" % (iter,i,alphaPairsChanged)
- iter += 1
- #如果这次是完整遍历的话,下次不用进行完整遍历
- if entireSet: entireSet = False #终止完整循环
- elif (alphaPairsChanged == 0): entireSet = True #如果alpha的改变数量为0的话,再次遍历所有的集合一次
- print "iteration number: %d" % iter
- return oS.b,oS.alphas
- def calcWs(alphas,dataArr,classLabels): #计算模型的参数w,即alpha*y*x转置的累加
- X = mat(dataArr); labelMat = mat(classLabels).transpose()
- m,n = shape(X)
- w = zeros((n,1))
- for i in range(m):
- w += multiply(alphas[i]*labelMat[i],X[i,:].T)
- return w
- def testRbf(k1=1.3):
- dataArr,labelArr = loadDataSet('testSetRBF.txt')
- b,alphas = smoP(dataArr, labelArr, 200, 0.0001, 10000, ('rbf', k1)) #C=200 important
- datMat=mat(dataArr); labelMat = mat(labelArr).transpose()
- svInd=nonzero(alphas.A>0)[0]
- sVs=datMat[svInd] #get matrix of only support vectors
- labelSV = labelMat[svInd];
- print "there are %d Support Vectors" % shape(sVs)[0]
- m,n = shape(datMat)
- errorCount = 0
- for i in range(m):
- kernelEval = kernelTrans(sVs,datMat[i,:],('rbf', k1))
- predict=kernelEval.T * multiply(labelSV,alphas[svInd]) + b
- if sign(predict)!=sign(labelArr[i]): errorCount += 1
- print "the training error rate is: %f" % (float(errorCount)/m)
- dataArr,labelArr = loadDataSet('testSetRBF2.txt')
- errorCount = 0
- datMat=mat(dataArr); labelMat = mat(labelArr).transpose()
- m,n = shape(datMat)
- for i in range(m):
- kernelEval = kernelTrans(sVs,datMat[i,:],('rbf', k1))
- predict=kernelEval.T * multiply(labelSV,alphas[svInd]) + b
- if sign(predict)!=sign(labelArr[i]): errorCount += 1
- print "the test error rate is: %f" % (float(errorCount)/m)
- def img2vector(filename):
- returnVect = zeros((1,1024))
- fr = open(filename)
- for i in range(32):
- lineStr = fr.readline()
- for j in range(32):
- returnVect[0,32*i+j] = int(lineStr[j])
- return returnVect
- def loadImages(dirName):
- from os import listdir
- hwLabels = []
- trainingFileList = listdir(dirName) #load the training set
- m = len(trainingFileList)
- trainingMat = zeros((m,1024))
- for i in range(m):
- fileNameStr = trainingFileList[i]
- fileStr = fileNameStr.split('.')[0] #take off .txt
- classNumStr = int(fileStr.split('_')[0])
- if classNumStr == 9: hwLabels.append(-1)
- else: hwLabels.append(1)
- trainingMat[i,:] = img2vector('%s/%s' % (dirName, fileNameStr))
- return trainingMat, hwLabels
- def testDigits(kTup=('rbf', 10)):
- dataArr,labelArr = loadImages('trainingDigits')
- b,alphas = smoP(dataArr, labelArr, 200, 0.0001, 10000, kTup)
- datMat=mat(dataArr); labelMat = mat(labelArr).transpose()
- svInd=nonzero(alphas.A>0)[0]
- sVs=datMat[svInd]
- labelSV = labelMat[svInd];
- print "there are %d Support Vectors" % shape(sVs)[0]
- m,n = shape(datMat)
- errorCount = 0
- for i in range(m):
- kernelEval = kernelTrans(sVs,datMat[i,:],kTup)
- predict=kernelEval.T * multiply(labelSV,alphas[svInd]) + b
- if sign(predict)!=sign(labelArr[i]): errorCount += 1
- print "the training error rate is: %f" % (float(errorCount)/m)
- dataArr,labelArr = loadImages('testDigits')
- errorCount = 0
- datMat=mat(dataArr); labelMat = mat(labelArr).transpose()
- m,n = shape(datMat)
- for i in range(m):
- kernelEval = kernelTrans(sVs,datMat[i,:],kTup)
- predict=kernelEval.T * multiply(labelSV,alphas[svInd]) + b
- if sign(predict)!=sign(labelArr[i]): errorCount += 1
- print "the test error rate is: %f" % (float(errorCount)/m)
机器学习——支持向量机(SVM)之核函数(kernel)的更多相关文章
- [白话解析] 深入浅出支持向量机(SVM)之核函数
[白话解析] 深入浅出支持向量机(SVM)之核函数 0x00 摘要 本文在少用数学公式的情况下,尽量仅依靠感性直觉的思考来讲解支持向量机中的核函数概念,并且给大家虚构了一个水浒传的例子来做进一步的通俗 ...
- 机器学习——支持向量机SVM
前言 学习本章节前需要先学习: <机器学习--最优化问题:拉格朗日乘子法.KKT条件以及对偶问题> <机器学习--感知机> 1 摘要: 支持向量机(SVM)是一种二类分类模型, ...
- coursera机器学习-支持向量机SVM
#对coursera上Andrew Ng老师开的机器学习课程的笔记和心得: #注:此笔记是我自己认为本节课里比较重要.难理解或容易忘记的内容并做了些补充,并非是课堂详细笔记和要点: #标记为<补 ...
- 机器学习支持向量机SVM笔记
SVM简述: SVM是一个线性二类分类器,当然通过选取特定的核函数也可也建立一个非线性支持向量机.SVM也可以做一些回归任务,但是它预测的时效性不是太长,他通过训练只能预测比较近的数据变化,至于再往后 ...
- 吴裕雄 python 机器学习——支持向量机SVM非线性分类SVC模型
import numpy as np import matplotlib.pyplot as plt from sklearn import datasets, linear_model,svm fr ...
- 机器学习——支持向量机(SVM)之拉格朗日乘子法,KKT条件以及简化版SMO算法分析
SVM有很多实现,现在只关注其中最流行的一种实现,即序列最小优化(Sequential Minimal Optimization,SMO)算法,然后介绍如何使用一种核函数(kernel)的方式将SVM ...
- 机器学习-支持向量机SVM
简介: 支持向量机(SVM)是一种二分类的监督学习模型,他的基本模型是定义在特征空间上的间隔最大的线性模型.他与感知机的区别是,感知机只要找到可以将数据正确划分的超平面即可,而SVM需要找到间隔最大的 ...
- 机器学习:SVM(核函数、高斯核函数RBF)
一.核函数(Kernel Function) 1)格式 K(x, y):表示样本 x 和 y,添加多项式特征得到新的样本 x'.y',K(x, y) 就是返回新的样本经过计算得到的值: 在 SVM 类 ...
- 机器学习——支持向量机(SVM)
支持向量机原理 支持向量机要解决的问题其实就是寻求最优分类边界.且最大化支持向量间距,用直线或者平面,分隔分隔超平面. 基于核函数的升维变换 通过名为核函数的特征变换,增加新的特征,使得低维度空间中的 ...
随机推荐
- 使用Fiddler抓取手机请求
使用Fiddler抓取手机请求 Fiddler 手机 今天想尝试在手机上抓包,发现一个好玩的小工具——Fiddler. Fiddler是一个专门的抓包工具,可以模拟请求,修改请求,手机应用调试等.还是 ...
- 使用 Json.Net 对Json文本进行 增删改查
JSON 已经成为当前主流交互格式, 如何在C#中使用 Json.Net 对Json文本进行 增删改查呢?见如下代码 #region Create (从零创建) public static strin ...
- SQLServer中Partition By 函数的使用
今天群里看到一个问题,在这里概述下:查询出不同分类下的最新记录.一看这不是很简单的么,要分类那就用Group By;要最新记录就用Order By呗.然后在自己的表中试着做出来: 首先呢我把表中的数据 ...
- Oracle学习笔记一 初识Oracle
数据库简介 数据库(Database)是按照数据结构来组织.存储和管理数据的仓库.SQL 是 Structured Query Language(结构化查询语言)的首字母缩写词. 定义 数据库,简单来 ...
- 路由集合中已存在名为“ XXXX” 的路由
一般是认为路由的名字Key重复了,改下就行,但是还有种情况,你发现不是的,你把Key名称改了就好,不改就有问题.为什么?那就是有可能在bin目录下其它的DLL中有重复的Key了,这个时候,就要看看该改 ...
- OnDraw函数
本文仅用于学习交流,商业用途请支持正版!转载请注明:http://www.cnblogs.com/mxbs/p/6219428.html 方法一.对字符串直接赋值 在View类中定义了OnDraw函数 ...
- [LeetCode] Count Numbers with Unique Digits 计算各位不相同的数字个数
Given a non-negative integer n, count all numbers with unique digits, x, where 0 ≤ x < 10n. Examp ...
- [LeetCode] Remove Duplicates from Sorted Array 有序数组中去除重复项
Given a sorted array, remove the duplicates in place such that each element appear only once and ret ...
- 实现数据库的跨库join
功能需求 首先要理解原始需求是什么,为什么要跨库join.举个简单的例子,在日志数据库log_db有一份充值记录表pay_log,里面的用户信息只有一个userid:而用户的详细信息放在主库main_ ...
- JS组件系列——又一款MVVM组件:Vue(一:30分钟搞定前端增删改查)
前言:关于Vue框架,好几个月之前就听说过,了解一项新技术之后,总是处于观望状态,一直在犹豫要不要系统学习下.正好最近有点空,就去官网了解了下,看上去还不错的一个组件,就抽空研究了下.最近园子里vue ...