支持向量机(SVM)的理论推导

连续推导了两天的公式外加一天的编程,身体和脑子已不是自己的了。今天傍晚还没实现,到了快晚饭时间才调试通过得到了不错的结果,下午是崩溃的,一直收敛不了,找了许久也没找到什么原因导致的,于是开始怀疑人生。没办法,只好一步一步调试过去,终于被我找到某个地方的j写成了i,还有之前的大于号写成了小于号…这么多复杂的公式,有一处小的地方写错了,原因真的很难找到。要不是因为它好玩,我才不想干这种苦逼的事呢。
简书又出Bug了,登不进去,只好用微薄
话不多说,上公式:











































上程序:

'''

Created on 2017年7月9日



@author: fujianfei

'''

from os.path import os 

import numpy as np  







#导入数据,数据集

def loadDataSet (fileName):

    data_path = os.getcwd()+'\\data\\'

    labelMat = []

    svmData = np.loadtxt(data_path+fileName,delimiter=',')

    dataMat=svmData[:,0:2]

    #零均值化

#     meanVal=np.mean(dataMat,axis=0)

#     dataMat=dataMat-meanVal

    label=svmData[:,2]

    for i in range (np.size(label)):

        if label[i] == 0 or label[i] == -1:

            labelMat.append(float(-1))

        if label[i] == 1:

            labelMat.append(float(1))

    return dataMat.tolist(),labelMat

#简化版SMO算法,不启用启发式选择alpha,先随机选

def selectJrand(i,m):

    j=i

    while (j==i):

        j = int(np.random.uniform(0,m))#在0-m的随机选一个数

    return j





#用于调整大于H或小于L的值,剪辑最优解

def clipAlpha(aj,H,L):

    if aj > H:

        aj = H

    if L > aj:

        aj = L

    return aj



'''

定义核函数

kernelOption=linear 线性

kernelOption=rbf 高斯核函数

'''

def calcKernelValue(matrix_x, sample_x, kernelOption):  

    kernelType = kernelOption[0]  

    numSamples = matrix_x.shape[0]  

    kernelValue = np.mat(np.zeros((numSamples, 1)))  

    if kernelType == 'linear':  

        kernelValue = matrix_x.dot(sample_x.T)  

    elif kernelType == 'rbf':  

        sigma = kernelOption[1]  

        if sigma == 0:  

            sigma = 1.0  

        for i in range(numSamples):  

            diff = matrix_x[i, :] - sample_x  

            kernelValue[i] = np.exp(diff.dot(diff.T) / (-2.0 * sigma**2))  

    else:  

        raise NameError('Not support kernel type! You can use linear or rbf!')  

    return kernelValue  



'''

简化版SMO算法。

dataMatIn:输入的数据集

classLabels:类别标签

C:松弛变量前的常数

toler:容错率

maxIter:最大循环数

'''

