支持向量机(support vector machines)

目录

前言

一、支持向量机

 1.1几何间隔

1.2求解策略

1.3实例

二、对偶算法

三、算法代码


前言

采蘑菇的小姑娘 ,背着一个大竹筐~

小姑娘又去森林里采蘑菇了;森林地上躺着许多红伞伞白杆杆,可是如果照单全收的话吃完可能会躺板板;为了不让全村吃饭饭,我们需要一种方法区分有毒和无毒的蘑菇。

我们既希望可以多采到无毒的蘑菇,也希望能区分出有毒的蘑菇,也就是说,我们要尽可能的正确区分蘑菇,于是乎,我们的模型支持向量机便来了。

一、支持向量机

支持向量机(support vector machines, SVM)是一种二分类模型,它的基本模型是定义在特征空间上的间隔最大的线性分类器,间隔最大使它有别于感知机(perceptron)。复习一下我们前面讲过的感知机,我们需要找到一个超平面(hyperplane)将正例(positive)和负例(nagetive)分开;

我们还是以蘑菇为例子,我们判断蘑菇是否有毒(poisonous)关注蘑菇的两个属性,伞盖(cap)大小和伞柄(stipe)长度,图中我们已经讲两类用不同的颜色进行了标注,我们试着找一个超平面(这里属性是二维的,超平面在这里体现为直线)将二者分开。

1.1几何间隔

然而这样的超平面有无限多的,如果我们随意取一个超平面,他可能会面对这样的问题:

超平面边界的点分类效果不好

换种说法就是,有误分的可能。采蘑菇的小姑娘如果误判了蘑菇的属性,那么她要么吃不到美味的菌子了,更甚要么吃到有毒的菌子躺板板全村吃饭饭了。

于是,我们需要一定的条件来限定我们的超平面。 

我们采用几何间隔来描述样本点和超平面的差距,我们给定数据集T和超平面\left ( w,b \right ),定义超平面关于样本点\left ( x_{i}, y_{i}\right )的几何间隔为:

\gamma _{i}=y_{i}(\frac{w}{\left \| w \right \|}\cdot x_{i}+ \frac{b}{\left \| w \right \|})

其中x_{i}为我们输入的样本特征,在蘑菇事件中为伞盖(cap)大小和伞柄(stipe)长度,而y_{i}则是是否有毒,如果有毒则为-1,无毒则为+1。所以当某个蘑菇伞盖大小为3cm,长度为5cm,而且有毒时,我们用((3,5),-1)来表示该个体。

\frac{w}{\left \| w \right \|}\cdot x_{i}+ \frac{b}{\left \| w \right \|}描述为点到超平面的距离,注意当点位于超平面之下时该值<0,位于超平面之上时>0,这时我们乘上y_{i}使其恒大于0,于是乎\gamma _{i}就是点到超平面的距离。

1.2求解策略

SVM的基本思想时求解能正确分类样本且几何间隔最大化的超平面,也就是使得正负例尽量远离超平面。对于线性可分的数据集而言,线性可分的超平面有无数个(就是我们的感知机了),但几何间隔最大的超平面只有一个,这里几何间隔最大化成为硬间隔最大化。间隔最大化的意义是:

用更高的确信度对数据进行分类,不仅要将正负例分开,而且对最难分的实例点(离超平面最近的点)也有足够大的确信度把他们分开;这样的超平面对未知的新实例有很好的分类能力。

我们求一个间隔最大超平面,可以转化为约束最优化问题

\underset{w,b}{max}\ \gamma\ \\s.t. \ \ \ y_{i}(\frac{w}{\left \| w \right \|}\cdot x_{i}+ \frac{b}{\left \| w \right \|})\geqslant \gamma ,i=1,2,...,N

即我们想要找到一个间隔\gamma,所有样本点的几何间隔都比他大,且我们希望这个\gamma最大

我们引入函数间隔 \widehat{\gamma }=y_{_{i}}(w\cdot x_{i}+b),其与几何间隔的关系\gamma =\frac{\widehat{\gamma }}{\left \| w \right \|}

 于是乎我们将上述公式改写为

\underset{w,b}{max}\ \frac{\widehat{\gamma }}{\left \| w \right \|}\ \\ s.t.\ \ \ y_{i}(w\cdot x_{i}+ b)\geqslant \widehat{\gamma} ,i=1,2,...,N

函数间隔\widehat{\gamma }随着w取值变化而变化,当wb按比例变化\lambda倍后,函数间隔也变化 \lambda倍,几何间隔不变。所以,\widehat{\gamma }并不影响几何间隔,我们取其为1;同时最大化\frac{1}{\left \| w \right \|}和最小化\frac{1}{2}\left \| w \right \|^{2}是等价的,于是我们可以改写我们的优化问题为

