机器学习之支持向量机模型(SVM)

  • 1、支持向量机模型介绍
  • 2、支持向量机数学原理
  • 3、算法及Python
  • 4、小结

1、支持向量机模型介绍

支持向量机(SVM)是一种二类分类模型。它的基本模型是定义在特征空间上的间隔最大的线性分类器,间隔最大使它有别于感知机;支持向量机还包括核技巧,这使它成为实质上的非线性分类器。支持向量机的学习策略就是间隔最大化,可形式化为一个求解凸二次规划的问题,支持向量机的学习算法是求解凸二次规划的最优算法。
定义一(线性可分支持向量机):
给定线性可分训练数据集,通过间隔最大化或等价地求解相应的凸二次规划问题学习得到的分离超平面为
w^*\cdot x+b^*=0
以及相应的分类决策函数
f(x)=sign(w^*\cdot x+b^*)
称为线性可分支持向量机。

image.png

定义二(非线性支持向量机):
从非线性分类训练集,通过核函数与软间隔最优化,或凸二次规划,学习得到的分类决策函数
f(x)=sign\left( \sum_{i=1}^Na_i^*y_iK(x,x_i)+b^* \right)
称为非线性支持向量机,K(x,z)是正定核函数。
image.png

2、支持向量机数学原理

函数间隔:对于给定的训练数据集和超平面(w,b),定义超平面(w,b)关于样本点(x_i,y_i)的函数间隔为
\hat{\gamma}_i = y_i(w\cdot x_i+b)
几何间隔:对于给定的训练数据集和超平面(w,b),定义超平面(w,b)关于样本点(x_i,y_i)的几何间隔为
\gamma_i = y_i\left( \frac{w}{||w||}\cdot x_i +\frac{b}{||w||}\right)
间隔最大化
max_{w,b} \gamma
s.t.\ \ \ \ \ y_i\left( \frac{w}{||w||}\cdot x_i+\frac{b}{||w||} \right)\geq\gamma, \ \ \ \ \ i=1,2,\cdots,N
即希望最大化超平面(w,b)关于训练集的几何间隔\gamma,约束条件表示是超平面(w,b)关于每个训练样本点的几何间隔至少是\gamma.
可以将问题改写为
max_{w,b} \frac{\hat{\gamma}}{||w||}
s.t.\ \ \ \ \ y_i\left( w\cdot x_i +b \right)\geq\hat{\gamma}, \ \ \ \ \ i=1,2,\cdots,N
因为假设将w\cdot x+b=0中左边乘以\lambda则对于超平面没有影响,但是对样本点的函数间隔却有影响,因此我们可以通过调整\lambda值使\hat{\gamma}=1此时便得到线性可分支持向量机学习的最优化问题
min_{w,b} \ \ \ \ \frac{1}{2}||w||^2
s.t \ \ \ \ y_i(w\cdot x_i +b)-1\geq0,\ \ \ \ i=1,2,\cdots,N
软间隔最大化:
当数据集中有一些特异点时,可能导致数据集线性不可分,此时可以对每个样本点(x_i,y_i)引入一个松弛变量\xi_i\geq0,使函数间隔加上松弛变量大于等于1,这样约束条件变为
y_i(w\cdot x_i+b)\geq1-\xi_i
同时对每个松弛变量支付一个代价\xi_i,目标函数由原来的\frac{1}{2}||w||^2变为
\frac{1}{2}||w||^2+C\sum_{i=1}^N\xi_i
这里,C>0称为惩罚参数,一般由应用问题决定
线性不可分的线性支持向量机的学习问题变为如下凸二次规划问题(原始问题)
min_{w,b\xi} \ \ \ \frac{1}{2}||w||^2+C\sum_{i=1}^N\xi_i
y_i(w\cdot x_i+b)\geq1-\xi_i,\ \ \ \ i=1,2,\cdots,N
\xi_i\geq0,\ \ \ \ i=1,2,\cdots,N
学习的对偶算法:
应用拉格朗日对偶性,通过求解对偶问题得到原始问题的最优解,这样做的优点是,一是对偶问题往往更容易求解;二是自然引入核函数,进而推广到非线性分类问题。
线性可分支持向量机对偶问题
首先构建拉格朗日函数,为此,对每一个不等式约束引进拉格朗日乘子\alpha_i \geq0,i=1,2,\cdots,N定义拉格朗日函数L(w,b,\alpha)=\frac{1}{2}||w||^2-\sum_{i=1}^N\alpha_iy_i(w \cdot x_i+b)+\sum_{i=1}^N\alpha_i
其中,\alpha=(\alpha_1,\alpha_2,\cdots,\alpha_N)^T为拉格朗日乘子向量。
根据拉格朗日对偶性,可得到对偶最优化问题
min_a \ \ \ \frac{1}{2}\sum_{i=1}^N\sum_{j=1}^N\alpha_i\alpha_jy_iy_j(x_i\cdot x_j)-\sum_{i=1}^N\alpha_i
s.t. \ \ \ \ \sum_{i=1}^N\alpha_iy_i=0
\alpha_i\geq0,\ \ \ \ i=1,2,\cdots,N
线性不可分线性支持向量机对偶问题
max_a \ \ \ -\frac{1}{2}\sum_{i=1}^N\sum_{j=1}^N\alpha_i\alpha_jy_iy_j(x_i\cdot x_j)+\sum_{i=1}^N\alpha_i
s.t. \ \ \ \ \sum_{i=1}^N\alpha_iy_i=0
C-\alpha_i-\mu_i=0
\alpha\geq0
\mu_i\geq0,\ \ \ \ i=1,2,\cdots,N
非线性支持向量机最优化问题对偶问题
min_a \ \ \ \frac{1}{2}\sum_{i=1}^N\sum_{j=1}^N\alpha_i\alpha_jy_iy_jK(x_i,x_j)-\sum_{i=1}^N\alpha_i
s.t. \ \ \ \ \sum_{i=1}^N\alpha_iy_i=0
0\leq\alpha_i\leq C,\ \ \ \ i=1,2,\cdots,N

