![ac452df5e307b86c6f61527c9b9da107.png](https://i-blog.csdnimg.cn/blog_migrate/91dd6e0d2801eeff49d5673186a51c16.jpeg)
一起探索机器学习
Machine learning
SVM
CSDN:
https://blog.csdn.net/weixin_45814668知乎:
https://www.zhihu.com/people/qiongjian0427Git:
https://github.com/qiongjian/Machine-learning/
运行环境:anaconda—jupyter notebook
Python版本:Python3
![648504be693b0e4c4b63fbc22abc23f7.png](https://i-blog.csdnimg.cn/blog_migrate/03df8cfcd1e9197dc6b23244a2e8761b.jpeg)
利用核函数将数据映射到高维空间
如上图所示,数据点处于一个圆中,人类的大脑能够意识到这一点,而对于分类器而言,它只能识别分类器的结果是大于0还是小于0。如果只在x和y轴构成的坐标系中插入直线进行分类的话,我们并不会得到理想的结果。我们或许可以对圆中的数据进行某种形式的转换,从而得到某些新的变量来表示数据。 将数据从一个特征空间转换到另一个特征空间,在新空间下,我们可以很容易利用已有的工具对数据进行处理,这个过程叫做从一个特征空间到另一个特征空间的映射。通常情况下,映射会将低维特征空间映射到高维特征空间。 这种从某个特征空间到另一个特征空间的映射是通过核函数来实现的。我们可以把核函数想象成一个包装器(wrapper)或者是接口(interface),它能把数据从某个很难处理的形式转换成为另一个较容易的处理的形式。 SVM优化中一个特别好的地方就是,所有的运算都可以写成内积(inner product,也称点积)的形式。向量的内积使之两个向量相乘,之后得到单个标量或者数值。我们可以把内积运算替换成核函数,而不必做简化处理。将内积替换成核函数的方式被称为核技巧(kernel trick)或者核“变电”(kernel substation)。
![593e0fee5695076b6b5339554bf2f0f2.png](https://i-blog.csdnimg.cn/blog_migrate/2d1356edebe8fa6aba4ecbc4bab04088.jpeg)
径向基核函数
径向基函数是SVM中常用的一个核函数。径向基函数是一个采用向量作为自变量的函数,能够基于向量距离运算输出一个标量。这个距离可以使从<0,0>向量或者其他向量开始计算的距离。径向基函数的高斯版本的具体公式为:代码如下:
import matplotlib.pyplot as pltimport numpy as npimport randomdef kernelTrans(X, A, kTup): m,n = np.shape(X) K = np.mat(np.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 =np.exp(K/(-1*kTup[1]**2)) else: raise NameError('Houston We Have a Problem -- That Kernel is not recognized') return Kclass optStruct: def __init__(self,dataMatIn, classLabels, C, toler, kTup): self.X = dataMatIn self.labelMat = classLabels self.C = C self.tol = toler self.m = np.shape(dataMatIn)[0] self.alphas = np.mat(np.zeros((self.m,1))) self.b = 0 self.eCache = np.mat(np.zeros((self.m,2))) self.K = np.mat(np.zeros((self.m,self.m))) for i in range(self.m): #计算所有数据的核K self.K[:,i] = kernelTrans(self.X, self.X[i,:], kTup)
![ec22917cdcfb4b2f55c366ab420eb5d3.png](https://i-blog.csdnimg.cn/blog_migrate/588a8e4a54ae2d2afc55b7ca2f6c93b8.png)
对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)): j,Ej = selectJ(i, oS, Ei) alphaIold = oS.alphas[i].copy(); alphaJold = oS.alphas[j].copy(); 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 = 2.0 * oS.K[i,j] - oS.K[i,i].T - oS.K[j,j] if eta >= 0: print("eta>=0"); return 0 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 not moving enough"); return 0 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
![6af21649eb43b6a00df6c44e1a5be040.png](https://i-blog.csdnimg.cn/blog_migrate/ce0b410a882cce1978950dbddb92bad5.jpeg)
在测试中使用核函数
♥
def testRbf(k1=1.3): dataArr,labelArr = loadDataSet('testSetRBF.txt') b,alphas = smoP(dataArr, labelArr, 200, 0.0001, 10000, ('rbf', k1)) datMat=np.mat(dataArr); labelMat = np.mat(labelArr).transpose() svInd=np.nonzero(alphas.A>0)[0] sVs=datMat[svInd] #get matrix of only support vectors labelSV = labelMat[svInd]; print("there are %d Support Vectors" % np.shape(sVs)[0]) m,n = np.shape(datMat) errorCount = 0 for i in range(m): kernelEval = kernelTrans(sVs,datMat[i,:],('rbf', k1)) predict=kernelEval.T * np.multiply(labelSV,alphas[svInd]) + b if np.sign(predict)!=np.sign(labelArr[i]): errorCount += 1 print("the training error rate is: %f" % (float(errorCount)/m)) dataArr,labelArr = loadDataSet('testSetRBF2.txt') errorCount = 0 datMat=np.mat(dataArr); labelMat = np.mat(labelArr).transpose() m,n = np.shape(datMat) for i in range(m): kernelEval = kernelTrans(sVs,datMat[i,:],('rbf', k1)) predict=kernelEval.T * np.multiply(labelSV,alphas[svInd]) + b if np.sign(predict)!=np.sign(labelArr[i]): errorCount += 1 print("the test error rate is: %f" % (float(errorCount)/m))
用到的前面的函数
♥
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 smoP(dataMatIn, classLabels, C, toler, maxIter, kTup = ('lin',0)): oS = optStruct(np.mat(dataMatIn), np.mat(classLabels).transpose(), C, toler, kTup) iter = 0 entireSet = True; alphaPairsChanged = 0 #如果迭代字数大于最大迭代数,或者遍历完整个集合还没有找到一对i和j可以优化,那么退出迭代 while (iter < maxIter) and ((alphaPairsChanged > 0) or (entireSet)): alphaPairsChanged = 0 if entireSet: #遍历所有的值 for i in range(oS.m): alphaPairsChanged += innerL(i,oS) #innerL第二个选择alpha print("fullSet, iter: %d i:%d, pairs changed %d" % (iter,i,alphaPairsChanged)) iter += 1 else:#遍历非边界值 nonBoundIs = np.nonzero((oS.alphas.A > 0) * (oS.alphas.A < C))[0] for i in nonBoundIs: alphaPairsChanged += innerL(i,oS) print("non-bound, iter: %d i:%d, pairs changed %d" % (iter,i,alphaPairsChanged)) iter += 1 if entireSet: entireSet = False elif (alphaPairsChanged == 0): entireSet = True print("iteration number: %d" % iter) return oS.b,oS.alphas
♥
def calcEk(oS, k): fXk = float(np.multiply(oS.alphas,oS.labelMat).T*(oS.K[:,k])) + oS.b Ek = fXk - float(oS.labelMat[k]) return Ekdef selectJ(i, oS, Ei):#选择第二个alpha maxK = -1; maxDeltaE = 0; Ej = 0 oS.eCache[i] = [1,Ei] validEcacheList = np.nonzero(oS.eCache[:,0].A)[0]#构建一个非零表 if (len(validEcacheList)) > 1: for k in validEcacheList: if k == i: continue Ek = calcEk(oS, k) deltaE = abs(Ei - Ek) if (deltaE > maxDeltaE): maxK = k; maxDeltaE = deltaE; Ej = Ek return maxK, Ej else: j = selectJrand(i, oS.m) Ej = calcEk(oS, j) return j, Ej#辅助函数1,随机选择一个整数def selectJrand(i, m):#i是alpha下标,m是alpha个数 j = i while (j == i): j = int(random.uniform(0, m)) return j#辅助函数2,调整大于H或小于L的alpha值def clipAlpha(aj,H,L): if aj > H: aj = H if L > aj: aj = L return aj
♥
def updateEk(oS, k):#计算误差值并返回缓存中 Ek = calcEk(oS, k) oS.eCache[k] = [1,Ek]
![a099b84e0a98a30f0ff129157908c1a9.png](https://i-blog.csdnimg.cn/blog_migrate/50f3fc707e32059bd45d401b9d9372d0.jpeg)
运行结果
训练集错误率为9%,测试集错误率都是18%,训练耗时1.7s,26个支持向量。
闹钟一响就起
走了就不回头
开开心心
![3edd15215e4887fcaca7f73ab3a6a328.png](https://i-blog.csdnimg.cn/blog_migrate/aff66e5c389eed89afdee0d5415ce837.jpeg)
ID:qiongjian0427
关注我,一起学习机器学习~