京公网安备 11010802034615号
经营许可证编号:京B2-20210330
今天跟大家介绍的是SVM算法原理以及实现,废话不多说,直接来看干货吧!
一、SVM概念
SVM的全称为Support Vector Machine,也就是我们经常提到的支持向量机,主要被用来解决模式识别领域中的数据分类问题,是一种有监督学习算法。
具体解释一下:
Support Vector,支持向量,指的是训练样本集中的某些训练点,这些训练点非常靠近分类决策面,因此是最难分类的数据点。SVM中最优分类标准为:这些点与分类超平面之间的距离达到最大值;
Machine“机”,指的是机器学习领域对一些算法的统称,通常我们把算法看做一个机器或学习函数。SVM是一种有监督的学习方法,主要是针对小样本数据的学习、分类和预测。
二、SVM的优点
1、需要的样本数量不是很大,但这并不表示SVM训练样本的绝对量很少,只是说与其他训练分类算法相比,在同样的问题复杂度情况下,SVM对样本的需求相对是较少的。而且SVM引入了核函数,因此即使是高维的样本,SVM也能轻松应对。
2、结构风险最小。这种风险指的是分类器对问题真实模型的逼近,以及问题真实解之间的累积误差。
3、非线性,指的是:SVM非常擅长应付样本数据线性不可分的情况,通常是利用松弛变量(或者叫惩罚变量)以及核函数技术来实现的,这也是SVM的精髓所在。
三、SVM的原理
1.点到超平面的距离公式
超平面的方程也可以写成一下形式:
假设P(x1.x2...xn)为样本的中的一个点,其中xi表示为第个特征变量。那么该点到超平面的距离d就可以用如下公式进行计算:
其中||w||为超平面的2范数,也就是w向量的模长,常数b类似于直线方程中的截距。
2.最大间隔的优化模型
其中y代表数据点的标签,并且其为-1或1.若数据点在平面的正方向(也就是+1类),那么就是一个正数,而如果数据点在平面的负方向的情况下(即-1类),仍然是一个正数,这样就可以保证始终大于0了。我们需要注意,如果w和b等比例放大,d的结果不会改变。令u=y(wTx+b),所有支持向量的u为1.那么其他点的u大于1.我们可以通过调节w和b求到。这样一来,上面的问题可以简化为:
等价替换为:
这是一个有约束条件的优化问题,我们通常会用拉格朗日乘子法来求解。令:
四、python实现
#svm算法的实现 from numpy import* import random from time import* def loadDataSet(fileName):#输出dataArr(m*n),labelArr(1*m)其中m为数据集的个数 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):#随机找一个和i不同的j j=i while(j==i): j=int(random.uniform(0,m)) return j def clipAlpha(aj,H,L):#调整大于H或小于L的alpha的值 if aj>H: aj=H if aj<L: aj=L return aj def smoSimple(dataMatIn,classLabels,C,toler,maxIter): dataMatrix=mat(dataMatIn);labelMat=mat(classLabels).transpose()#转置 b=0;m,n=shape(dataMatrix)#m为输入数据的个数,n为输入向量的维数 alpha=mat(zeros((m,1)))#初始化参数,确定m个alpha iter=0#用于计算迭代次数 while (iter<maxIter):#当迭代次数小于最大迭代次数时(外循环) alphaPairsChanged=0#初始化alpha的改变量为0 for i in range(m):#内循环 fXi=float(multiply(alpha,labelMat).T*\ (dataMatrix*dataMatrix[i,:].T))+b#计算f(xi) Ei=fXi-float(labelMat[i])#计算f(xi)与标签之间的误差 if ((labelMat[i]*Ei<-toler)and(alpha[i]<C))or\ ((labelMat[i]*Ei>toler)and(alpha[i]>0)):#如果可以进行优化 j=selectJrand(i,m)#随机选择一个j与i配对 fXj=float(multiply(alpha,labelMat).T*\ (dataMatrix*dataMatrix[j,:].T))+b#计算f(xj) Ej=fXj-float(labelMat[j])#计算j的误差 alphaIold=alpha[i].copy()#保存原来的alpha(i) alphaJold=alpha[j].copy() if(labelMat[i]!=labelMat[j]):#保证alpha在0到c之间 L=max(0,alpha[j]-alpha[i]) H=min(C,C+alpha[j]-alpha[i]) else: L=max(0,alpha[j]+alpha[i]-C) H=min(C,alpha[j]+alpha[i]) if L==H:print('L=H');continue eta=2*dataMatrix[i,:]*dataMatrix[j,:].T-\ dataMatrix[i,:]*dataMatrix[i,:].T-\ dataMatrix[j,:]*dataMatrix[j,:].T if eta>=0:print('eta=0');continue alpha[j]-=labelMat[j]*(Ei-Ej)/eta alpha[j]=clipAlpha(alpha[j],H,L)#调整大于H或小于L的alpha if (abs(alpha[j]-alphaJold)<0.0001): print('j not move enough');continue alpha[i]+=labelMat[j]*labelMat[i]*(alphaJold-alpha[j]) b1=b-Ei-labelMat[i]*(alpha[i]-alphaIold)*\ dataMatrix[i,:]*dataMatrix[i,:].T-\ labelMat[j]*(alpha[j]-alphaJold)*\ dataMatrix[i,:]*dataMatrix[j,:].T#设置b b2=b-Ej-labelMat[i]*(alpha[i]-alphaIold)*\ dataMatrix[i,:]*dataMatrix[i,:].T-\ labelMat[j]*(alpha[j]-alphaJold)*\ dataMatrix[j,:]*dataMatrix[j,:].T if (0<alpha[i])and(C>alpha[j]):b=b1 elif(0<alpha[j])and(C>alpha[j]):b=b2 else:b=(b1+b2)/2 alphaPairsChanged+=1 print('iter:%d i:%d,pairs changed%d'%(iter,i,alphaPairsChanged)) if (alphaPairsChanged==0):iter+=1 else:iter=0 print('iteraction number:%d'%iter) return b,alpha #定义径向基函数 def kernelTrans(X, A, kTup):#定义核转换函数(径向基函数) m,n = shape(X) K = mat(zeros((m,1))) if kTup[0]=='lin': K = X * A.T #线性核K为m*1的矩阵 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)) #divide in NumPy is element-wise not matrix like Matlab 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): # 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): maxK = -1; maxDeltaE = 0; Ej = 0 oS.eCache[i] = [1,Ei] 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 #don't calc for i, waste of time Ek = calcEk(oS, k) deltaE = abs(Ei - Ek) if (deltaE > maxDeltaE): 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):#after any alpha has changed update the new value in the cache Ek = calcEk(oS, k) oS.eCache[k] = [1,Ek] 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) #this has been changed from selectJrand 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] - oS.K[j,j] #changed for kernel 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) #added this for the Ecache 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) #added this for the Ecache #the update is in the oppostie direction 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 #smoP函数用于计算超平的alpha,b def smoP(dataMatIn, classLabels, C, toler, maxIter,kTup=('lin', 0)): #完整的Platter SMO oS = optStruct(mat(dataMatIn),mat(classLabels).transpose(),C,toler, kTup) iter = 0#计算循环的次数 entireSet = True; alphaPairsChanged = 0 while (iter < maxIter) and ((alphaPairsChanged > 0) or (entireSet)): alphaPairsChanged = 0 if entireSet: #go over all for i in range(oS.m): alphaPairsChanged += innerL(i,oS) print("fullSet, iter: %d i:%d, pairs changed %d" % (iter,i,alphaPairsChanged)) iter += 1 else:#go over non-bound (railed) alphas nonBoundIs = 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 #toggle entire set loop elif (alphaPairsChanged == 0): entireSet = True print("iteration number: %d" % iter) return oS.b,oS.alphas #calcWs用于计算权重值w def calcWs(alphas,dataArr,classLabels):#计算权重W 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 #值得注意的是测试准确与k1和C的取值有关。 def testRbf(k1=1.3):#给定输入参数K1 #测试训练集上的准确率 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]#找出alphas中大于0的元素的位置 #此处需要说明一下alphas.A的含义 sVs=datMat[svInd] #获取支持向量的矩阵,因为只要alpha中不等于0的元素都是支持向量 labelSV = labelMat[svInd]#支持向量的标签 print("there are %d Support Vectors" % shape(sVs)[0])#输出有多少个支持向量 m,n = shape(datMat)#数据组的矩阵形状表示为有m个数据,数据维数为n errorCount = 0#计算错误的个数 for i in range(m):#开始分类,是函数的核心 kernelEval = kernelTrans(sVs,datMat[i,:],('rbf', k1))#计算原数据集中各元素的核值 predict=kernelEval.T * multiply(labelSV,alphas[svInd]) + b#计算预测结果y的值 if sign(predict)!=sign(labelArr[i]): errorCount += 1#利用符号判断类别 ### sign(a)为符号函数:若a>0则输出1,若a<0则输出-1.### print("the training error rate is: %f" % (float(errorCount)/m)) #2、测试测试集上的准确率 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 main(): t1=time() dataArr,labelArr=loadDataSet('testSet.txt') b,alphas=smoP(dataArr,labelArr,0.6,0.01,40) ws=calcWs(alphas,dataArr,labelArr) testRbf() t2=time() print("程序所用时间为%ss"%(t2-t1)) if __name__=='__main__': main()
数据分析咨询请扫描二维码
若不方便扫码,搜微信号:CDAshujufenxi
Python凭借简洁的语法、丰富的生态库,成为算法开发、数据处理、机器学习等领域的首选语言。但受限于动态类型、解释性执行的特性 ...
2026-04-03在深度学习神经网络中,卷积操作是实现数据特征提取的核心引擎,更是让模型“看懂”数据、“解读”数据的关键所在。不同于传统机 ...
2026-04-03当数字化转型从企业的“战略口号”落地为“生存之战”,越来越多的企业意识到,转型的核心并非技术的堆砌,而是数据价值的深度挖 ...
2026-04-03在日常办公数据分析中,数据透视表凭借高效的汇总、分组功能,成为Excel、WPS等办公软件中最常用的数据分析工具之一。其中,“计 ...
2026-04-02在数字化交互的全场景中,用户的每一次操作都在生成动态的行为轨迹——电商用户的“浏览商品→点击详情→加入购物车”,内容APP ...
2026-04-02在数字化转型深度推进的今天,企业数据已成为驱动业务增长、构建核心竞争力的战略资产,而数据安全则是守护这份资产的“生命线” ...
2026-04-02在数据驱动决策的浪潮中,数据挖掘与数据分析是两个高频出现且极易被混淆的概念。有人将二者等同看待,认为“做数据分析就是做数 ...
2026-04-01在数据驱动决策的时代,企业与从业者每天都会面对海量数据——电商平台的用户行为数据、金融机构的信贷风险数据、快消品牌的营销 ...
2026-04-01在数字化转型的浪潮中,企业数据已从“辅助运营的附属资源”升级为“驱动增长的核心资产”,而一套科学、可落地的企业数据管理方 ...
2026-04-01在数字化时代,每一位用户与产品的交互都会留下可追溯的行为轨迹——电商用户的浏览、加购、下单,APP用户的注册、登录、功能使 ...
2026-03-31在日常数据统计、市场调研、学术分析等场景中,我们常常需要判断两个分类变量之间是否存在关联(如性别与消费偏好、产品类型与满 ...
2026-03-31在CDA(Certified Data Analyst)数据分析师的职场实战与认证考核中,“可解释性建模”是核心需求之一——企业决策中,不仅需要 ...
2026-03-31多层感知机(MLP,Multilayer Perceptron)作为深度学习中最基础、最经典的神经网络模型,其结构设计直接决定了模型的拟合能力、 ...
2026-03-30在TensorFlow深度学习实战中,数据集的加载与预处理是基础且关键的第一步。手动下载、解压、解析数据集不仅耗时费力,还容易出现 ...
2026-03-30在CDA(Certified Data Analyst)数据分析师的日常工作中,“无监督分组、挖掘数据内在聚类规律”是高频核心需求——电商场景中 ...
2026-03-30机器学习的本质,是让模型通过对数据的学习,自主挖掘规律、实现预测与决策,而这一过程的核心驱动力,并非单一参数的独立作用, ...
2026-03-27在SQL Server数据库操作中,日期时间处理是高频核心需求——无论是报表统计中的日期格式化、数据筛选时的日期类型匹配,还是业务 ...
2026-03-27在CDA(Certified Data Analyst)数据分析师的能力体系与职场实操中,高维数据处理是高频且核心的痛点——随着业务场景的复杂化 ...
2026-03-27在机器学习建模与数据分析实战中,特征维度爆炸、冗余信息干扰、模型泛化能力差是高频痛点。面对用户画像、企业经营、医疗检测、 ...
2026-03-26在这个数据无处不在的时代,数据分析能力已不再是数据从业者的专属技能,而是成为了职场人、管理者、创业者乃至个人发展的核心竞 ...
2026-03-26