SVM支持向量机数学原理与代码实现

数学推导:


















Platt SMO 算法代码:

import numpy as np
import random

#SMO算法辅助函数
#加载数据
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 selectJrand(i,m):
    j=i
    while (j==i):
        j = int(random.uniform(0,m))
    return j
#约束条件下的alpha取值范围L<=alpha<=H
def clipAlpha(aj,H,L):
    if aj > H:
        aj = H
    if L > aj:
        aj = L
    return aj

#platt SMO的支持函数
class optStruct:
    def __init__(self,dataMatIn,classLabels,C,toler):
        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)))#误差缓存

def calcEk(oS,k):
    fXk = float(np.multiply(oS.alphas,oS.labelMat).T * (oS.X * oS.X[k,:].T)) + 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 = np.nonzero(oS.eCache[:,0].A)[0] #matrix.A 将矩阵类型转换为ndarray数据结构
    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

def updateEk(oS,k):
    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)
        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.X[i,:] * oS.X[j,:].T - oS.X[i,:]*oS.X[i,:].T - oS.X[j,:]*oS.X[j,:].T
        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.X[i,:]*oS.X[i,:].T - \
             oS.labelMat[j]*(oS.alphas[j]-alphaJold)*oS.X[i,:]*oS.X[j,:].T
        b2 = oS.b - Ej - oS.labelMat[i]*(oS.alphas[i]-alphaIold)*oS.X[i,:]*oS.X[j,:].T -\
            oS.labelMat[j]*(oS.alphas[j]-alphaJold)*oS.X[j,:]*oS.X[j,:].T
        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 smoP(dataMatIn,classLabels,C,toler,maxIter,kTup=('lin',0)):
    oS = optStruct(np.mat(dataMatIn),np.mat(classLabels).transpose(),C,toler)
    iter = 0
    entireSet = True
    alphaPairsChanged = 0
    while (iter < maxIter) and ((alphaPairsChanged > 0) or (entireSet)):
        alphaPairsChanged = 0
        if entireSet:
            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:
            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 calcWs(alphas,dataArr,classLabels):
    X = np.mat(dataArr)
    labelMat = np.mat(classLabels).transpose()
    m,n = np.shape(X)
    w = np.zeros((n,1))
    for i in range(m):
        w += np.multiply(alphas[i]*labelMat[i],X[i,:].T)
    return w

def Accurate(dataArr,labelArr,ws,b):
    datMat = np.mat(dataArr)
    m,n = np.shape(datMat)
    lab = []
    for i in range(m):
        result = datMat[i]*np.mat(ws) + b
        if result[0] > 0:
            lab.append(1)
        else:
            lab.append(-1)
    lab = np.array(lab)
    acc = np.mean(lab == labelArr)
    return acc


if __name__ == "__main__":
    filename = "testSet.txt"
    dataArr,labelArr = loadDataSet(filename)
    b,alphas = smoP(dataArr,labelArr,0.6,0.0001,40)
    ws = calcWs(alphas,dataArr,labelArr)
    print Accurate(dataArr,labelArr,ws,b)


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
支持向量机(Support Vector Machine, SVM)是一种常用于机器学习中的分类算法。其数学原理可以总结为以下几点: 1. 定义训练数据和标签:在SVM算法中,我们需要定义训练数据集的位置(xi)和对应的标签(yi)。这里的训练数据是指用于训练模型的输入样本,而标签是指每个训练样本所属的类别。 2. 线性可分思路:SVM算法的基本思想是将训练数据映射到一个高维空间,在这个空间中找到一个最优的超平面,使得不同类别的样本尽可能地分开。这个最优的超平面被称为分割超平面。 3. 支持向量和间隔:在SVM算法中,支持向量是离分割超平面最近的训练样本。支持向量的存在决定了分割超平面的位置和方向。而间隔是指分割超平面到最近的支持向量之间的距离。 4. 松弛变量:为了处理线性不可分的情况,SVM引入了松弛变量,允许一些样本距离分割超平面有一定的误差。这样可以避免这些样本对模型学习的影响。 5. 核函数:SVM算法可以通过使用核函数来实现非线性分类。核函数的作用是将低维输入空间映射到高维特征空间,从而使得原本线性不可分的样本在高维空间中线性可分。 6. 多分类问题:虽然SVM最初是用于二分类问题的,但也可以扩展到多分类问题。常用的方法包括一对一(OvO)和一对多(OvR)策略,通过多个二分类模型的组合来实现多分类。 总结起来,支持向量机算法利用训练数据和标签定义模型,通过找到一个最优的分割超平面来实现分类。它能够解决小样本情况下的机器学习问题,并通过核函数处理非线性分类。然而,SVM算法也存在一些缺点,比如对大规模训练样本的效率较低,对多分类问题的解决效果不理想,并且需要进行参数调优。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值