支持向量机分类问题(SVC)

基本思想

基于训练集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 映射后的特征向量
** 常用核函数**

  1. 线性核 k(x(i), x(j)) = x’(i)x(j)
  2. 多项式核 k(x(i), x(j)) = (x’(i)x(j))^d d为多项式的次数
  3. 高斯核 k(x(i), x(j)) = exp(-||x(i)-x(j)||^2 / 2*σ^2
  4. 拉普拉斯核
  5. sigmoid核
  6. 核函数的线性组合也为核函数,如:
    (1) 对于任意正数r1, r2
    r1k1+r2k2
    (2) 直线: k1@k2(x,z) = k1(x,z)k2(x,z)
    (3) 对于任意函数g(x)
    k(x,z) = g(x)k1(x,z)g(z)

软间隔和正则化

解决的问题
合适的核函数难以确定,线性可分的结果是否存在过拟合问题难以确定。
处理方法
引入软间隔,即允许支持向量机在一些样本上出错。
优化目标确定
在最大化软间隔的同时,不满足约束的样本应尽可能少。以此为目标优化。
引入松弛变量,可得软间隔支持向量机。
正则化
正则化可理解为一种“惩罚函数”, 即对不希望得到的结果施以惩罚,从而使得优化过程趋向于希望目标。

支持向量回归(SVR)

基本思路
训练样本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()