目录
前言
采蘑菇的小姑娘 ,背着一个大竹筐~
小姑娘又去森林里采蘑菇了;森林地上躺着许多红伞伞白杆杆,可是如果照单全收的话吃完可能会躺板板;为了不让全村吃饭饭,我们需要一种方法区分有毒和无毒的蘑菇。
我们既希望可以多采到无毒的蘑菇,也希望能区分出有毒的蘑菇,也就是说,我们要尽可能的正确区分蘑菇,于是乎,我们的模型支持向量机便来了。
一、支持向量机
支持向量机(support vector machines, SVM)是一种二分类模型,它的基本模型是定义在特征空间上的间隔最大的线性分类器,间隔最大使它有别于感知机(perceptron)。复习一下我们前面讲过的感知机,我们需要找到一个超平面(hyperplane)将正例(positive)和负例(nagetive)分开;
我们还是以蘑菇为例子,我们判断蘑菇是否有毒(poisonous)关注蘑菇的两个属性,伞盖(cap)大小和伞柄(stipe)长度,图中我们已经讲两类用不同的颜色进行了标注,我们试着找一个超平面(这里属性是二维的,超平面在这里体现为直线)将二者分开。
1.1几何间隔
然而这样的超平面有无限多的,如果我们随意取一个超平面,他可能会面对这样的问题:
超平面边界的点分类效果不好
换种说法就是,有误分的可能。采蘑菇的小姑娘如果误判了蘑菇的属性,那么她要么吃不到美味的菌子了,更甚要么吃到有毒的菌子躺板板全村吃饭饭了。
于是,我们需要一定的条件来限定我们的超平面。
我们采用几何间隔来描述样本点和超平面的差距,我们给定数据集和超平面
,定义超平面关于样本点
的几何间隔为:
其中为我们输入的样本特征,在蘑菇事件中为伞盖(cap)大小和伞柄(stipe)长度,而
则是是否有毒,如果有毒则为-1,无毒则为+1。所以当某个蘑菇伞盖大小为3cm,长度为5cm,而且有毒时,我们用
来表示该个体。
描述为点到超平面的距离,注意当点位于超平面之下时该值<0,位于超平面之上时>0,这时我们乘上
使其恒大于0,于是乎
就是点到超平面的距离。
1.2求解策略
SVM的基本思想时求解能正确分类样本且几何间隔最大化的超平面,也就是使得正负例尽量远离超平面。对于线性可分的数据集而言,线性可分的超平面有无数个(就是我们的感知机了),但几何间隔最大的超平面只有一个,这里几何间隔最大化成为硬间隔最大化。间隔最大化的意义是:
用更高的确信度对数据进行分类,不仅要将正负例分开,而且对最难分的实例点(离超平面最近的点)也有足够大的确信度把他们分开;这样的超平面对未知的新实例有很好的分类能力。
我们求一个间隔最大超平面,可以转化为约束最优化问题
即我们想要找到一个间隔,所有样本点的几何间隔都比他大,且我们希望这个
最大
我们引入函数间隔 ,其与几何间隔的关系
于是乎我们将上述公式改写为
函数间隔随着
取值变化而变化,当
和
按比例变化
倍后,函数间隔也变化
倍,几何间隔不变。所以,
并不影响几何间隔,我们取其为1;同时最大化
和最小化
是等价的,于是我们可以改写我们的优化问题为
这是一个凸二次规划问题,它存在最优解。
线性可分的情况下,与超平面距离最近的样本点叫做支持向量(support vector),支持向量是成立的点,所有的距离都大于支持向量到超平面的距离
我们平行于超平面经过支持向量机做直线H1,H2之间的距离称之为间隔(margin)。
在决定分类超平面时只有支持向量起作用,其他实例点不起作用。支持向量一般很少,所有支持向量机是由很少一部分的向量所决定的。
1.3实例
我们来看一个简单的例子
如图是正例,
是负例,我们想寻找间隔最大的超平面
于是我们可以构造以下优化问题:
得到优化问题的解,于是最大间隔超平面为
,其中
为支持向量
二、对偶算法
我们求解线性可分的支持向量机最优化问题,将其作为原始问题,运用拉格朗日对偶性,通过求解对偶问题求解原始问题的最优解。
我们建立拉格朗日函数(Lagrange function)
其中拉格朗日乘子(Lagrange multiplier)
如此原问题就转化为极大极小的对偶问题
即先将看为变量求其最小,再将
看为变量求其最大
(1)首先求
将对
求偏导并使其=0得到
(2)求的极大
相当于
解得是对偶问题的最优解,便有
分类决策函数为
三、算法代码
这里我们数据集选用鸢尾花数据集,取标签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()
结果如图所示,虚线所标注的就是支持向量所在的直线