svm

版权声明:ˋ( ° ▽、° )  ̄へ ̄ https://blog.csdn.net/acm_fighting/article/details/61429047
  • 优点:泛化错误率低,计算开销不大,结果易解释
  • 缺点:对参数调节和核函数的选择敏感,原始分类器不加修改仅适用于处理二类问题。
  • 适用数据类型:数值型和标称型数据。

拉格朗日乘子法

求在约束条件gj(x1,x2,...,xn)=0的条件下,求f(x1,x2,...,xn)

引进拉格朗日乘子a;建立方程
L(x1,x2,...,xn,a1,a2,...,am)=f(x1,x2,...,xn)+mj=1ajgj(x1,x2,...,xn)

建立n+m个函数的无约束条件的极值,即分别对x1,x2,...,xn,a1,a2,...,an求导

KTT条件
gj(x1,x2,...,xn)=0或者gj(x1,x2,...,xn)<=0
或者gj(x1,x2,...,xn)>=0可以转化为小于号约束,等号约束

L(x,α)=f(x)+αigi(x)+βihi(x)
其中g是不等式约束,h是等式约束,那么KKT条件就是函数的最优值必定满足下面条件:

  1. L对各个x求导为0;
  2. h(x)=0;
  3. αigi(x)=0

构造分析器的原理
如果数据点离决策边界越远,’那么其最后的预测结果也就越可信。
支持向量(support vector):离分隔超平面最近的那些点。(距离:指垂直于直线的点与当前点的距离)

目标函数

min1/2WTW
s.t.yi(Wxi+b)>=1

后续公式推导

svm的一般流程

  1. 收集数据:可以使用任意方法。
  2. 准备数据:需要数值型数据。
  3. 分析数据:有助于可视化分隔超平面。
  4. 训练算法:svm的大部分时间都源自训练,该过程主要实现两个参数的调优。
  5. 测试算法:十分简单的计算过程就可以实现。
  6. 使用算法:几乎所有分类问题都可以使用SVM,值得一提的是,SVM 本身是一个二类分类器,对多类问题应用SVM需要对代码做一些修改。

SMO高效优化算法

from numpy import *
import pylab as pl
def loadDataSet():
    dataMat = []
    labelMat = []
    fr = open('d:\\testSet.txt','r')
    for line in fr:
        lineArr = line.split('\t',3)
        dataMat.append([float(lineArr[0]),float(lineArr[1])])
        labelMat.append(float(lineArr[2]))
    return dataMat,labelMat
'''
下一个函数3616£^0^1«1()有两个参数值,其中1是第一个&姊 &的下标,1(\是所有3中1^的数
目。只要函数值不等于输人值1 ,函数就会进行随机选择。
'''
def selectJrand(i,m):
    j = i;
    while j==i :
        j = random.randint(0,m-1)
    return j

#是用于调整大于H或小于L的alpha值
def clipAlpha(aj,L,H):
    if aj>H :
        aj = H
    if aj<H:
        aj = H
    return aj

