小杰机器学习(nine)——支持向量机
1. 支持向量机理论讲解
1.1支持向量机(support vector machines. ,SVM)概念
1.支持向量机是一种二类分类模型,它的基本模型是定义在特征空间上的间隔最大的线性分类器,间隔最大使它有别于感知机;
2.支持向量机还包括核技巧,这使它成为实质上的非线性分类器.
3.支持向量机的学习策略就是间隔最大化,可形式化为一个求解凸二次规划(convex quadratic programming)的问题,也等价于正则化的合页损失函数的最小化问题。
4.支持向量机的学习算法是求解凸二次规划的最优化算法.
1.2支持向量机(supportvectormachines. SVM)分类
1.线性可分支持向量机(linear support vector machine in linearly separable case ).
当训练数据线性可分时,通过硬间隔最大化(hard margin maximization);
2.线性支持向量机(linear supportvector machine)
训练数据近似线性可分时,通过软间隔最大化(soft margin maximization);
3.非线性支持向量机(non-linear support vector machine)
当训练数据线性不可分时,通过使用核技巧(kernel trick)及软间隔最大化。
1.3线性可分支持向量机
应用场景 :
1.适用于数据集线性可分的情况,即数据点能够被一个超平面清晰地分割成两类。
2.对噪声敏感,因为它要求所有的样本都严格位于各自的类别一侧,容忍不了任何错误。
3.在训练数据线性可分的情况下,线性可分支持向量机能够找到全局最优解。
学习目标:
1.3.1线性可分支持向量机
下图所示的二维特征空间中的分类问题。图中
表示正例,
表示负例。训练数据集线性可分,这时有很多直线能将两类数据正确划分,线性可分支持向量机对应着两类数据正确划分且间隔最大的直线。
1.3.2点到超平面的距离
要想获得最大间隔,就要计算训练数据集到超平面的距离。
假设二维空间中 点(x,y)到直线Ax+By+C=0的距离公式
扩展到n维空间后,点x=(x1,x2……xn)到超平面的的距离
点在平面的不同侧时,正负号是不同的,法向量指向的一侧为+号,另一侧为-号.
1.3.3函数间隔(functional margin):
1.3.4几何间隔(geometric margin):
1.3.5函数间隔和几何间隔的关系
1.3.6硬间隔最大化
对线性可分的训练集而言,这里的间隔最大化又称为硬间隔最大化。直观解释是对训练集找到几何间隔最大的超平面意味着以充分大的确信度对训练数据进行分类。求最大间隔分离超平面即约束最优化问题:
(解释 s.t. 表示为subject to 约束 后面的式子表示所有的距离都要大于最小间隔 xi表示所有的数据点)
1.3.7几何间隔和函数间隔的关系
问题变为凸二次规划(convex quadratic programming)问题。
1.3.4 得到最终的目标函数和约束如下
到此为止,已经得到了目标函数,如果要继续使用硬间隔去解决问题,那么就需要引入对偶问题和SMO求解,比较复杂,实际上,使用软间隔的较多一些。
这里直接讲述软间隔的使用(代码也是软间隔)
1.4 线性支持向量机
应用场景
1.适用于数据集不是完全线性可分的情况,即数据集中存在一些异常点或噪声。
2.允许一些样本出现在超平面的错误一侧,通过引入松弛变量和损失函数来处理分类错误。
3.对于实际中存在噪声或离群点的情况更具鲁棒性,可以更好地适应复杂的数据分布。
1.4.1线性支持向量机
训练数据中有一些特异点(outlier),不能满足函数间隔大于等于1的约束条件。
1.4.2解决方法:
1.4.2.1松弛变量的引入
在线性可分支持向量机的约束条件中,样本点都要求严格满足
1.4.2.2惩罚参数的引入
目标函数中引入惩罚参数,目标函数变为
1.4.2.3线性支持向量机的学习问题:
1.4.3合页损失函数
线性支持向量机学习还有另外一种解释,就是最小化以下目标函数:
1.线性支持向量机原始最优化问题
1.5 非线性支持向量机
应用场景
之前介绍的硬间隔和软间隔都是指样本完全线性可分或者大部分样本点线性可分的情况,
如果分类问题是非线性的,就要使用非线性支持向量机。主要特点是使用核技巧。
1.5.1非线性分类问题
⽤线性分类⽅法求解⾮线性分类问题分为两步:
第一步:使⽤⼀个变换将原空间的数据映射到新空间。
第二步:在新空间⾥⽤线性分类学习⽅法从训练数据中学习分类模型。
1.5.2 常见的核函数
多项式核函数:
多项式核函数可以实现将低维的输入空间映射到高维的特征空间,但是多项式核函数的参数多,当多项式的阶数比较高的时候,核矩阵的元素值将趋于无穷大或者无穷小,计算复杂度会大到无法计算。
高斯核函数:(存在需要调整的超参数)
高斯径向基函数是一种局部性强的核函数,其可以将一个样本映射到一个更高维的空间内,该核函数是应用最广的一个,无论大样本还是小样本都有比较好的性能,而且其相对于多项式核函数参数要少,因此大多数情况下在不知道用什么核函数的时候,优先使用高斯核函数。
1.5.3核技巧
基本思想是通过⼀个⾮线性变换将输⼊空间对应于⼀个特征空间,使得在输⼊空间中 的超曲⾯模型对应于特征空间中的超平⾯模型 ( ⽀持向量机 ) 。在学习和预测中只定义核函数 K(x,z),⽽不显式地定义映射函数。在实际应⽤中,往往依赖领域知识直接选择核函数。
1.5.4非线性支持向量机学习算法
选取适当的核函数 K(x,z) 和适当的参数 C,将线性⽀持向量机对偶形式中的内积换成核函数,构造并求解最优化问题。
代码实现:
import numpy as np
import matplotlib.pyplot as plt# 定义数据
class1_points = np.array([[1.9, 1.2],[1.5, 2.1],[1.9, 3.5],[1.5, 4.9],[0.9, 5.2],[1.1, 6.7],[1.4, 7.1]])class2_points = np.array([[3.2, 1.2],[3.7, 2.9],[3.2, 3.6],[3.7, 4.3],[3.4, 5.6],[4.1, 6.3],[3.0, 7.9]])# 将两个特征单独提取
x1_data = np.concatenate((class1_points[:, 0], class2_points[:, 0]))
x2_data = np.concatenate((class1_points[:, 1], class2_points[:, 1]))
y = np.concatenate((np.ones(class1_points.shape[0]), -np.ones(class2_points.shape[0])))# 参数初始化
w1 = 0.1
w2 = 0.1
b = 0.3
learning_rate = 0.01
num_iterations = 5000# 显示子图
fig, (ax1,ax2) = plt.subplots(2, 1)
step_list = np.array([])
loss_values = np.array([])for n in range(1, num_iterations + 1):z = w1 * x1_data + w2 * x2_data + byz = y * z# hinge lossloss = 1 - yzloss[loss < 0] = 0hinge_loss = np.mean(loss)# 加上正则化项total_loss = 0.5* (w1 ** 2 + w2 ** 2) + hinge_lossloss_values = np.append(loss_values, total_loss)step_list = np.append(step_list, n)# 计算梯度(带正则化)gradient_w1 = w1 # 来自 0.5 * w1^2 的导数gradient_w2 = w2 # 来自 0.5 * w2^2 的导数gradient_b = 0for i in range(len(y)):if loss[i] > 0: # 只有 margin < 1 的点会影响梯度gradient_w1 += -y[i] * x1_data[i] / len(y)gradient_w2 += -y[i] * x2_data[i] / len(y)gradient_b += -y[i] / len(y)# 更新参数w1 -= learning_rate * gradient_w1w2 -= learning_rate * gradient_w2b -= learning_rate * gradient_b# 显示频率设置frequence_display = 50if n % frequence_display == 0 or n == 1:if np.abs(w2) < 1e-5:continuex1_min, x1_max = 0, 6x2_min, x2_max = -(w1 * x1_min + b) / w2, -(w1 * x1_max + b) / w2ax1.clear()ax1.scatter(x1_data[:len(class1_points)], x2_data[:len(class1_points)], c='red', label='Class 1')ax1.scatter(x1_data[len(class1_points):], x2_data[len(class1_points):], c='blue', label='Class 2')ax1.plot((x1_min, x1_max), (x2_min, x2_max), 'r-')ax1.set_xlim(-10,10)ax1.set_ylim(-10,10)ax1.set_title(f"SVM: w1={round(w1, 3)}, w2={round(w2, 3)}, b={round(b, 3)}")# 绘制损失图ax2.clear()ax2.plot(step_list, loss_values, 'g-')ax2.set_xlabel("Step")ax2.set_ylabel("Loss")plt.pause(0.5)plt.show()