对于线性不可分的数据集,可以利用核函数(kernel)将数据转换成易于分类器理解的形式。

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

  这种从某个特征空间到另一个特征空间的映射是通过核函数来。

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

径向基核函数

径向基核函数是SVM中常用的一个核函数径向基函数是一个采用向量作为自变量的函数,能够基于向量距离运算输出一个标量

  1. '''#######********************************
  2. 以下是有核函数的版本
  3. '''#######********************************
  4. class optStruct:
  5. def __init__(self,dataMatIn, classLabels, C, toler, kTup): # Initialize the structure with the parameters
  6. self.X = dataMatIn
  7. self.labelMat = classLabels
  8. self.C = C
  9. self.tol = toler
  10. self.m = shape(dataMatIn)[0]
  11. self.alphas = mat(zeros((self.m,1)))
  12. self.b = 0
  13. self.eCache = mat(zeros((self.m,2))) #first column is valid flag
  14. self.K = mat(zeros((self.m,self.m)))
  15. for i in range(self.m):
  16. self.K[:,i] = kernelTrans(self.X, self.X[i,:], kTup)
  17.  
  18. def calcEk(oS, k): #计算误差
  19. fXk = float(multiply(oS.alphas,oS.labelMat).T*oS.K[:,k] + oS.b)
  20. Ek = fXk - float(oS.labelMat[k])
  21. return Ek
  22.  
  23. def selectJ(i, oS, Ei): #用于选择第2个循环(内循环)的alpha值,内循环中的启发式方法
  24. maxK = -1; maxDeltaE = 0; Ej = 0
  25. oS.eCache[i] = [1,Ei] #set valid #choose the alpha that gives the maximum delta E
  26. validEcacheList = nonzero(oS.eCache[:,0].A)[0]
  27. if (len(validEcacheList)) > 1:
  28. for k in validEcacheList: #loop through valid Ecache values and find the one that maximizes delta E
  29. if k == i: continue #跳过本身
  30. Ek = calcEk(oS, k)
  31. deltaE = abs(Ei - Ek)
  32. if (deltaE > maxDeltaE): #选取具有最大步长的j
  33. maxK = k; maxDeltaE = deltaE; Ej = Ek
  34. return maxK, Ej
  35. else: #in this case (first time around) we don't have any valid eCache values
  36. j = selectJrand(i, oS.m)
  37. Ej = calcEk(oS, j)
  38. return j, Ej
  39.  
  40. def updateEk(oS, k): #alpha改变后,更新缓存
  41. Ek = calcEk(oS, k)
  42. oS.eCache[k] = [1,Ek]
  43.  
  44. #内部循环的代码和简版的SMO代码很相似
  45. def innerL(i, oS):
  46. Ei = calcEk(oS, i)
  47. #判断每一个alpha是否被优化过,如果误差很大,就对该alpha值进行优化,toler是容错率
  48. 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)):
  49. j,Ej = selectJ(i, oS, Ei) #使用启发式方法选取第2个alpha,选取使得误差最大的alpha
  50. alphaIold = oS.alphas[i].copy(); alphaJold = oS.alphas[j].copy();
  51. #保证alpha在0与C之间
  52. if (oS.labelMat[i] != oS.labelMat[j]): #当y1和y2异号,计算alpha的取值范围
  53. L = max(0, oS.alphas[j] - oS.alphas[i])
  54. H = min(oS.C, oS.C + oS.alphas[j] - oS.alphas[i])
  55. else: #当y1和y2同号,计算alpha的取值范围
  56. L = max(0, oS.alphas[j] + oS.alphas[i] - oS.C)
  57. H = min(oS.C, oS.alphas[j] + oS.alphas[i])
  58. if L==H: print "L==H"; return 0
  59. #eta是alpha[j]的最优修改量,eta=K11+K22-2*K12,也是f(x)的二阶导数,K表示核函数
  60. eta = 2.0 * oS.K[i,j] - oS.K[i,i] - oS.K[j,j] #changed for kernel
  61. #如果二阶导数-eta <= 0,说明一阶导数没有最小值,就不做任何改变,本次循环结束直接运行下一次for循环
  62. if eta >= 0: print "eta>=0"; return 0
  63. oS.alphas[j] -= oS.labelMat[j]*(Ei - Ej)/eta #利用公式更新alpha[j],alpha2new=alpha2-yj(Ei-Ej)/eta
  64. oS.alphas[j] = clipAlpha(oS.alphas[j],H,L) #判断alpha的范围是否在0和C之间
  65. updateEk(oS, j) #在alpha改变的时候更新Ecache
  66. print "j=",j
  67. print oS.alphas.A[j]
  68. #如果alphas[j]没有调整,就忽略下面语句,本次循环结束直接运行下一次for循环
  69. if (abs(oS.alphas[j] - alphaJold) < 0.00001): print "j not moving enough"; return 0
  70. oS.alphas[i] += oS.labelMat[j]*oS.labelMat[i]*(alphaJold - oS.alphas[j])#update i by the same amount as j
  71. updateEk(oS, i) #在alpha改变的时候更新Ecache
  72. print "i=",i
  73. print oS.alphas.A[i]
  74. #已经计算出了alpha,接下来根据模型的公式计算b
  75. 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]
  76. 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]
  77. #根据公式确定偏移量b,理论上可选取任意支持向量来求解,但是现实任务中通常使用所有支持向量求解的平均值,这样更加鲁棒
  78. if (0 < oS.alphas[i]) and (oS.C > oS.alphas[i]): oS.b = b1
  79. elif (0 < oS.alphas[j]) and (oS.C > oS.alphas[j]): oS.b = b2
  80. else: oS.b = (b1 + b2)/2.0
  81. return 1 #如果有任意一对alpha发生改变,返回1
  82. else: return 0
  83.  
  84. #完整版Platt SMO的外循环
  85. def smoP(dataMatIn, classLabels, C, toler, maxIter,kTup=('lin', 0)):
  86. oS = optStruct(mat(dataMatIn),mat(classLabels).transpose(),C,toler, kTup)
  87. iter = 0
  88. entireSet = True; alphaPairsChanged = 0
  89. while (iter < maxIter) and ((alphaPairsChanged > 0) or (entireSet)): #有alpha改变同时遍历次数小于最大次数,或者需要遍历整个集合
  90. alphaPairsChanged = 0
  91. #首先进行完整遍历,过程和简化版的SMO一样
  92. if entireSet:
  93. for i in range(oS.m):
  94. alphaPairsChanged += innerL(i,oS) #i是第1个alpha的下标
  95. print "完整遍历, 迭代次数: %d i:%d, 成对改变的次数 %d" % (iter,i,alphaPairsChanged)
  96. iter += 1
  97. #非边界遍历,挑选其中alpha值在0和C之间非边界alpha进行优化
  98. else:
  99. nonBoundIs = nonzero((oS.alphas.A > 0) * (oS.alphas.A < C))[0] #然后挑选其中值在0和C之间的非边界alpha进行遍历
  100. for i in nonBoundIs:
  101. alphaPairsChanged += innerL(i,oS)
  102. print "非边界, 迭代次数: %d i:%d, 成对改变的次数 %d" % (iter,i,alphaPairsChanged)
  103. iter += 1
  104. #如果这次是完整遍历的话,下次不用进行完整遍历
  105. if entireSet: entireSet = False #终止完整循环
  106. elif (alphaPairsChanged == 0): entireSet = True #如果alpha的改变数量为0的话,再次遍历所有的集合一次
  107. print "iteration number: %d" % iter
  108. return oS.b,oS.alphas
  109.  
  110. def calcWs(alphas,dataArr,classLabels): #计算模型的参数w,即alpha*y*x转置的累加
  111. X = mat(dataArr); labelMat = mat(classLabels).transpose()
  112. m,n = shape(X)
  113. w = zeros((n,1))
  114. for i in range(m):
  115. w += multiply(alphas[i]*labelMat[i],X[i,:].T)
  116. return w
  117.  
  118. def testRbf(k1=1.3):
  119. dataArr,labelArr = loadDataSet('testSetRBF.txt')
  120. b,alphas = smoP(dataArr, labelArr, 200, 0.0001, 10000, ('rbf', k1)) #C=200 important
  121. datMat=mat(dataArr); labelMat = mat(labelArr).transpose()
  122. svInd=nonzero(alphas.A>0)[0]
  123. sVs=datMat[svInd] #get matrix of only support vectors
  124. labelSV = labelMat[svInd];
  125. print "there are %d Support Vectors" % shape(sVs)[0]
  126. m,n = shape(datMat)
  127. errorCount = 0
  128. for i in range(m):
  129. kernelEval = kernelTrans(sVs,datMat[i,:],('rbf', k1))
  130. predict=kernelEval.T * multiply(labelSV,alphas[svInd]) + b
  131. if sign(predict)!=sign(labelArr[i]): errorCount += 1
  132. print "the training error rate is: %f" % (float(errorCount)/m)
  133. dataArr,labelArr = loadDataSet('testSetRBF2.txt')
  134. errorCount = 0
  135. datMat=mat(dataArr); labelMat = mat(labelArr).transpose()
  136. m,n = shape(datMat)
  137. for i in range(m):
  138. kernelEval = kernelTrans(sVs,datMat[i,:],('rbf', k1))
  139. predict=kernelEval.T * multiply(labelSV,alphas[svInd]) + b
  140. if sign(predict)!=sign(labelArr[i]): errorCount += 1
  141. print "the test error rate is: %f" % (float(errorCount)/m)
  142.  
  143. def img2vector(filename):
  144. returnVect = zeros((1,1024))
  145. fr = open(filename)
  146. for i in range(32):
  147. lineStr = fr.readline()
  148. for j in range(32):
  149. returnVect[0,32*i+j] = int(lineStr[j])
  150. return returnVect
  151.  
  152. def loadImages(dirName):
  153. from os import listdir
  154. hwLabels = []
  155. trainingFileList = listdir(dirName) #load the training set
  156. m = len(trainingFileList)
  157. trainingMat = zeros((m,1024))
  158. for i in range(m):
  159. fileNameStr = trainingFileList[i]
  160. fileStr = fileNameStr.split('.')[0] #take off .txt
  161. classNumStr = int(fileStr.split('_')[0])
  162. if classNumStr == 9: hwLabels.append(-1)
  163. else: hwLabels.append(1)
  164. trainingMat[i,:] = img2vector('%s/%s' % (dirName, fileNameStr))
  165. return trainingMat, hwLabels
  166.  
  167. def testDigits(kTup=('rbf', 10)):
  168. dataArr,labelArr = loadImages('trainingDigits')
  169. b,alphas = smoP(dataArr, labelArr, 200, 0.0001, 10000, kTup)
  170. datMat=mat(dataArr); labelMat = mat(labelArr).transpose()
  171. svInd=nonzero(alphas.A>0)[0]
  172. sVs=datMat[svInd]
  173. labelSV = labelMat[svInd];
  174. print "there are %d Support Vectors" % shape(sVs)[0]
  175. m,n = shape(datMat)
  176. errorCount = 0
  177. for i in range(m):
  178. kernelEval = kernelTrans(sVs,datMat[i,:],kTup)
  179. predict=kernelEval.T * multiply(labelSV,alphas[svInd]) + b
  180. if sign(predict)!=sign(labelArr[i]): errorCount += 1
  181. print "the training error rate is: %f" % (float(errorCount)/m)
  182. dataArr,labelArr = loadImages('testDigits')
  183. errorCount = 0
  184. datMat=mat(dataArr); labelMat = mat(labelArr).transpose()
  185. m,n = shape(datMat)
  186. for i in range(m):
  187. kernelEval = kernelTrans(sVs,datMat[i,:],kTup)
  188. predict=kernelEval.T * multiply(labelSV,alphas[svInd]) + b
  189. if sign(predict)!=sign(labelArr[i]): errorCount += 1
  190. print "the test error rate is: %f" % (float(errorCount)/m)