\underset{w,b}{min}\ \ \ \frac{1}{2}\left \| w \right \|^{2}\\ s.t.\ \ \ y_{i}(w\cdot x_{i}+ b)-1\geqslant 0 ,i=1,2,...,N

 这是一个凸二次规划问题,它存在最优解。

线性可分的情况下,与超平面距离最近的样本点叫做支持向量(support vector),支持向量是y_{i}(w\cdot x_{i}+ b)-1= 0成立的点,所有的距离都大于支持向量到超平面的距离

 我们平行于超平面经过支持向量机做直线H1,H2之间的距离称之为间隔(margin)。

在决定分类超平面时只有支持向量起作用,其他实例点不起作用。支持向量一般很少,所有支持向量机是由很少一部分的向量所决定的。

1.3实例

我们来看一个简单的例子

如图x_{1}=(3,3)^{T},x_{2}=(4,3)^{T}是正例,x_{3}=(1,1)^{T}是负例,我们想寻找间隔最大的超平面

于是我们可以构造以下优化问题:

\underset{w,b}{min}\ \ \ \frac{1}{2}(w_{1}^{2}+w_{2}^{2})\\ s.t. \begin{cases} 3w_{1}+3w_{2}+b\geqslant 1\\ 4w_{1}+3w_{2}+b\geqslant 1\\ -w_{1}+-w_{2}-b\geqslant 1 \end{cases}

得到优化问题的解w_{1}=w_{2}=\frac{1}{2},b=-2,于是最大间隔超平面为\frac{1}{2}x_{1}+\frac{1}{2}x_{2}-2=0,其中x_{1},x_{3}为支持向量

二、对偶算法

我们求解线性可分的支持向量机最优化问题,将其作为原始问题,运用拉格朗日对偶性,通过求解对偶问题求解原始问题的最优解。

我们建立拉格朗日函数(Lagrange function)

L(w,b,\alpha )=\frac{1}{2}\left \| w \right \|^{2}-\sum_{i=1}^{N}\alpha _{i}y_{i}(w\cdot x_{i}+b)+\sum_{i=1}^{N}\alpha _{i}

其中拉格朗日乘子(Lagrange multiplier)\alpha _{i}\geq 0,i=1,2,...N

如此原问题就转化为极大极小的对偶问题

\underset{\alpha}{max}\ \underset{w,b}{min} \ L(w,b,\alpha )

即先将w,b看为变量求其最小,再将\alpha看为变量求其最大

(1)首先求\underset{w,b}{min} \ L(w,b,\alpha )

\ L(w,b,\alpha )w,b求偏导并使其=0得到

w=\sum_{i=1}^{N}\alpha _{i}y_{i}x_{i}

\sum_{i=1}^{N}\alpha _{i}y_{i}=0

\underset{w,b}{min} \ L(w,b,\alpha )=-\frac{1}{2}\sum_{i=1}^{N}\sum_{j=1}^{N}\alpha _{i}\alpha _{j}y_{i}y_{j}(x_{i}\cdot x_{j})+\sum_{i=1}^{N}\alpha _{i}

(2)求\underset{w,b}{min} \ L(w,b,\alpha )的极大

\underset{\alpha }{max}\ \ -\frac{1}{2}\sum_{i=1}^{N}\sum_{j=1}^{N}\alpha _{i}\alpha _{j}y_{i}y_{j}(x_{i}\cdot x_{j})+\sum_{i=1}^{N}\alpha _{i}\\ s.t. \sum_{i=1}^{N}\alpha _{i}y_{i}=0\\ \alpha _{i}\geqslant 0,i=1,2,...N

相当于

\underset{\alpha }{min}\ \ \frac{1}{2}\sum_{i=1}^{N}\sum_{j=1}^{N}\alpha _{i}\alpha _{j}y_{i}y_{j}(x_{i}\cdot x_{j})-\sum_{i=1}^{N}\alpha _{i}\\ s.t. \sum_{i=1}^{N}\alpha _{i}y_{i}=0\\ \alpha _{i}\geqslant 0,i=1,2,...N

解得\alpha ^{*}是对偶问题的最优解,便有

w^{*}=\sum_{i=1}^{N}\alpha _{i}^{*}y_{i}x_{i}

b^{*}=y_{j}-\sum_{i=1}^{N}\alpha _{i}^{*}y_{i}(x_{i}\cdot x_{j})

分类决策函数为

f(x)=sign(\sum_{i=1}^{N}\alpha _{i}^{*}y_{i}(x_{i}\cdot x)+b^{*})

三、算法代码

这里我们数据集选用鸢尾花数据集,取标签0,1分别为正例和负例

from sklearn import svm
from sklearn.datasets import load_iris
import numpy as np
from numpy import *
import matplotlib.pyplot as plt

l0_data=[]
l1_data=[]
total_data=[]
target=[]

