基于训练集D在样本空间中找到一个划分超平面,将不同类别的样本分开。
划分超平面
w’x + b = 0
w为超平面的法向量,b是位移项,决定了超平面与原点之间的距离。
支持向量
距离超平面最近的几个训练样本点(到超平面的距离相等)
两个异类支持向量到超平面的额距离之和为r = 2/||w||
目标
欲找到具有“最大间隔”的划分超平面
SVM的基本型
min(w,b) 1/2*||w||^2
s.t. y(i)(w’x(i) + b)>=1 ,i=1,2,…,m (式1)
求解方法:拉格朗日乘子法
问题提出: 前面讨论的是:假设训练样本线性可分,即在原始样本空间中存在一个超平面能将训练样本分类正确。
然而在现实任务中,原始样本空间内也许并不存在一个能正确划分两类样本的超平面。
解决问题: 对于这样的问题, 可将样本从原始空间映射到一个更高维的特征空间,使得样本在这个特征空间内线性可分。
划分超平面
f(x) = w’ h(x) + b
h(x) : 指将 x 映射后的特征向量
** 常用核函数**
解决的问题
合适的核函数难以确定,线性可分的结果是否存在过拟合问题难以确定。
处理方法
引入软间隔,即允许支持向量机在一些样本上出错。
优化目标确定
在最大化软间隔的同时,不满足约束的样本应尽可能少。以此为目标优化。
引入松弛变量,可得软间隔支持向量机。
正则化
正则化可理解为一种“惩罚函数”, 即对不希望得到的结果施以惩罚,从而使得优化过程趋向于希望目标。
基本思路
训练样本D,希望学到一个回归模型 f(x) = w’x + b , 使f(x)与y尽可能接近。
方法
假设能容忍 |f(x) - y| <= Σ,当 |f(x) - y| > Σ
时,计为损失。
解决:拉格朗日乘子法
# 导入包
import matplotlib.pyplot as plt
from sklearn import svm
import numpy as np
# 生成数据
data = np.array([
[0.1, 0.7],
[0.3, 0.6],
[0.4, 0.1],
[0.5, 0.4],
[0.8, 0.04],
[0.42, 0.6],
[0.9, 0.4],
[0.6, 0.5],
[0.7, 0.2],
[0.7, 0.67],
[0.27, 0.8],
[0.5, 0.72]
])
label = [1] * 6 + [0] * 6
x_min, x_max = data[:, 0].min() - 0.2, data[:, 0].max() + 0.2
y_min, y_max = data[:, 1].min() - 0.2, data[:, 1].max() + 0.2
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.002), np.arange(y_min, y_max, 0.002)) # meshgrid 生成网格点坐标矩阵 ,第一个是生成相等的行,第二个是转置后生成相同的列
# 建立模型
# c:惩罚参数,kernel: 核函数
model_linear = svm.SVC(kernel='linear', c=0.001)
# 训练
model_linear.fit(data, label)
# 预测, np.c_按列合并矩阵
z = model_linear.predict(np.c_[xx.ravel(), yy.ravel()])
z = z.reshape(xx.shape)
plt.contourf(xx, yy, z, cmap = plt.cm.ocean, alpha=0.8) # 等高线图 (背景颜色)
plt.scatter(data[:6,0], data[:6, 1],marker='o', color='r', s=100, lw=3)
plt.scatter(data[6:,0], data[6:, 1],marker='x', color='k', s=100, lw=3)
plt.title('Linear SVM')
plt.show()
# 多项式SVM
# 对比不同最高次数的分类情况
plt.figure(figsize=(16,15))
for i, degree in enumerate([1,3,5,7,9,12]): # 返回 enumerate(枚举) 对象。s索引
# C:惩罚系数, gramma: 高斯核的系数
model_poly = svm.SVC(C=0.0001, kernel='poly', degree=degree) #多项式核,默认3
model_poly.fit(data, label)
'''
# ravel - flatten
# c_ - vstack
# 把后面两个压扁之后变成了x1, x2, 然后进行判断,得到结果再压缩成一个矩阵
'''
z = model_poly.predict(np.c_[xx.ravel(), yy.ravel()])
z = z.reshape(xx.shape)
plt.subplot(3, 2, i+1)
plt.subplots_adjust(wspace=0.4, hspace=0.6) # 调整子图间距
plt.contourf(xx, yy, z, cmap=plt.cm.ocean, alpha=0.6)
# 画出训练点
plt.scatter(data[:6, 0], data[:6, 1], marker='o', color='r', s=100, lw=3)
plt.scatter(data[6:, 0], data[6:, 1], marker='x', color='k', s=100, lw=3) # 观察数据形态
plt.title('poly SVM with $\degree=$'+ str(degree))
plt.show()
理论参考:《西瓜书》BY 周志华
代码参考: github: datawhalechina
机器学习学习笔记