一、概念
支持向量机(SVM)是一类按监督学习方式对数据进行二元分类的广义线性分类器,其决策边界是对学习样本求解的最大边距超平面,可以将问题化为一个求解凸二次规划的问题。与逻辑回归和神经网络相比,支持向量机,在学习复杂的非线性方程时提供了一种更为清晰,更加强大的方式。
具体来说就是在线性可分时,在原空间寻找两类样本的最优分类超平面。在线性不可分时,加入松弛变量并通过使用非线性映射将低维度输入空间的样本映射到高维度空间使其变为线性可分,这样就可以在该特征空间中寻找最优分类超平面。
SVM使用准则:n为特征数,m为训练样本数。
如果相较于m而言,n要大许多,即训练集数据量不够支持我们训练一个复杂的非线性模型,我们选用逻辑回归模型或者不带核函数的支持向量机。
如果n较小,而且m大小中等,例如n在 1-1000 之间,而m在10-10000之间,使用高斯核函数的支持向量机。
如果n较小,而m较大,例如n在1-1000之间,而𝑚大于50000,则使用支持向量机会非常慢,解决方案是创造、增加更多的特征,然后使用逻辑回归或不带核函数的支持向量机。
二、支持向量机
1、超平面
在维度为1时,我们可以找到一个点来分开两类的样本。在维度为2时,我们可以找到一条直线来分开两类样本。在维度为3时,我们也可以找到一个平面来分开两类样本。即维度为n时,我们可以找到一个维度为n-1的超平面来对样本进行分类。总之,将数据集分隔开的直线或者平面叫做超平面。下图为超平面示意图及超平面公式:
2、间隔
间隔指的是数据点到超平面的距离
线性可分
硬间隔
假如数据是完全线性可分的,即数据的分类完全正确,不存在错误分类的情况下,即称我们学习出来的模型叫做硬间隔支持向量机
软间隔
允许数据的分类存在一定量的错误,即称我们学习到的模型成为软间隔支持向量机。但相应的需要增加一个惩罚项。
线性不可分
倘若两类数据无法进行线性分类,则称这种情况为线性不可分。
3、支持向量
在支持向量机中,距离超平面最近的且满足一定条件的几个训练样本点被称为支持向量
4、核函数
支持向量机算法分类和回归方法的中都支持线性性和非线性类型的数据类型。非线性类型通常是二维平面不可分,为了使数据可分,需要通过一个函数将原始数据映射到高维空间,从而使得数据在高维空间很容易可分,这样就达到数据分类或回归的目的,而实现这一目标的函数称为核函数。
工作原理:当低维空间内线性不可分时,可以通过高位空间实现线性可分。但如果在高维空间内直接进行分类或回归时,则存在确定非线性映射函数的形式和参数问题,而最大的障碍就是高维空间的运算困难且结果不理想。通过核函数的方法,可以将高维空间内的点积运算,巧妙转化为低维输入空间内核函数的运算,从而有效解决这一问题。
常用的核函数有:线性核函数,多项式核函数,径向基核函数,Sigmoid核函数和复合核函数,傅立叶级数核,B样条核函数和张量积核函数等 。
三、线性可分支持向量机
1、目标
线性可分支持向量机(Linear SVM)是一种用于二分类问题的监督学习算法。它的目标是在特征空间中找到一个超平面,使得不同类别的样本能够被该超平面很好地分割开来,并且离超平面最近的样本点(支持向量)到超平面的距离尽可能大。这需要寻找到一组最好的w和b来定位超平面。
2、推导
1、假设有一个二分类问题,训练集为,
,
,
。
2、我们希望找到一个超平面,
是超平面的法向量,
是超平面的偏置项,使得对于所有的样本点
,都有
。
3、为了找到最优的超平面,我们需要最大化离超平面最近的样本点到超平面的距离(即最大化间隔)。可以证明,这个距离等于 。因此,我们的优化目标可以表示为
,
。
4、为了方便求解,我们可以等价地将优化目标改写为,
。
5、这是一个带不等式约束的凸二次规划问题,可以使用拉格朗日乘子法求解。引入拉格朗日乘子,得到拉格朗日函数
。
6、根据拉格朗日对偶性,原问题可以转化为等价的对偶问题:,
,
7、求解对偶问题得到最优解,然后可以计算出原问题的最优解
,选择任意满足
的样本点
,计算偏置项
8、最终得到的线性可分支持向量机的分类决策函数为
四、代码实现
1、数据集的准备
X = np.array([
[1, 7],
[2, 8],
[3, 8],
[7, 2],
[8, 3],
[8, 1]
])
labels = np.array([0, 0, 0, 1, 1, 1])
2、利用梯度下降训练支持向量机
# 支持向量机模型的训练
def svm_train(X, y, C=1.0, lr=0.001, epochs=1000):
n_samples, n_features = X.shape # 获取样本数量和特征数量
weights = np.zeros(n_features) # 初始化权重向量
bias = 0 # 初始化偏置项
# 调整标签,将0标签转换为-1
y_transformed = np.where(y==0, -1, 1)
for epoch in range(1, epochs + 1): # 迭代训练epochs次
for idx, x_i in enumerate(X): # 遍历每个样本
condition = y_transformed[idx] * (np.dot(x_i, weights) + bias) >= 1 # 判断样本是否满足SVM约束条件
if not condition: # 如果不满足约束条件,则更新权重和偏置
weights -= lr * (2 * 1/epoch * weights - np.dot(x_i, y_transformed[idx])) # 更新权重
bias -= lr * y_transformed[idx] # 更新偏置
else:
weights -= lr * 2 * 1/epoch * weights # 如果满足约束条件,则仅更新权重
return weights, bias # 返回训练好的权重和偏置
weights, bias = svm_train(X, labels) # 训练SVM模型
# 调用svm_train函数训练模型并获取权重和偏置
weights, bias = svm_train(X, labels)
# 打印训练后的权重和偏置
print("Trained weights:", weights)
print("Trained bias:", bias)
该函数用于训练支持向量机模型,输入参数包括数据集X,标签y,正则化参数C(默认为1.0),学习率lr(默认为0.001)和迭代次数epochs(默认为1000)。在函数内部,首先初始化权重向量weights和偏置项bias。将标签y中的0转换为-1,以符合支持向量机的约束条件。然后进行多次迭代训练,遍历每个样本并根据约束条件更新权重和偏置。如果样本不满足约束条件(不在间隔边界上),则按照梯度下降更新权重和偏置;如果满足约束条件,则仅更新权重。最终返回训练好的权重weights和偏置bias。
3、对训练模型进行预测
# 预测
def svm_predict(X, weights, bias):
return np.sign(np.dot(X, weights) + bias) # 使用训练好的权重和偏置对样本进行预测
predictions = svm_predict(X, weights, bias) # 对样本进行预测
该函数接受输入参数包括数据集X、训练好的权重weights和偏置bias。使用训练好的权重和偏置来计算每个样本在模型下的预测值。预测值通过计算数据集X与权重weights的点积(内积),加上偏置bias,然后通过符号函数np.sign将结果转换为1(正类别)或-1(负类别)。最终返回预测结果,即对每个样本的类别进行预测。
4、利用hinge函数对模型分类进行损失评估
def calculate_loss(X, y, weights, bias):
n_samples = X.shape[0]
regularization_strength = 1 / 2 # 正则化强度参数
hinge_loss = np.maximum(0, 1 - y * (np.dot(X, weights) + bias))
data_loss = np.sum(hinge_loss) / n_samples
regularization_loss = regularization_strength * np.dot(weights, weights)
total_loss = data_loss + regularization_loss
return total_loss
# 计算训练后模型的损失
loss = calculate_loss(X, labels, weights, bias)
print("Total Loss:", loss)
用于计算线性支持向量机 (SVM) 模型的损失。损失函数包括数据损失(hinge loss)和正则化损失。函数采用训练数据 X、目标标签 y、模型权重 weights 和偏置 bias 作为输入.当分类正确时损失为0,发呢类不正确是损失为hinge_loss。
5、对分类后的数据进行图像输出
# 计算训练后模型的损失
loss = calculate_loss(X, labels, weights, bias)
print("Total Loss:", loss)
# 绘制分类图像
def plot_svm_decision_boundary(X, y, weights, bias):
plt.figure(figsize=(10, 6))
# 绘制数据点
plt.scatter(X[y == 0][:, 0], X[y == 0][:, 1], color='red', marker='o', label='Class 0')
plt.scatter(X[y == 1][:, 0], X[y == 1][:, 1], color='blue', marker='x', label='Class 1')
# 绘制分类边界
x0_min, x0_max = min(X[:, 0]) - 1, max(X[:, 0]) + 1
x1_min, x1_max = min(X[:, 1]) - 1, max(X[:, 1]) + 1
xx, yy = np.meshgrid(np.linspace(x0_min, x0_max, 500), np.linspace(x1_min, x1_max, 500))
Z = svm_predict(np.c_[xx.ravel(), yy.ravel()], weights, bias)
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, levels=[-1, 0, 1], alpha=0.3, colors=['red', 'blue'])
plt.contour(xx, yy, Z, levels=[0], linewidths=2, colors=['black'])
plt.xlim(x0_min, x0_max)
plt.ylim(x1_min, x1_max)
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.legend()
plt.title('SVM Decision Boundary')
plt.show()
plot_svm_decision_boundary(X, labels, weights, bias)
输出的图像:
分类正确,并且距离超平面最近点的距离最大。
训练结果为:
五、总结
SVM的优缺点
优点:
支持向量机算法可以解决小样本情况下的机器学习问题,简化了通常的分类和回归等问题。
由于采用核函数方法克服了维数灾难和非线性可分的问题,所以向高维空间映射时没有增加计算的复杂性。换句话说,由于支持向量计算法的最终决策函数只由少数的支持向量所确定,所以计算的复杂性取决于支持向量的数目,而不是样本空间的维数。
支持向量机算法利用松弛变量可以允许一些点到分类平面的距离不满足原先要求,从而避免这些点对模型学习的影响。
缺点:
支持向量机算法对大规模训练样本难以实施。这是因为支持向量机算法借助二次规划求解支持向量,这其中会涉及m阶矩阵的计算,所以矩阵阶数很大时将耗费大量的机器内存和运算时间。
经典的支持向量机算法只给出了二分类的算法,而在数据挖掘的实际应用中,一般要解决多分类问题,但支持向量机对于多分类问题解决效果并不理想。
SVM算法效果与核函数的选择关系很大,往往需要尝试多种核函数,即使选择了效果比较好的高斯核函数,也要调参选择恰当的 gamma 参数。另一方面就是现在常用的SVM理论都是使用固定惩罚系数 C,但正负样本的两种错误造成的损失是不一样的。
自身体会
SVM算法的核心思想是训练最佳超平面,并通过距离超平面最近的点的最远距离来进行分类。它可对线性和非线性数据进行分类处理。可以通过对权重和偏置的不断调整来使分类效果最佳。支持向量机还对小样本类和高维数据的问题具有高效稳健的特点。