机器学习——支持向量机(SVM)之核函数(kernel)的更多相关文章

  1. [白话解析] 深入浅出支持向量机(SVM)之核函数

    [白话解析] 深入浅出支持向量机(SVM)之核函数 0x00 摘要 本文在少用数学公式的情况下,尽量仅依靠感性直觉的思考来讲解支持向量机中的核函数概念,并且给大家虚构了一个水浒传的例子来做进一步的通俗 ...

  2. 机器学习——支持向量机SVM

    前言 学习本章节前需要先学习: <机器学习--最优化问题:拉格朗日乘子法.KKT条件以及对偶问题> <机器学习--感知机> 1 摘要: 支持向量机(SVM)是一种二类分类模型, ...

  3. coursera机器学习-支持向量机SVM

    #对coursera上Andrew Ng老师开的机器学习课程的笔记和心得: #注:此笔记是我自己认为本节课里比较重要.难理解或容易忘记的内容并做了些补充,并非是课堂详细笔记和要点: #标记为<补 ...

  4. 机器学习支持向量机SVM笔记

    SVM简述: SVM是一个线性二类分类器,当然通过选取特定的核函数也可也建立一个非线性支持向量机.SVM也可以做一些回归任务,但是它预测的时效性不是太长,他通过训练只能预测比较近的数据变化,至于再往后 ...

  5. 吴裕雄 python 机器学习——支持向量机SVM非线性分类SVC模型

    import numpy as np import matplotlib.pyplot as plt from sklearn import datasets, linear_model,svm fr ...

  6. 机器学习——支持向量机(SVM)之拉格朗日乘子法,KKT条件以及简化版SMO算法分析

    SVM有很多实现,现在只关注其中最流行的一种实现,即序列最小优化(Sequential Minimal Optimization,SMO)算法,然后介绍如何使用一种核函数(kernel)的方式将SVM ...

  7. 机器学习-支持向量机SVM

    简介: 支持向量机(SVM)是一种二分类的监督学习模型,他的基本模型是定义在特征空间上的间隔最大的线性模型.他与感知机的区别是,感知机只要找到可以将数据正确划分的超平面即可,而SVM需要找到间隔最大的 ...

  8. 机器学习:SVM(核函数、高斯核函数RBF)

    一.核函数(Kernel Function) 1)格式 K(x, y):表示样本 x 和 y,添加多项式特征得到新的样本 x'.y',K(x, y) 就是返回新的样本经过计算得到的值: 在 SVM 类 ...

  9. 机器学习——支持向量机(SVM)

    支持向量机原理 支持向量机要解决的问题其实就是寻求最优分类边界.且最大化支持向量间距,用直线或者平面,分隔分隔超平面. 基于核函数的升维变换 通过名为核函数的特征变换,增加新的特征,使得低维度空间中的 ...