iris=load_iris()
for data,label in zip(iris['data'],iris['target']):
    if int(label) == 1:
        l1_data.append(np.array([data[0],data[1]]))
        total_data.append(np.array([data[0], data[1]]))
        target.append(label)
    if int(label) == 0:
        l0_data.append(np.array([data[0],data[1]]))
        total_data.append(np.array([data[0],data[1]]))
        target.append(label)

l0_data=np.array(l0_data)
l1_data=np.array(l1_data)
data=np.array(total_data)

clf = svm.SVC(kernel='linear',C=1000)
clf.fit(data, target)

w = clf.coef_  
b = clf.intercept_  

w=np.squeeze(w)
b=np.squeeze(b)

x_axis=np.arange(4,8)
y_axis=-x_axis*w[0]/w[1]-b/w[1]
plt.scatter(l0_data[:,0],l0_data[:,1])
plt.scatter(l1_data[:,0],l1_data[:,1])


Support_vector = clf.support_vectors_

x1=Support_vector[1]
x2=Support_vector[2]
b_1=-w[0]*x1[0]-w[1]*x1[1]
b_2=-w[0]*x2[0]-w[1]*x2[1]

plt.plot(x_axis,-x_axis*w[0]/w[1]-b_1/w[1],'b:')
plt.plot(x_axis,-x_axis*w[0]/w[1]-b_2/w[1],'r:')
plt.plot(x_axis,y_axis)

plt.show()

结果如图所示,虚线所标注的就是支持向量所在的直线

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
#include <math.h> #include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <float.h> #include <string.h> #include <stdarg.h> #include <limits.h> #include <locale.h> #include "svm.h" int libsvm_version = LIBSVM_VERSION; typedef float Qfloat; typedef signed char schar; #ifndef min template <class T> static inline T min(T x,T y) { return (x<y)?x:y; } #endif #ifndef max template <class T> static inline T max(T x,T y) { return (x>y)?x:y; } #endif template <class T> static inline void swap(T& x, T& y) { T t=x; x=y; y=t; } template <class S, class T> static inline void clone(T*& dst, S* src, int n) { dst = new T[n]; memcpy((void *)dst,(void *)src,sizeof(T)*n); } static inline double powi(double base, int times) { double tmp = base, ret = 1.0; for(int t=times; t>0; t/=2) { if(t%2==1) ret*=tmp; tmp = tmp * tmp; } return ret; } #define INF HUGE_VAL #define TAU 1e-12 #define Malloc(type,n) (type *)malloc((n)*sizeof(type)) static void print_string_stdout(const char *s) { fputs(s,stdout); fflush(stdout); } static void (*svm_print_string) (const char *) = &print_string_stdout; #if 1 static void info(const char *fmt,...) { char buf[BUFSIZ]; va_list ap; va_start(ap,fmt); vsprintf(buf,fmt,ap); va_end(ap); (*svm_print_string)(buf); } #else static void info(const char *fmt,...) {} #endif // // Kernel Cache // // l is the number of total data items // size is the cache size limit in bytes // class Cache { public: Cache(int l,long int size); ~Cache(); // request data [0,len) // return some position p where [p,len) need to be filled // (p >= len if nothing needs to be filled) int get_data(const int index, Qfloat **data, int len); void swap_index(int i, int j); private: int l; long int size; struct head_t { head_t *prev, *next; // a circular list Qfloat *data; int len; // data[0,len) is cached in this entry }; head_t *head; head_t lru_head; void lru_delete(head_t *h); void lru_insert(head_t *h); }; Cache::Cache(int l_,long int size_):l(l_),size(size_) { head = (head_t *)calloc(l,sizeof(head_t)); // initialized to 0 size /= sizeof(Qfloat); size -= l * sizeof(head_t) / sizeof(Qfloat); size = max(size, 2 * (long int) l); // cache must be large enough for two columns lru_head.next = lru_head.prev = &lru_head; } Cache::~Cache() { for(head_t *h = lru_head.next; h != &lru_head; h=h->next) free(h->data); free(head); } void Cache::lru_delete(head_t *h) { // delete from current location h->prev->next = h->next; h->next->prev = h->prev; } void Cache::lru_insert(head_t *h) { // insert to last position h->next = &lru_head; h->prev = lru_head.prev; h->prev->next = h; h->next->prev = h; } int Cache::get_data(const int index, Qfloat **data, int len) { head_t *h = &head[index]; if(h->len) lru_delete(h); int more = len - h->len; if(more > 0) { // free old space while(size < more) { head_t *old = lru_head.next; lru_delete(old); free(old->data); size += old->len; old->data = 0; old->len = 0; } // allocate new space h->data = (Qfloat *)realloc(h->data,sizeof(Qfloat)*len); size -= more; swap(h->len,len); }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值