zoukankan      html  css  js  c++  java
  • 基于SVM的数字识别

    KNN也能实现数字识别但需要保留所有的训练样本,支持向量机只需要保留支持向量就可以达到类似的效果

    支持向量机本质上是一个二分类器

    代码如下:

    # -*- coding: utf-8 -*-
    #完整版的支持向量机 有核函数
    
    from numpy import *
    from time import sleep
    #导入数据集
    def loadDataSet(fileName):
        dataMat = []
        labelMat = []
        fr = open(fileName)
        for line in fr.readlines():#按行读取
            lineArr = line.strip().split('	')#对每行分割并剔除空格
            dataMat.append([float(lineArr[0]), float(lineArr[1])])
            labelMat.append(float(lineArr[2]))
        return dataMat,labelMat
    #随机选择一个i!=j的数
    def selectJrand(i,m):
        j=i #we want to select any J not equal to i
        while (j==i):
            j = int(random.uniform(0,m))
        return j
    #数值太大太小时调整
    def clipAlpha(aj,H,L):
        if aj > H: 
            aj = H
        if L > aj:
            aj = L
        return aj
    #简化的SMO算法
    #输入参数为(数据集,标签集,常数C,容错率,最大循环次数)
    def smoSimple(dataMatIn, classLabels, C, toler, maxIter):
        dataMatrix = mat(dataMatIn);           #转换为NumPy矩阵类型
        labelMat = mat(classLabels).transpose()#转换为NumPy矩阵类型,并求转置
        b = 0; 
        m,n = shape(dataMatrix)    #求矩阵的大小
        alphas = mat(zeros((m,1))) #生成一个0矩阵 列矩阵
        iter = 0                   #迭代次数
        while (iter < maxIter):
            alphaPairsChanged = 0  #用于记录alpha是否已经优化
            for i in range(m):
                fXi = float(multiply(alphas,labelMat).T*(dataMatrix*dataMatrix[i,:].T)) + b      #fXi是要预测的类别
                Ei = fXi - float(labelMat[i])#if checks if an example violates KKT conditions    #计算误差
                if ((labelMat[i]*Ei < -toler) and (alphas[i] < C)) or ((labelMat[i]*Ei > toler) and (alphas[i] > 0)): #如果可以被优化
                    j = selectJrand(i,m)#随机选择一个数
                    fXj = float(multiply(alphas,labelMat).T*(dataMatrix*dataMatrix[j,:].T)) + b  #fXj是要预测的类别 multiply表示各元素相乘,T是转置
                    Ej = fXj - float(labelMat[j])                                                #计算误差
                    alphaIold = alphas[i].copy()#python中的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])
                    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
                    if eta >= 0: 
                        print ("eta>=0"); continue
                    alphas[j] -= labelMat[j]*(Ei - Ej)/eta
                    alphas[j] = clipAlpha(alphas[j],H,L)
                    if (abs(alphas[j] - alphaJold) < 0.00001): 
                        print ("j not moving enough"); continue
                    alphas[i] += labelMat[j]*labelMat[i]*(alphaJold - alphas[j])#更新i,与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 # alphaPairsChanged == 0 表示未更新
            else: 
                iter = 0  # alphaPairsChanged != 0 表示已更新
            print ("iteration number: %d" % iter)
        return b,alphas
    #核转换函数
    #输入参数为()
    #元组KTup给出了核函数的信息 元组的第一个参数描述核函数的类型
    def kernelTrans(X, A, kTup): #calc the kernel or transform data to a higher dimensional space
        m,n = shape(X)
        K = mat(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 = 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): #使用参数来初始化结构
            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))) #第一列是标志位第二列是实际的E值
            self.K = mat(zeros((self.m,self.m)))
            for i in range(self.m):
                self.K[:,i] = kernelTrans(self.X, self.X[i,:], kTup)
    #计算E值并返回,是从SMO中提取出来的        
    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
    #计算内循环的alpha        
    def selectJ(i, oS, Ei):         #this is the second choice -heurstic, and calcs Ej
        maxK = -1; maxDeltaE = 0; Ej = 0
        oS.eCache[i] = [1,Ei]  #set valid #choose the alpha that gives the maximum delta E
        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]
    #与smoSimple类似但是有改进     
    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
    #有核函数的完整版的SMO算法
    #输入参数为(数据集,标签集,常数C,容错率,最大循环次数,核函数)
    def smoP(dataMatIn, classLabels, C, toler, maxIter,kTup=('lin', 0)):    #full Platt 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
    #计算WS
    def calcWs(alphas,dataArr,classLabels):
        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
    #测试径向基核函数
    def testRbf(k1=1.3):
        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]#得到大于零的alpha值 从而得到支持向量
        sVs=datMat[svInd] #get matrix of only support vectors
        labelSV = labelMat[svInd];
        print ("there are %d Support Vectors" % shape(sVs)[0])
        m,n = shape(datMat)
        errorCount = 0
        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 training error rate is: %f" % (float(errorCount)/m))
        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 img2vector(filename):
        returnVect = zeros((1,1024))
        fr = open(filename)
        for i in range(32):
            lineStr = fr.readline()
            for j in range(32):
                returnVect[0,32*i+j] = int(lineStr[j])
        return returnVect
    #加载图像
    def loadImages(dirName):
        from os import listdir
        hwLabels = []
        trainingFileList = listdir(dirName)           #load the training set
        m = len(trainingFileList)
        trainingMat = zeros((m,1024))
        for i in range(m):
            fileNameStr = trainingFileList[i]
            fileStr = fileNameStr.split('.')[0]     #take off .txt
            classNumStr = int(fileStr.split('_')[0])
            if classNumStr == 9: #二分类
                hwLabels.append(-1)
            else: 
                hwLabels.append(1)
            trainingMat[i,:] = img2vector('%s/%s' % (dirName, fileNameStr))
        return trainingMat, hwLabels    
    #和testRbf差不多也是一个测试函数
    def testDigits(kTup=('rbf', 10)):#设置了默认的核函数
        dataArr,labelArr = loadImages('trainingDigits')
        b,alphas = smoP(dataArr, labelArr, 200, 0.0001, 10000, kTup)
        datMat=mat(dataArr); labelMat = mat(labelArr).transpose()
        svInd=nonzero(alphas.A>0)[0]
        sVs=datMat[svInd] 
        labelSV = labelMat[svInd];
        print ("there are %d Support Vectors" % shape(sVs)[0])
        m,n = shape(datMat)
        errorCount = 0
        for i in range(m):
            kernelEval = kernelTrans(sVs,datMat[i,:],kTup)
            predict=kernelEval.T * multiply(labelSV,alphas[svInd]) + b
            if sign(predict)!=sign(labelArr[i]): errorCount += 1
        print ("the training error rate is: %f" % (float(errorCount)/m))
        dataArr,labelArr = loadImages('testDigits')
        errorCount = 0
        datMat=mat(dataArr); labelMat = mat(labelArr).transpose()
        m,n = shape(datMat)
        for i in range(m):
            kernelEval = kernelTrans(sVs,datMat[i,:],kTup)
            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)) 

    结果如下:

    import svm
    》svm.testDigits(kTup=('rbf', 10))
    there are 125 Support Vectors
    the training error rate is: 0.000000
    the test error rate is: 0.005376

    除此外要有公式推导

  • 相关阅读:
    HDU 4069 Squiggly Sudoku
    SPOJ 1771 Yet Another NQueen Problem
    POJ 3469 Dual Core CPU
    CF 118E Bertown roads
    URAL 1664 Pipeline Transportation
    POJ 3076 Sudoku
    UVA 10330 Power Transmission
    HDU 1426 Sudoku Killer
    POJ 3074 Sudoku
    HDU 3315 My Brute
  • 原文地址:https://www.cnblogs.com/Aaron12/p/8994058.html
Copyright © 2011-2022 走看看