随机推荐

  1. 使用Fiddler抓取手机请求

    使用Fiddler抓取手机请求 Fiddler 手机 今天想尝试在手机上抓包,发现一个好玩的小工具——Fiddler. Fiddler是一个专门的抓包工具,可以模拟请求,修改请求,手机应用调试等.还是 ...

  2. 使用 Json.Net 对Json文本进行 增删改查

    JSON 已经成为当前主流交互格式, 如何在C#中使用 Json.Net 对Json文本进行 增删改查呢?见如下代码 #region Create (从零创建) public static strin ...

  3. SQLServer中Partition By 函数的使用

    今天群里看到一个问题,在这里概述下:查询出不同分类下的最新记录.一看这不是很简单的么,要分类那就用Group By;要最新记录就用Order By呗.然后在自己的表中试着做出来: 首先呢我把表中的数据 ...

  4. Oracle学习笔记一 初识Oracle

    数据库简介 数据库(Database)是按照数据结构来组织.存储和管理数据的仓库.SQL 是 Structured Query Language(结构化查询语言)的首字母缩写词. 定义 数据库,简单来 ...

  5. 路由集合中已存在名为“ XXXX” 的路由

    一般是认为路由的名字Key重复了,改下就行,但是还有种情况,你发现不是的,你把Key名称改了就好,不改就有问题.为什么?那就是有可能在bin目录下其它的DLL中有重复的Key了,这个时候,就要看看该改 ...

  6. OnDraw函数

    本文仅用于学习交流,商业用途请支持正版!转载请注明:http://www.cnblogs.com/mxbs/p/6219428.html 方法一.对字符串直接赋值 在View类中定义了OnDraw函数 ...

  7. [LeetCode] Count Numbers with Unique Digits 计算各位不相同的数字个数

    Given a non-negative integer n, count all numbers with unique digits, x, where 0 ≤ x < 10n. Examp ...

  8. [LeetCode] Remove Duplicates from Sorted Array 有序数组中去除重复项

    Given a sorted array, remove the duplicates in place such that each element appear only once and ret ...

  9. 实现数据库的跨库join

    功能需求 首先要理解原始需求是什么,为什么要跨库join.举个简单的例子,在日志数据库log_db有一份充值记录表pay_log,里面的用户信息只有一个userid:而用户的详细信息放在主库main_ ...

  10. JS组件系列——又一款MVVM组件:Vue(一:30分钟搞定前端增删改查)

    前言:关于Vue框架,好几个月之前就听说过,了解一项新技术之后,总是处于观望状态,一直在犹豫要不要系统学习下.正好最近有点空,就去官网了解了下,看上去还不错的一个组件,就抽空研究了下.最近园子里vue ...