#数据集、类别标签、常数 、容错率和取消前最大的循环次数
def smoSimple(dataMatIn ,classLabls ,C, toler, maxIter):
    dataMatrix = mat(dataMatIn)     #比如之前有m个样例,每个样例有m个数据
    labelMat = mat(classLabls).transpose()#生成一个1*m的矩阵
    b = 0
    m,n = shape(dataMatrix)
    alphas = mat(zeros((m,1)))  #初始化为m行1列的矩阵,初始值为0
    iter = 0    #当前的循环次数

    while iter < maxIter:   
        alphaPairsChanged = 0 #标记是否有修改
        for i in range(m):
            fxi = float(multiply(alphas,labelMat).T * (dataMatrix*dataMatrix[i,:].T))+b
            '''
            multiply是numpy的ufunc函数,执行方法是对应元素相乘,而不是线性代数中的矩阵运算方式,类似于matlab中的点乘,当矩阵的维度不相同时,会根据一定的广播规则将维数扩充到一致的形式
            * 就表示矩阵乘法
            [i,:]是Numpy花式索引
            .T就是进行轴对换而transpose则可以接收参数进行更丰富的变换
            f(x)=W^T*x+b=sum(alphas(i)*yi*K(x,xi)) +b
            w的值可以通过拉格朗日乘子法求偏导为0得到
            '''
            Ei = fxi - float(labelMat[i]) #误差

            #是否可以继续优化
            if ((labelMat[i]*Ei < -toler) and (alphas[i] <C)) or((labelMat[i]*Ei > toler) and (alphas[i] > 0)):
                '''
                原理解释:
                labelMat[i]*Ei = (fxi - labelMat[i])*labelMat[i] = yi*(W^T*x+b) - 1
                拉格朗日的约束条件是yi*(W^T*x+b) >= 1 且 alphas[i](1-yi*(W^T*x+b)) = 0
                目标函数是最小化1/2*||w||^2+sum(1-alphas[i]*(yi(w^T*x+b)))


                toler表示允许误差

                如果labelMat[i]*Ei < -toler,那么表示离分界线太近,不符合,此时alphas[i]应该为C,使答案过大,从而调整
                如果labelMat[i]*Ei > toler,那么表示离分界线太远,此时alphas[i]应该为0,符合约束条件alphas[i](1-yi*(W^T*x+b)) = 0
                '''
                j = selectJrand(i,m)    #随机选择第j个样本

                fxj = float(multiply(alphas,labelMat).T*(dataMatrix*dataMatrix[j,:].T)) + b
                Ej = fxj - float(labelMat[j])# 误差

                alphaIold = alphas[i].copy()    #拷贝,分配新的内存
                alphaJold = alphas[j].copy()

                if labelMat[i] != labelMat[j]:
                    L = max(0,alphas[j]-alphas[i])
                    H = min(C,C + alphas[j] - alphas[i])
                else:
                    L = max(0, alphas[j] + alphas[i] - C)
                    H = min(C, alphas[j] + alphas[i]) 
                '''
                a1new y1 + a2new y2 =a1old y1 + a2old = xi
                当y1 = y2 = 1,根据a1new的范围->a2new的范围,再与自身的范围进行比较

                其余同理
                '''
                if L==H:
                    print("L==H")
                    continue
                eta = 2.0 * dataMatrix[i,:]*dataMatrix[j,:].T - dataMatrix[i,:]*dataMatrix[i,:].T - dataMatrix[j,:]*dataMatrix[j,:].T
                '''
                eta = K11 + K22 - 2K12
                推导见http://blog.csdn.net/willbkimps/article/details/54697698

                '''
                if eta >= 0: print("eta>=0"); continue

                alphas[j] -= labelMat[j]*(Ei - Ej)/eta
                alphas[j] = clipAlpha(alphas[j],H,L)  # 门限函数阻止alpha_j的修改量过大

                #如果修改量很微小
                if (abs(alphas[j] - alphaJold) < 0.00001): print("j not moving enough"); continue

                # alpha_i的修改方向相反
                alphas[i] += labelMat[j]*labelMat[i]*(alphaJold - alphas[j])

                # 为两个alpha设置常数项b
                b1 = b - Ei- labelMat[i]*(alphas[i]-alphaIold)*dataMatrix[i,:]*dataMatrix[i,:].T - labelMat[j]*(alphas[j]-alphaJold)*dataMatrix[i,:]*dataMatrix[j,:].T
                b2 = b - Ej- labelMat[i]*(alphas[i]-alphaIold)*dataMatrix[i,:]*dataMatrix[j,:].T - labelMat[j]*(alphas[j]-alphaJold)*dataMatrix[j,:]*dataMatrix[j,:].T
                if (0 < alphas[i]) and (C > alphas[i]): b = b1
                elif (0 < alphas[j]) and (C > alphas[j]): b = b2
                else: b = (b1 + b2)/2.0
                alphaPairsChanged += 1
                print("iter: %d i:%d, pairs changed %d" % (iter,i,alphaPairsChanged))
        if (alphaPairsChanged == 0): iter += 1
        else: iter = 0
        print("iteration number: %d" % iter)
    return b,alphas

dataArr,labelArr = loadDataSet();
b,alphas = smoSimple(dataArr,labelArr,0.6,0.001,40)

核函数

核函数:从某个特征空间到另外一个特征空间的映射。
经过空间转换之后,我们可以在高维空间中解决线性问题,等价于在低维空间中解决非线性问题。

设X是输入空间(欧氏空间或离散集合),Η为特征空间(希尔伯特空间),如果存在一个从X到Η的映射
φ(x): X→Η
使得对所有的x,y∈X,函数Κ(x,y)=φ(x)∙φ(y), 则称Κ(x,y)为核函数,φ(x)为映射函数,φ(x)∙φ(y)为x,y映射到特征空间上的内积。

展开阅读全文

没有更多推荐了,返回首页