支持向量机(SVM)

1.什么支持向量机

支持向量机解决的是多维的分类问题。当给出一定的数据集时,分类学习的最基本想法就是基于训练集在样本空间中找到一个划分超平面,将不同类别的样本去划分,又因为在训练学习中,数据大多是高维度的,并且数据不一定都是线性可分的,那么线性不可分的数据,和非线性函数怎么划分呢?这时候就需要使用到一种新的分类器,支持向量机,支持向量机是基于线性分类器提出的另一种设计最佳准则。


支持向量机和线性回归的区别:

线性回归,当样本空间里的属性都是线性可分的时候,如图1.1,使用线性回归即可解决这些问题,但是在实际运用中,样本空间内的特征大部分都不是线性可分的,这时候我们的支持向量机就派上用场了。因为支持向量机可以根据不同的核函数(在下面会讲)得到线性回归模型和非线性回归模型。

1.1

2.支持向量机的基本型

在样本空间中,划分超平面通过的线性方程:


2.1

其中w为法向量,决定超平面的方向,b为位移项,决定超平面与原点之间的距离
但是基于这个线性方程划分的超平面,很明显,会有很多种划分方法,如图1.1

而为了寻找最优的划分超平面,我们必须找到具有“最大间隔”的划分超平面。“间隔”指的是两个异类向量距离超平面的距离。为了找到‘最大间隔’,在这里加上了一个约束条件


假设有超平面(w,b)能将训练集正确划分,那对于训练集D中的(xi,yi)则有以下约束条件。


2.2

根据这个约束条件,可以将2.2中的公式重写:


2.3

根据这条公式,产生了支持向量机的基本型

3.核函数

2中使用的支持向量机基本型,只能支持训练样本是线性可分的情况下,即存在一个划分超平面能将训练样本的正确分类,然而在现实任务中,原始样本空间不一定都会存在一个能正确划分的超平面,例如图3.1的“异或”问题就不是线性可分的。

3.1

对于这个问题,怎么办呢?这时候我们就可以将这个原始空间,映射到一个更高维度的特征空间中,如图3.1将一个二维的样本空间,映射到一个三维的特征空间上,就能找到一个合适的划分超平面,按照这个原理,当原始空间是有限维度的,即属性数有限 ,那么一定存在一个高纬度的样本可分。


举个例子:假设需要在一个桌面上划分篮球和红球,并且在尽量在放更多球之后,仍然适用。那么我们可以如下图所示划分,蓝色球跟红色球的间隔最大化。
3.2

但如果是下图中的这种无法线性划分的情况,没有直接的直线可以分开两种球了,那怎么办呢?那么可以看做球飞到空中,在其中用一张纸,插到了两种球的中间把两种球分开了。

3.3

将原始空间映射后的特征向量模型可表示为:


3.4

如2.2一样,需要寻找最大间隔,所以必须增加约束条件:


3.5

对这个函数求解的话,由于特征空间维度可能会很大,甚至无穷维,所以为了避开这个障碍,可以设想一个这样的函数

3.6

即Xi与Xj在特征空间内积等于他们在原始空间中通过函数κ()计算的结果,重写3.5的公式为:
3.7

求解后得到

3.8

在这里κ(,)就是‘核函数’


通常我们不知道合适映射0(·)是什么形式,所以无法直接写出核函。但任何一个核函数都隐式定义了一个称为“再生和希尔伯特空间”的特征空间。核函数的选择对支持向量机的性能至关重要。图3.9列出了常用的核函数。
3.9

4.软间隔与正则化

在现实任务中,数据并不“纯”,而且在显示任务中很难确认核函数是否真的那么适合,即使你得出一个刚刚好把数据划分得很完美的超平面,你也很难确定,这是不是因为学习器把数据学习得太好了,而产生‘过拟合’。
为了缓解这个问题的一个办法就是,允许支持向量机在一些样本上出错。所以引入了‘软间隔’的概念:

4.1

在原有的公式上,增加一个损失函数,这些函数不包含在最大间隔计算范围,但是我们计算最大间隔的时候,同时也对于不满足的样本尽可能少

4.2

其中C为一个大于0的参数,而C后面的为“0/1损失函数”如图4.1所示,间隔在1的样本,我们把它当作损失函数
4.2

5.代码实现支持向量机

《机器学习实战》中给出了利用Python实现SVM的代码:

import random
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 aj < L:
        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 ):  
            # 输出 alphas 信息
            # 输出 labelMat 信息
            fXi = float ( multiply ( alphas , labelMat ).T * (dataMatrix * dataMatrix[i , :].T) ) + b
            # fXi=float(np.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.00001): 
                    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) * \
                              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


if __name__ == "__main__":
    dataArr , labelArr = loadDataSet ( 'testSet.txt' )
    b , alphas = smoSimple ( dataArr , labelArr , 0.6 , 0.001 , 40 )

    print(b , alphas)

详细代码查看请点击码云

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

推荐阅读更多精彩内容

  • 【干货】支持向量机SVM算法推演 来源:海阔心 尽管早就听说SVM比较复杂,当真正下笔推导时其复杂程度还是出乎意料...
    Major术业阅读 2,684评论 0 9
  • 一、什么是支持向量机 支持向量机(supportvectormachine),故一般简称SVM,通俗来讲,它是一种...
    owolf阅读 4,781评论 0 3
  • 参考Jerrylead和july-支持向量机通俗导论 一、由逻辑回归,引申出SVM(线性可分的SVM) 1.1 逻...
    小碧小琳阅读 1,473评论 0 2
  • 从今天开始整理一些关于支持向量机-Support Vector Machine 的相关知识,大约发6-8篇的博客,...
    011b8ee4cba4阅读 558评论 0 0
  • 1.什么支持向量机 当给出一定的数据集时,分类学习的最基本想法就是基于训练集在样本空间中找到一个划分超平面,将不同...
    DouMarK阅读 553评论 0 0