def smoSimple(dataMatIn,classLabels,C,toler,maxIter):

    dataMatrix = np.mat(dataMatIn);labelMat = np.mat(classLabels).transpose()

    b=0;m,n = np.shape(dataMatrix)

    alphas = np.mat(np.zeros((m,1)))

    iter = 0

    while(iter < maxIter):

        alphaPairsChanged = 0 #记录alpha值是否优化,即是否变化

        for i in range(m):#遍历数据集,第一层循环,遍历所有的alpha

            fXi = float(np.multiply(alphas,labelMat).T.dot(calcKernelValue(dataMatrix,dataMatrix[i,:],('linear', 0)))) + b

            Ei = fXi - float(labelMat[i])

            if (((labelMat[i]*Ei < -toler) and (alphas[i] < C)) or ((labelMat[i]*Ei > toler) and (alphas[i] > 0))):

                j = selectJrand(i, m)

                fXj = float(np.multiply(alphas,labelMat).T.dot(calcKernelValue(dataMatrix,dataMatrix[j,:],('linear', 0)))) + 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])

                if(L == H):print('L==H');continue

                eta = 2.0 * calcKernelValue(dataMatrix[i,:],dataMatrix[j,:],('linear', 0)) - calcKernelValue(dataMatrix[i,:],dataMatrix[i,:],('linear', 0)) - calcKernelValue(dataMatrix[j,:],dataMatrix[j,:],('linear', 0))

                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.0001) : print('j not moving enough');continue

                alphas[i] += labelMat[i]*labelMat[j]*(alphaJold - alphas[j]) 

                b1 = b - Ei - labelMat[i]*(alphas[i] - alphaIold)*calcKernelValue(dataMatrix[i,:],dataMatrix[i,:],('linear', 0)) - labelMat[j]*(alphas[j]-alphaJold)*calcKernelValue(dataMatrix[j,:],dataMatrix[i,:],('linear', 0)) 

                b2 = b - Ej - labelMat[i]*(alphas[i] - alphaIold)*calcKernelValue(dataMatrix[i,:],dataMatrix[j,:],('linear', 0)) - labelMat[j]*(alphas[j]-alphaJold)*calcKernelValue(dataMatrix[j,:],dataMatrix[j,:],('linear', 0)) 

                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              



from SVM import svmMLiA

import numpy as np  

import matplotlib.pyplot as plt



#实现,并可视化

if __name__ == '__main__':

    dataMatIn,classLabels = svmMLiA.loadDataSet('data1.txt')

    dataMatrix = np.mat(dataMatIn);labelMat = np.mat(classLabels).transpose()

    C=0.6

    toler=0.001

    maxIter=40

    m,n = np.shape(dataMatrix)

    b,alphas = svmMLiA.smoSimple(dataMatIn, classLabels, C, toler, maxIter)

    w=np.multiply(alphas,labelMat).T.dot(dataMatrix)

    w=np.mat(w)

    x1=dataMatrix[:,0]

    y1=dataMatrix[:,1]

    x2=range(20,100)

    b=float(b)

    w0=float(w[0,0])

    w1=float(w[0,1])

    y2 = [-b/w1-w0/w1*elem for elem in x2]

    plt.plot(x2, y2)

    for i in range(m):  

        if ((alphas[i] < C) and (alphas[i] > 0)):

            print('########################')

            print(alphas[i])

            plt.scatter(x1[i], y1[i],s=60,c='red',marker='o',alpha=0.5,label='SV')

        if int(labelMat[i, 0]) == -1:  

            plt.scatter(x1[i], y1[i],s=30,c='red',marker='.',alpha=0.5,label='-1')  

        elif int(labelMat[i, 0]) == 1:  

            plt.scatter(x1[i], y1[i],s=30,c='blue',marker='x',alpha=0.5,label='+1') 



    plt.show()

最后的结果是这样滴:


​说明:大大的红色的圈圈就是支持向量。
支持向量机的功能绝不限于此,这个东西早在数周前用逻辑斯特回归早就画出来了。关于支持向量的其他更高级应用下周再说。包括高斯核和启发式选择初始值,这次的是简单版本的SMO算法,因为随便选的,速度慢的要死。几百个数据点就跑了好几分钟。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,047评论 25 707
  • 【概述】 SVM训练分类器的方法是寻找到超平面,使正负样本在超平面的两侧(分类正确性即“分得开”),且样本到超平面...
    sealaes阅读 10,908评论 0 7
  • (一)《自志》 岁既冬春下, 人常老病间。 刀锋久避月, 书气远离天。 世上千秋度, 眉中万古掀。 谁应惜骏驰, ...
    南山青阅读 138评论 0 2
  • 【心满意足】十分满足。 出处:宋·刘克庄《答欧阳秘书书》:“精义多先儒所未讲,陈言无一字之相袭,虽累数千言,而义理...
    有趣儿阅读 559评论 0 0
  • 凌峭峭的回忆
    余晓辰阅读 148评论 0 0