3、算法及Python实现

线性支持向量机学习算法
输入:训练数据集T={(x_1,y_1),(x_2,y_2),\cdots,(x_N,x_N)},其中,x_i\in \chi=R^n,y\in \Upsilon=\{-1,+1\},i=1,2,\cdots,N;
输出:分离超平面和分类决策函数。
(1)选择惩罚参数C>0,构造并求解凸二次规划问题
min_a \ \ \ \frac{1}{2}\sum_{i=1}^N\sum_{j=1}^N\alpha_i\alpha_jy_iy_j(x_i\cdot x_j)-\sum_{i=1}^N\alpha_i
s.t. \ \ \ \ \sum_{i=1}^N\alpha_iy_i=0
0\leq\alpha_i\leq C, \ \ \ \ i=1,2,\cdots,N
求得最优解\alpha^*=(\alpha_1^*,\alpha_2^*,\cdots,\alpha_N^*)T
(2)计算w^*=\sum_{i=1}^N\alpha_i^*y_ix_i
选择\alpha^*的一个分量\alpha_j^*适合条件0<\alpha_j^*<C计算
b^*=y_j-\sum_{i=1}^Ny_i\alpha_i^*(x_i\cdot x_j)
(3)求得分离超平面
w^*\cdot x+b^*=0
分类决策函数:
f(x)=sign(w^*\cdot x+b^*)
非线性支持向量机学习算法
输入:训练数据集T={(x_1,y_1),(x_2,y_2),\cdots,(x_N,x_N)},其中,x_i\in \chi=R^n,y\in \Upsilon=\{-1,+1\},i=1,2,\cdots,N;
输出:分类决策函数。
1)选择适当的核函数K(x,z)和适当的参数C,构造并求解最优化问题
min_a \ \ \ \frac{1}{2}\sum_{i=1}^N\sum_{j=1}^N\alpha_i\alpha_jy_iy_jK(x_i, x_j)-\sum_{i=1}^N\alpha_i
s.t. \ \ \ \ \sum_{i=1}^N\alpha_iy_i=0
0\leq\alpha_i\leq C, \ \ \ \ i=1,2,\cdots,N
求得最优解\alpha^*=(\alpha_1^*,\alpha_2^*,\cdots,\alpha_N^*)T
(2)选择\alpha^*的一个正分量0<\alpha_j^*<C计算
b^*=y_j-\sum_{i=1}^N\alpha_i^*y_iK(x_i\cdot x_j)
(3)构造决策函数
w^*\cdot x+b^*=0
分类决策函数:
f(x)=sign(\sum_{i=1}^N\alpha_i^*y_iK(x\cdot x_i)+b^*)
当K(x,z)是正定核函数时,上述问题是凸二次规划问题,解是存在的。
为了更为高效的求解凸二次规划问题,这里介绍由Platt于1998年提出的序列最小最优化(SMO)算法。
SMO算法
输入:输入:训练数据集T={(x_1,y_1),(x_2,y_2),\cdots,(x_N,x_N)},其中,x_i\in \chi=R^n,y\in \Upsilon=\{-1,+1\},i=1,2,\cdots,N,精度\varepsilon;
输出:近似解\hat\alpha.
(1)取初值\alpha^{(0)}=0,令k=0;
(2)选取最优化变量\alpha_1^{(k)},\alpha_1^{(k)}解析求解两个变量的最优化问题,求得最优解\alpha_1^{(k+1)},\alpha_1^{(k+2)},更新\alpha 为\alpha^{(k+1)}
(3)若在精度\varepsilon范围内满足停止条件
\sum_{i=1}^N\alpha_iy_i=0
0\leq\alpha_i\leq C, \ \ \ \ i=1,2,\cdots,N
y_i \cdot g(x_i)=\begin{cases} \geq1, &\{x_i|\alpha_i=0\} \\ =1, & \{x_i|0< \alpha_i < C\} \\ \leq1,& \{x_i|\alpha_i=C\} \end{cases}
其中,
g(x_i)=\sum_{j=1}^K \alpha_jy_jK(x_j,x_i)+b
则转(4);否则令k=k+1,转(2);
(4)取\hat\alpha = \alpha^{(k+1)}

