支持向量机的算法原理与Python实现
支持向量机(Support Vector Machine,SVM)是一种强大的监督学习算法,用于分类和回归任务。其核心思想是在高维空间中找到一个最优的超平面,将不同类别的数据分开。SVM的关键在于找到支持向量,即离超平面最近的数据点,这些支持向量决定了超平面的位置和方向。SVM通过最大化支持向量与超平面的间隔来实现分类,这个间隔被称为“间隔最大化”。对于非线性可分的数据,SVM可以通过核函数将数据映射到更高维的空间中,从而使其线性可分,常用的核函数有线性核、多项式核和高斯核等。SVM具有良好的泛化能力和鲁棒性,适用于处理小样本、高维度数据,并且不易受到局部极小值的影响。
一、支持向量机原理与数学描述
感知机算法使用误分类样本到分隔超平面的距离作为损失函数,通过最小化该距离调整参数ww和bb以得到最终的超平面。然而,初始参数和选择的误分类样本不同会导致不同的超平面。支持向量机通过在各种可能的超平面中选择最佳者来解决这个问题,考虑到参数的初值和误分类样本的影响,以此实现更好的分类效果。
线性向量支持 | 非线性向量支持 |
---|---|
![]() |
![]() |
2.1 线性可分支持向量机
给定一个线性可分的训练集,T={(x1,y1),(x2,y2),...,(xN,yN)}T={(x1,y1),(x2,y2),...,(xN,yN)}找到一个间隔最大的分隔超平面w∗⋅x+b∗=0w∗⋅x+b∗=0(确定w∗w∗和b∗b∗),将两类数据正确划分。分类确信度,一个正类样本点,被预测为正类,如果样本点距离超平面越近,预测结果的确信度越高,反之越低。负类样本亦如此。为了能表示分类预测的确信度,需要定义函数间隔和几何间隔。
对于给定的训练数据集TT和超平面 (w,b)(w,b), 函数间隔定义:
- 超平面 (w,b)(w,b) 关于样本点 (xi,yi)(xi,yi) 的函数间隔为:
- 超平面 (w,b)(w,b) 关于训练数据 TT 的函数间隔为 所有样本点 (xi,yi)(xi,yi) 的函数间隔最小值:
几何间隔是对分隔超平面的参数 WW 加上一个约束,即归一化 ∣W‖=1∣W∥=1 ,对于给定的训练数据集T和超平面 (w,b)(w,b) ,几何间隔定义:
- 超平面 (w,b)(w,b) 关于样本点 (xi,yi)(xi,yi) 的几何间隔为:
- 超平面 (w,b)(w,b) 关于训练数据 TT 的几何间隔为所有样本点 (xi,yi)(xi,yi) 的几何间隔最小值:
- 函数间隔和几何间隔的关系如下:
几何间隔最大的超平面:
考虑到函数间隔和几何间隔的关系,该最优化问题可改写为:
由于当 w 和 b同时扩大 2 倍,函数间隔 ˆγ 也会同时扩大为原来的 2 倍,这对于上述的优化问题和约束条件并没有影响,因此,可取 ˆγ=1 ,则上述最优化问题变成:
SVM求解分隔超平面要满足两个条件:正确划分训练数据集;几何间隔最大,即距离分隔超平面最近的点的几何间隔最大。
2.2 支持向量和间隔边界
在线性可分情况下,训练数据集的样本点中与分隔超平面距离最近的样本点称为支持向量。
硬间隔 | 支持向量和间隔 |
---|---|
![]() |
![]() |
支持向量Xi对应的约束条件为:y(i)(w⋅X(i)+b)−1=0。当y(i)=+1时,支持向量所在的超平面为:H1:w⋅X+b=1;当y(i)=−1时,支持向量所在的超平面为:H2:w⋅X+b=−1,在确定最终的分隔超平面时,只有支持向量起作用,其他的样本点不起作用。
2.3 对偶算法
怎样求解线性可分支持向量机的最优化问题?根据拉格朗日对偶性,将原始问题转化为对偶问题,通过求解对偶问题的最优解,然后进一步求解就得原始问题的最优解和,这就是线性可分支持向量机的对偶算法。采用对偶算法的优点,一是对偶算法往往更容易求解,二是自然的引入核函数,进而推广到非线性分类的问题。
对每个不等式约束引入拉格朗日乘子αi ,将其转化为无约束的最优化问题求解,定义以下拉格朗日函数:
其中, α=(α1,α2,⋯,αN)T 为非负的拉格朗日乘子向量。
根据拉格朗日对偶性,得到等价的对偶问题:
!!!(xi⋅xj)表示两个向量的内积。
对线性可分训练数据集,假设对偶最优化问题对 α 的解为 α∗=(α∗1,α∗2,…,α∗N)T ,可以由 α∗ 求得原始最优化问题对 w 和 b 的最优解 w∗ 和 b∗ 。
输入: 线性可分训练集 T={(x1,y1),(x2,y2),⋯,(xN,yN)}, 其中 xi∈X=Rn, yi∈Y={−1,+1},i=1,2,⋯,N;
输出: 分离超平面和分类决策函数。
(1) 构造并求解约束最优化问题minα12∑Ni=1∑Nj=1αiαjyiyj(xi⋅xj)−∑Ni=1αi s.t. ∑Ni=1αiyi=0αi⩾0,i=1,2,⋯,N求得最优解 α∗=(α∗1,α∗2,⋯,α∗N)T 。
(2) 计算w∗=N∑i=1α∗iyixi并选择 α∗ 的一个正分量 α∗j>0, 计算
b∗=yj−N∑i=1α∗iyi(xi⋅xj)(3)求得分离超平面
w∗⋅x+b∗=0分类决策函数:
f(x)=sign(w∗⋅x+b∗)
例:假设有三个样本点,其中正例 X1(3,3)、X2(4,3),负例 X3(1,1),求解:
约束条件为:
将数据代入求解公式可得:
由于 ai+a2−a3=0, 化简可得:
分别对 a1 和 a2 求偏导,令偏导等于0 ,可得,
这显然与 ai≥0 相违背,所以解应该在边界上,分别令 a1=0, 得 a2=−213, 同样不满足条件。令 a2=0,满足条件,可得最小值在 (0.25,0,0.25) 取得。将 a 的取值代入
可得
故超平面方程为: 0.5x1+0.5x2−2=0
2.4 非线性支持向量机
对于非线性的分类问题,可以使用非线性支持向量机。非线性问题往往不好求解,通常采取的方法是进行一个非线性变换,将非线性问题变换成线性问题,通过求解变换后的线性问题的方法来求解原来的非线性问题。常常采用核技巧(使用一个线性变换将原空间的数据映射到新空间,然后在新空间里用线性分类学习方法从训练数据中学习分类模型。),核技巧应用到支持向量机的思想是,通过一个非线性变换将输入空间(欧氏空间)对应一个特征空间(希尔伯特空间),使得再输入空间中的超曲面模型对应于特征空间中的超平面模型,这样,分类问题的学习任务通过在特征空间中求解线性支持向量机就可以完成。
核函数的作用是在不显式计算高维特征空间的情况下,隐式地将样本映射到高维空间。这样可以避免直接计算高维特征空间的复杂性,而只需要在低维空间中进行计算,常用的核函数如下表所示。
名称 | 表达式 | 参数 |
---|---|---|
线性核 | κ(xi,xj)=x⊤ixj | |
多项式核 | κ(xi,xj)=(x⊤ixj)d | d≥1 为多项式的次数 |
高斯核 | κ(xi,xj)=exp(−|xi−xj|22δ2) | δ>0 为高斯核的带宽(width) |
拉普拉斯核 | κ(xi,xj)=exp(−|xi−xj|δ) | δ>0 |
Sigmoid核 | κ(xi,xj)=tanh(βx⊤ixj+θ) | tan 为双曲正切函数,β>0,θ<0 |
非线性支持向量机学习算法:
输入: 训练数据集 T={(x1,y1),(x2,y2),⋯,(xN,yN)}, 其中 xi∈X=Rn,yi∈ Y={−1,+1},i=1,2,⋯,N;
输出: 分类决策函数。
(1)选取适当的核函数 K(x,z) 和适当的参数 C, 构造并求解最优化问题minα12∑Ni=1∑Nj=1αiαjyiyjK(xi,xj)−∑Ni=1αi s.t. ∑Ni=1αiyi=00⩽αi⩽C,i=1,2,⋯,N求得最优解 α∗=(α∗1,α∗2,⋯,α∗N)T 。
(2) 选择 α∗ 的一个正分量 0<α∗j<C, 计算b∗=yj−N∑i=1α∗iyiK(xi,xj)(3)构造决策函数:
f(x)=sign(N∑i=1α∗iyiK(x,xi)+b∗)
三、支持向量机回归
图1 | 图2 |
---|---|
![]() |
![]() |
传统的回归模型通常直接基于模型输出 f(x) 与真实输出 y 之间的差值来计算损失,当模型输出和真实输出完全相同时,损失才为零。支持向量回归能容忍 f(x) 和 y 之间最多有 ε 的偏差,仅当 f(x) 与 y 之间差别绝对值大于 ε 时才计算损失。如上图1所示,相当于以 f(x) 为中心,构建了一个宽度为 2ε 的间隔带,若训练样本落入间隔带,则认为时被预测正确的。
SVR问题可形式化为:
其中, ℓϵ(z)={0, if |z|⩽ϵ;|z|−ϵ, otherwise ,见图2所示。
由于间隔带两侧的松他程度可不同,引入松驰变量 ξ 和 ˆξi ,优化函数为:
四、支持向量机和回归的Python实现
4.1 支持向量机
import mglearn
import matplotlib.pyplot as plt
from sklearn.svm import SVC
# 假设 mglearn.tools.make_handcrafted_dataset() 是一个存在的函数,
# 它将返回一些手工制作的特征数据 X 和对应的标签 y
X, y = mglearn.tools.make_handcrafted_dataset()
# 使用 RBF 核的 SVC 模型,C=10, gamma=0.1
svm = SVC(kernel='rbf', C=10, gamma=0.1).fit(X, y)
# 使用 mglearn 可视化工具绘制二维分隔线
mglearn.plots.plot_2d_separator(svm, X, eps=.5)
# 绘制数据点
mglearn.discrete_scatter(X[:, 0], X[:, 1], y)
# 绘制支持向量
sv = svm.support_vectors_
# 支持向量的类别标签由对偶系数的符号决定
sv_labels = svm.dual_coef_.ravel() > 0
mglearn.discrete_scatter(sv[:, 0], sv[:, 1], sv_labels, s=20, markeredgewidth=5)
# 设置坐标轴标签
plt.xlabel("feature0")
plt.ylabel("feature1")
# 显示图形
plt.show()
4.2 支持向量机回归
使用Python自带的波士顿房价数据集作为数据集,并将其分为按三七开分为data_train和data_test数据集。该数据集中“y1”为响应变量,为房屋总价,而x1-x9为特征变量,依次表示房屋的卧室数量、客厅数量、面积、装修情况、有无电梯、房屋所在楼层位置、有无地铁、关注度、看房次数共计9项。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn import preprocessing
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.svm import SVR
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
from sklearn.datasets import load_boston
# 加载波士顿房价数据集
boston = load_boston()
data = pd.DataFrame(boston.data, columns=boston.feature_names)
data['y1'] = boston.target
# 打印数据集的前10行
print("波士顿房价数据集前10行:")
print(data.head(10))
# 划分特征和响应变量
X = data.drop('y1', axis=1)
y = data['y1']
# 数据标准化
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# 划分训练集和测试集
data_train, data_test, y_train, y_test = train_test_split(X_scaled, y, test_size=0.3, random_state=42)
# 使用径向基核函数(rbf)的支持向量机回归模型
model_rbf = SVR(kernel='rbf')
model_rbf.fit(data_train, y_train)
y_pred_rbf = model_rbf.predict(data_test)
score_rbf = model_rbf.score(data_test, y_test)
mse_rbf = mean_squared_error(y_test, y_pred_rbf)
mae_rbf = mean_absolute_error(y_test, y_pred_rbf)
r2_rbf = r2_score(y_test, y_pred_rbf)
coef_rbf = model_rbf.dual_coef_[0]
intercept_rbf = model_rbf.intercept_[0]
print("\n径向基核函数(rbf)支持向量机回归模型结果:")
print("拟合优度:", score_rbf)
print("均方误差(MSE):", mse_rbf)
print("平均绝对误差(MAE):", mae_rbf)
print("R^2决定系数:", r2_rbf)
print("回归关系式: y = ", end="")
for i in range(len(coef_rbf)):
print(f"{coef_rbf[i]} * x{i} + ", end="")
print(intercept_rbf)
# 绘制预测值与真实值比较图
plt.figure(figsize=(10, 6))
plt.scatter(y_test, y_pred_rbf, color='blue', label='Predicted')
plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], '--', color='red', label='Actual')
plt.title("Comparison of Predicted and Actual Values (SVR with RBF Kernel)")
plt.xlabel("Actual Values")
plt.ylabel("Predicted Values")
plt.legend()
plt.grid(True)
plt.show()
4.3 非线性支持向量机
# 导入所需库
from sklearn.preprocessing import PolynomialFeatures, StandardScaler
from sklearn.svm import LinearSVC
import numpy as np
from sklearn import datasets
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
# 数据准备与可视化模块
# 生成数据集并进行初步可视化
def prepare_data_and_plot():
X_o, y = datasets.make_moons(noise=0.15, random_state=4)
plt.scatter(X_o[y==0, 0], X_o[y==0, 1], c='red') # 绘制红色点表示第一类数据
plt.scatter(X_o[y==1, 0], X_o[y==1, 1], c='blue') # 绘制蓝色点表示第二类数据
plt.show()
return X_o, y # 返回生成的数据集
# 特征转换与模型训练模块
# 对原始数据进行多项式特征转换并进行标准化处理
# 训练非线性支持向量机模型
def transform_features_and_train_model(X_o, y):
poly = PolynomialFeatures(degree=3)
X = poly.fit_transform(X_o)
scaler = StandardScaler() # 标准化处理
scaler.fit(X)
X = scaler.transform(X)
svc = LinearSVC(C=1000) # 线性支持向量机,但作用在多项式特征上实现非线性分类
svc.fit(X, y)
return svc, poly, scaler
# 绘制决策边界模块
# 使用模型预测网格上的点,并绘制决策边界
def plot_decision_boundary(svc, poly, scaler, X_o, y):
x_plot = np.linspace(-1.5, 2.5, 100)
y_plot = np.linspace(-1.0, 1.5, 100)
x_plot, y_plot = np.meshgrid(x_plot, y_plot)
x_axis = x_plot.reshape(100*100, 1)
y_axis = y_plot.reshape(100*100, 1)
X_grid = scaler.transform(poly.transform(np.hstack((x_axis, y_axis)))) # 这里不需要fit_transform,只需要transform
y_predict = svc.predict(X_grid)
zz = y_predict.reshape(100, 100)
custom_cmap = ListedColormap(['#EF9A9A', '#FFF59D', '#90CAF9']) # 自定义颜色映射(这里实际只需要两种颜色)
plt.contourf(x_plot, y_plot, zz, linewidth=5, cmap=custom_cmap)
plt.scatter(X_o[y==0, 0], X_o[y==0, 1], c='red', s=100) # 绘制原始数据点
plt.scatter(X_o[y==1, 0], X_o[y==1, 1], c='blue', s=100)
plt.show()
# 主程序
if __name__ == "__main__":
# 调用数据准备与可视化模块并接收返回值
X_o, y = prepare_data_and_plot()
# 调用特征转换与模型训练模块
svc, poly, scaler = transform_features_and_train_model(X_o, y)
# 调用绘制决策边界模块
plot_decision_boundary(svc, poly, scaler, X_o, y)
图1 | 图2 |
---|---|
![]() |
![]() |
总结
支持向量机(Support Vector Machine,简称SVM)算法是机器学习领域中的一种重要方法,尤其在分类和回归分析中展现出强大的性能。SVM算法在多个领域都有着广泛的应用,以下列举几个典型的例子:
图像识别:SVM算法能够处理高维数据,因此在图像识别领域具有独特的优势。图像可以表示为像素点的向量,而每个像素点都可以表示为颜色或灰度值。这些像素值可以用于训练SVM模型,从而实现对不同物体的识别。例如,SVM算法可以用于医学图像分析,检测病变和肿瘤,并对其进行分类。
文本分类:SVM算法在文本分类任务中也表现出色。它可以学习不同文本的特征,并在分类时使用这些特征。例如,SVM可以用于垃圾邮件检测,通过分析邮件中的特定单词或短语,将垃圾邮件与非垃圾邮件区分开来。此外,SVM还可以用于情感分析,判断文本所表达的情感倾向。
金融预测:在金融领域,SVM算法可以用于预测股票价格、信用风险等。通过对历史数据的学习,SVM可以捕捉到市场的潜在规律,为投资者提供有价值的参考信息。
支持向量机算法是一种强大而灵活的机器学习方法,通过在高维空间中寻找最优超平面实现数据的分类和回归。通过与其他算法进行集成,可以进一步提高其性能。在实际应用中,SVM算法在图像识别、文本分类、金融预测等多个领域都取得了显著的效果。随着机器学习技术的不断发展,相信SVM算法将在更多领域发挥重要作用。
参考文献
∑Ni=1[1−yi(w⋅xi+b)]++λ|w|2
上面目标函数的第 1 项是经验损失,函数 L(y(w⋅x+b))=[1−y(w⋅x+b)]+ 称为合页损失函数 (hinge loss function)。"+"表示取正值:
0−1 损失函数是二分类分问题的真正损失函数,0-1损失函数非凸、非连续、数学性质不太好,使得目标函数不易直接求解,于是通常用其他一些函数替代 0−1 损失函数,而替代损失函数是 0−1 损失函数的上界,合页损失函数是一种常见的替代损失函数。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
2022-04-28 存储系统模拟—R实现