概念
目录
什么是支持向量机
支持向量机是一种经典的机器学习方法,在数据量小等条件下其性能仍优于神经网络。
引言
如果用苹果的颜色和大小来判断苹果是否成熟,你觉得哪种方法更合适?
通过近邻的几个苹果样本判断。
设定颜色和大小的阈值,当苹果超过该阈值时认定为成熟。显然,上图中红色直线的分类效果比绿色直线的更好。
那么,我们应如何选取一条直线使得分类效果达到最好?这就是支持向量机所探讨的问题。
间隔与支持向量
线性可分和线形不可分
给定一个数据集
能够将数据集的正样本(+1)和负样本(-1)完全正确地划分到超平面的两侧,即:
- 对所有 𝑦𝑖=+1𝑦𝑖=+1 的样本 𝑖𝑖,有 𝒘T𝒙+𝑏>0𝑤T𝑥+𝑏>0
- 对所有 𝑦𝑖=−1𝑦𝑖=−1 的样本 𝑖𝑖,有 𝒘T𝒙+𝑏<0𝑤T𝑥+𝑏<0
则称数据集 𝑇𝑇 为线性可分数据集(linearly separable data set)。
若不存在超平面能够将样本完全正确地划分,则称数据集 𝑇𝑇 线性不可分。
函数间隔和几何间隔
函数间隔
|𝒘T𝒙+𝑏| 能够表示点 𝒙𝑥距离超平面的远近,而 𝒘T𝒙+𝑏𝑤T𝑥+𝑏 的符号与类标记 𝑦 的符号是否一致可表示分类是否正确。
因此,可用 𝑦(𝒘T𝒙+𝑏)𝑦(𝑤T𝑥+𝑏) 来表示分类的正确性及确信度,这就是函数间隔(functional margin)的概念。
对于给定的训练数据集 𝑇 和超平面 (𝒘,𝑏),定义超平面 (𝒘,𝑏)关于样本点 (𝒙𝑖,𝑦𝑖) 的函数间隔为
定义超平面 (𝒘,𝑏) 关于训练数据集 𝑇的函数间隔为超平面 (𝒘,𝑏)关于 𝑇 中所有样本点 (𝒙𝑖,𝑦𝑖) 的函数间隔的最小值,即
几何间隔
函数间隔可以表示分类预测的正确性和确信度。但在选择分离超平面时,仅用函数间隔还不够
因为只要成比例的改变 𝒘 和 𝑏,例如 2𝒘 和 2𝑏,超平面并没有改变,但函数间隔却成为原来的2倍。
我们可以对分离超平面的法向量 𝒘𝑤加某些约束,如规范化,‖𝒘‖=1,使间隔是确定的。
此时,函数间隔便成为几何间隔(geometric margin)
令 ‖𝒘‖ 表示 𝒘 的 𝐿2范数,对于给定的训练数据集 𝑇和超平面 (𝒘,𝑏),定义超平面 (𝒘,𝑏) 关于样本点 (𝒙𝑖,𝑦𝑖) 的几何间隔为
定义超平面 (𝒘,𝑏) 关于训练数据集 𝑇𝑇的几何间隔为超平面 (𝒘,𝑏) 关于 𝑇 中所有样本点 (𝑥𝑖,𝑦𝑖)的几何间隔的最小值,即
超平面 (𝒘,𝑏) 关于样本点 (𝑥𝑖,𝑦𝑖) 的几何间隔表示样本点到超平面的带符号的距离(signed distance)。
当样本点被正确分类时,几何间隔成为样本点到超平面的距离。
支持向量
距离超平面最近的几个点,将之称为支持向量(support vector)。
SVM的基本型
上图中两个异类支持向量到超平面的距离之和为
它被称为间隔(margin)。
通过转化可以得到
这就是支持向量机(Support Vector Machine, SVM)的基本型。
对偶问题
对 SVM 基本型使用拉格朗日乘子法可得到其对偶问题(dual problem)
根据拉格朗日对偶性,原始问题的对偶问题是极大极小问题
为了得到对偶问题的解,需要先求 𝐿(𝒘,𝑏,𝜶)对𝒘,𝑏的极小,再求对 𝜶 的极大。
核技巧
非线性问题往往不好求解,所以希望能用解线性分类问题的方法解决这个问题。
我们可以进行一个非线性变换,将非线性问题转化为线性问题,通过解变换后的线性问题的方法求解原来的非线性问题。
利用核技巧(kernel trick),我们可以用线性分类方法求解非线性分类问题,步骤如下
- 使用一个变换将原空间的数据映射到新空间(特征空间)
- 在新空间中用线性分类学习方法从训练数据中学习分类模型
如果原始样本空间是有限维,那么一定存在一个高维特征空间使样本可分。
常见的核函数如下:
代码
导入库
from sklearn.svm import SVC
from sklearn import datasets
import numpy as np
import matplotlib.pyplot as plt
import math
数据集
iris = datasets.load_iris()
X = iris['data'][:,(2,3)]
y = iris["target"]
setosa_or_versicolor = (y==0)|(y==1)
X = X[setosa_or_versicolor]
y = y[setosa_or_versicolor]
训练模型
svm_clf = SVC(kernel='linear',C=float(1000000000000))
svm_clf.fit(X,y)
决策边界
def plot_svc_decision_boundary(svm_clf, xmin, xmax, sv=True):
w = svm_clf.coef_[0]
b = svm_clf.intercept_[0]
x0 = np.linspace(0,5.5,200)
decision_boundary = -w[0]/w[1]*x0-b/w[1]
margin = 1/w[1]
gutter_up = decision_boundary + margin
gutter_down = decision_boundary - margin
if sv:
svs = svm_clf.support_vectors_
plt.scatter(svs[:,0],svs[:,1],s=180,facecolors = "#FFAAAA")
plt.plot(x0,decision_boundary,"k-",linewidth=2)
plt.plot(x0,gutter_up,"k--",linewidth=2)
plt.plot(x0,gutter_down,"k--",linewidth=2)
对比
x0 = np.linspace(0,5.5,200)
pred_1 = 5*x0 - 20
pred_2 = x0 -1.8
pred_3 = 0.1*x0 + 0.5
画图
plt.figure(figsize=(14,4))
plt.subplot(121)
plt.plot(X[:,0][y==1],X[:,1][y==1],'bs')
plt.plot(X[:,0][y==0],X[:,1][y==0],'ys')
plt.plot(x0,pred_1,"g-",linewidth=2)
plt.plot(x0,pred_2,"m-",linewidth=2)
plt.plot(x0,pred_3,"r-",linewidth=2)
plt.axis([0,5.5,0,2])
plt.subplot(122)
plot_svc_decision_boundary(svm_clf,0,5.5)
plt.plot(X[:,0][y==1],X[:,1][y==1],'bs')
plt.plot(X[:,0][y==0],X[:,1][y==0],'ys')
plt.axis([0,5.5,0,2])
plt.show()
运行结果
结论
训练好的模型的算法复杂度是由支持向量的个数决定的,而不是由数据的维度决定的。所以 SVM 不太容易产生 overfitting。
SVM 训练出来的模型完全依赖于支持向量,即使训练集里面所有非支持向量的点都被去除,重复训练过程,结果仍然会得到完全一样的模型。
一个 SVM 如果训练得出的支持向量个数比较少,那么SVM 训练出的模型比较容易被泛化。