Python代码实现
SMO算法求解线性可分支持向量机代码

from numpy import *
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
def clipAlpha(aj,H,L):
    if aj > H:
        aj = H
    if L > aj:
        aj = L
    return aj
def smoSimple(dataMatIn,classLabels,C,toler,maxIter):
    dataMatrix = mat(dataMatIn);labelMat = mat(classLabels).transpose()
    b = 0; m,n = shape(dataMatrix)
    alphas = mat(zeros((m,1)))
    iter = 0
    while(iter<maxIter):
        alphaPairsChanged = 0
        for i in range(m):
            fXi = float(multiply(alphas,labelMat).T*(dataMatrix*dataMatrix[i,:].T))+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(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])
                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.000001): 
#                     print("j not moving enough"); 
                    continue
                alphas[i] += labelMat[j]*labelMat[i]*(alphaJold-alphas[j])
                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)*labelMat[j]*alphas[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
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 plotData(dataArr,labelArr,ws,b):
    import matplotlib.pyplot as plt
    fig = plt.figure()
    plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
    plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
    xPlotx,xPloty,oPlotx,oPloty = [],[],[],[]
    for i in range(len(labelArr)):
        label = labelArr[i]
        if label == 1:
            xPlotx.append(dataArr[i][0])
            xPloty.append(dataArr[i][1])
        elif label == -1:
            oPlotx.append(dataArr[i][0])
            oPloty.append(dataArr[i][1])
    plt.title("SVM")
    pPlot1,pPlot2 = plt.plot(xPlotx,xPloty,'bx',oPlotx,oPloty,'ro')
    #Plot the split line
    w0 = ws[0][0]
    w1 = ws[1][0]
    x = linspace(1,8,100)
    y = -(w0/w1)*x-b[0][0]/w1
    pSplitPlot = plt.plot(x,y,'k',lw=1)
    plt.show()

绘制线性可分支持向量机超平面,所用的数据集SVM.rar

dataArr,labelArr = loadDataSet('./SVM/testSet.txt')
# print(labelArr)
b,alphas = smoSimple(dataArr,labelArr,0.6,0.001,40)
ws = calcWs(alphas,dataArr,labelArr)
b = array(b)
plotData(dataArr,labelArr,ws,b)

绘制的图形如下


image.png

4、小结

支持向量机是一种分类器,称为“机”是因为它会产生一个二值决策结果,即决策“机”。支持向量机的泛化错误率较低,具有良好的学习能力,且学到的结果具有很好的推广性,这些优点使得支持向量机十分流行。John Platt引入了SMO算法,此算法可以通过每次优化两个alpha值来加快SVM的训练速度。
核方法或者说核技巧会将数据(有时是非线性数据),从一个低维空间映射到一个高维空间,可以将一个在低维空间中的非线性问题转换为高维空间下的线性问题来求解,核方法不仅在SVM中适用,还可以用于其他算法中。而其中的径向基函数是一个常用的度量两个方向距离的核函数。
常用的核函数
1、多项式核函数(polynomial kernel function)
K(x,z)=(x\cdot z+1)^p
2、高斯核函数(Gaussian kernel function)
K(x,z)=exp\left ( - \frac{||x-z||^2}{2\sigma^2}\right)
3、字符串核函数(string kernel function)

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

推荐阅读更多精彩内容