前言
提醒:
文章内容为方便作者自己后日复习与查阅而进行的书写与发布,其中引用内容都会使用链接表明出处(如有侵权问题,请及时联系)。
其中内容多为一次书写,缺少检查与订正,如有问题或其他拓展及意见建议,欢迎评论区讨论交流。
分类与回归算法
机器学习中的分类与回归算法是两种主要的监督学习任务,它们分别用于解决不同类型的问题。以下是这两种算法的总结:
分类算法:
分类算法用于将数据分成不同的类别,适用于输出为离散标签的问题。常见的分类算法包括:
- 逻辑回归:使用逻辑函数来估计概率,用于二分类问题,也可以扩展到多分类问题。
- 支持向量机(SVM):通过找到最优的决策边界来最大化样本的分类准确率,适用于高维数据。
- 决策树:通过树结构来进行决策,每个节点代表一个特征的选择,叶子节点代表分类结果。
- 随机森林:由多个决策树组成的集成学习方法,通过投票来决定最终分类结果。
- 梯度提升决策树(GBDT):通过构建和结合多个弱学习器来形成强学习器,适用于分类和回归问题。
- 朴素贝叶斯:基于贝叶斯定理,假设特征之间相互独立,适用于文本分类等场景。
- K近邻(KNN):根据样本之间的距离进行分类,适用于小规模数据集。
- 神经网络:通过多层感知机学习数据的复杂模式,适用于图像、语音等复杂分类问题。
回归算法:
回归算法用于预测连续数值输出,适用于输出为连续变量的问题。常见的回归算法包括:
- 线性回归:通过拟合一条直线来预测目标变量的值,是最简单的回归方法。
- 岭回归:线性回归的扩展,通过引入L2正则化项来防止过拟合。
- Lasso回归:线性回归的另一种扩展,通过引入L1正则化项来进行特征选择。
- 弹性网回归:结合了岭回归和Lasso回归,同时引入L1和L2正则化项。
- 决策树回归:使用决策树结构来进行回归预测,适用于非线性关系。
- 随机森林回归:由多个决策树组成的集成学习方法,通过平均来决定最终回归结果。
- 梯度提升决策树回归(GBDT回归):通过构建和结合多个弱学习器来形成强学习器,适用于回归问题。
- 支持向量回归(SVR):支持向量机在回归问题上的应用,通过找到最优的决策边界来最大化样本的回归准确率。
- 神经网络回归:通过多层感知机学习数据的复杂模式,适用于复杂的回归问题。
分类与回归算法的比较:
- 输出类型:分类算法输出离散标签,回归算法输出连续数值。
- 评估指标:分类算法常用准确率、召回率、F1分数等指标,回归算法常用均方误差(MSE)、均方根误差(RMSE)等指标。
- 问题类型:分类算法适用于类别预测问题,如垃圾邮件检测;回归算法适用于数值预测问题,如房价预测。 在实际应用中,选择分类还是回归算法取决于问题的性质和需求。有时,可以将回归问题转化为分类问题,或者将分类问题转化为回归问题,具体取决于问题的特点和目标。
支持向量机(SVM)
数学原理(二分类)
一、线性可分的支持向量机(HardMarginSVM)
1.基本概念: 支持向量机是一种监督学习算法,主要用于分类问题,其目标是找到一个最优超平面,将不同类别的数据点分隔开。对于线性可分的情况,存在无数个超平面可以将两类数据分开,但SVM要找的是具有最大间隔的超平面。
2.超平面的表示: 对于一个二维平面,直线可以表示为: w 1 x 1 + w 2 x 2 + b = 0 w_1x_1+w_2x_2+b=0 w1x1+w2x2+b=0 在高维空间中,超平面可以表示为: w T x + b = 0 \mathbf{w}^T\mathbf{x}+b=0 wTx+b=0
其中 w = ( w 1 , w 2 , ⋯ , w n ) \mathbf{w}=(w_1,w_2,\cdots,w_n) w=(w1,w2,⋯,wn)是权重向量, x = ( x 1 , x 2 , ⋯ , x n ) \mathbf{x}=(x_1,x_2,\cdots,x_n) x=(x1,x2,⋯,xn)是特征向量, b b b是偏置项。3.间隔的定义: 对于线性可分的数据,我们可以定义函数间隔和几何间隔。
函数间隔:对于样本 ( x i , y i ) (\mathbf{x}_i,y_i) (xi,yi)( y i ∈ { − 1 , 1 } y_i\in\{-1,1\} yi∈{−1,1}表示类别),函数间隔为: γ ^ i = y i ( w T x i + b ) \hat{\gamma}_i=y_i(\mathbf{w}^T\mathbf{x}_i+b) γ^i=yi(wTxi+b)
其中 w T x i = ( w 1 w 2 ⋯ w n ) × ( x i 1 x i 2 ⋮ x i n ) = w 1 x i 1 + w 2 x i 2 + ⋯ + w n x i n \begin{align*} \mathbf{w}^T\mathbf{x}_i&=\begin{pmatrix} w_1&w_2&\cdots&w_n \end{pmatrix}\times\begin{pmatrix} x_{i1}\\ x_{i2}\\ \vdots\\ x_{in} \end{pmatrix}\\ &=w_1x_{i1}+w_2x_{i2}+\cdots+w_nx_{in} \end{align*} wTxi=(w1w2⋯wn)× xi1xi2⋮xin =w1xi1+w2xi2+⋯+wnxin几何间隔:几何间隔是函数间隔除以 ∣ ∣ w ∣ ∣ ||\mathbf{w}|| ∣∣w∣∣,即 γ i = y i ( w T x i + b ) ∣ ∣ w ∣ ∣ \gamma_i=\frac{y_i(\mathbf{w}^T\mathbf{x}_i+b)}{||\mathbf{w}||} γi=∣∣w∣∣yi(wTxi+b)
其中 ∣ ∣ w ∣ ∣ = ∑ i = 1 n w i 2 = w 1 2 + w 2 2 + ⋯ + w n 2 ||\mathbf{w}||=\sqrt{\sum_{i=1}^{n}w_i^2}=\sqrt{w_1^2+w_2^2+\cdots+w_n^2} ∣∣w∣∣=i=1∑nwi2=w12+w22+⋯+wn24.优化目标: SVM的目标是最大化间隔,即找到 w \mathbf{w} w和 b b b使得 min i γ i \min_{i}\gamma_i miniγi最大。为了简化计算,我们可以等价地求解以下优化问题:
max w , b 1 ∣ ∣ w ∣ ∣ min i y i ( w T x i + b ) \max_{\mathbf{w},b}\frac{1}{||\mathbf{w}||}\min_{i}y_i(\mathbf{w}^T\mathbf{x}_i+b) w,bmax∣∣w∣∣1iminyi(wTxi+b)
等价于: min w , b 1 2 ∣ ∣ w ∣ ∣ 2 \min_{\mathbf{w},b}\frac{1}{2}||\mathbf{w}||^2 w,bmin21∣∣w∣∣2
同时满足 y i ( w T x i + b ) ≥ 1 y_i(\mathbf{w}^T\mathbf{x}_i+b)\geq1 yi(wTxi+b)≥1, i = 1 , 2 , ⋯ , m i=1,2,\cdots,m i=1,2,⋯,m。
这里 m m m是样本的数量。二、线性不可分的支持向量机(SoftMarginSVM)
1.引入松弛变量: 对于线性不可分的数据,允许一些样本点在间隔内或误分类,引入松弛变量 ξ i ≥ 0 \xi_i\geq0 ξi≥0,对于每个样本 ( x i , y i ) (\mathbf{x}_i,y_i) (xi,yi),约束条件变为 y i ( w T x i + b ) ≥ 1 − ξ i y_i(\mathbf{w}^T\mathbf{x}_i+b)\geq1-\xi_i yi(wTxi+b)≥1−ξi。
2.优化目标: min w , b , ξ 1 2 ∣ ∣ w ∣ ∣ 2 + C ∑ i = 1 m ξ i \min_{\mathbf{w},b,\xi}\frac{1}{2}||\mathbf{w}||^2+C\sum_{i=1}^{m}\xi_i w,b,ξmin21∣∣w∣∣2+Ci=1∑mξi
同时满足 y i ( w T x i + b ) ≥ 1 − ξ i y_i(\mathbf{w}^T\mathbf{x}_i+b)\geq1-\xi_i yi(wTxi+b)≥1−ξi, ξ i ≥ 0 \xi_i\geq0 ξi≥0, i = 1 , 2 , ⋯ , m i=1,2,\cdots,m i=1,2,⋯,m。
这里 C C C是惩罚参数,控制着对错误分类的惩罚程度。较大的 C C C意味着对错误分类的惩罚更严重,更不允许错误分类;较小的 C C C则允许更多的错误分类。三、非线性支持向量机(KernelSVM)
1.核技巧(KernelTrick): 对于非线性可分的数据,可以将数据映射到高维空间,使其线性可分。通过核函数 K ( x i , x j ) = ϕ ( x i ) T ϕ ( x j ) K(\mathbf{x}_i,\mathbf{x}_j)=\phi(\mathbf{x}_i)^T\phi(\mathbf{x}_j) K(xi,xj)=ϕ(xi)Tϕ(xj)
可以在原始空间计算高维空间的内积,避免显式计算高维映射 ϕ ( x ) \phi(\mathbf{x}) ϕ(x)。2.常见的核函数:
- 线性核: K ( x i , x j ) = x i T x j K(\mathbf{x}_i,\mathbf{x}_j)=\mathbf{x}_i^T\mathbf{x}_j K(xi,xj)=xiTxj
- 多项式核: K ( x i , x j ) = ( x i T x j + c ) d K(\mathbf{x}_i,\mathbf{x}_j)=(\mathbf{x}_i^T\mathbf{x}_j+c)^d K(xi,xj)=(xiTxj+c)d,其中 c c c是常数, d d d是多项式的次数。
- 径向基函数(RBF)核(高斯核): K ( x i , x j ) = exp ( − γ ∣ ∣ x i − x j ∣ ∣ 2 ) K(\mathbf{x}_i,\mathbf{x}_j)=\exp(-\gamma||\mathbf{x}_i-\mathbf{x}_j||^2) K(xi,xj)=exp(−γ∣∣xi−xj∣∣2),其中 γ \gamma γ是一个参数,控制着核函数的宽度。
四、求解方法
1.对偶问题: 对于上述优化问题(无论是硬间隔还是软间隔),通常通过拉格朗日对偶性将原问题转化为对偶问题求解。 对于硬间隔SVM,拉格朗日函数为:
L ( w , b , α ) = 1 2 ∣ ∣ w ∣ ∣ 2 − ∑ i = 1 m α i [ y i ( w T x i + b ) − 1 ] L(\mathbf{w},b,\alpha)=\frac{1}{2}||\mathbf{w}||^2-\sum_{i=1}^{m}\alpha_i[y_i(\mathbf{w}^T\mathbf{x}_i+b)-1] L(w,b,α)=21∣∣w∣∣2−i=1∑mαi[yi(wTxi+b)−1]
其中 α i ≥ 0 \alpha_i\geq0 αi≥0是拉格朗日乘子。 通过求解对偶问题:
max α min w , b L ( w , b , α ) \max_{\alpha}\min_{\mathbf{w},b}L(\mathbf{w},b,\alpha) αmaxw,bminL(w,b,α)得到:
max α ∑ i = 1 m α i − 1 2 ∑ i = 1 m ∑ j = 1 m α i α j y i y j x i T x j \max_{\alpha}\sum_{i=1}^{m}\alpha_i-\frac{1}{2}\sum_{i=1}^{m}\sum_{j=1}^{m}\alpha_i\alpha_jy_iy_j\mathbf{x}_i^T\mathbf{x}_j αmaxi=1∑mαi−21i=1∑mj=1∑mαiαjyiyjxiTxj
同时满足: ∑ i = 1 m α i y i = 0 \sum_{i=1}^{m}\alpha_iy_i=0 ∑i=1mαiyi=0, α i ≥ 0 \alpha_i\geq0 αi≥0。五、支持向量的概念 在求解上述优化问题后,满足 α i > 0 \alpha_i>0 αi>0的样本 ( x i , y i ) (\mathbf{x}_i,y_i) (xi,yi)被称为支持向量。这些样本是离超平面最近的样本,它们决定了超平面的位置和方向,因为超平面可以表示为 w = ∑ i α i y i x i \mathbf{w}=\sum_{i}\alpha_iy_i\mathbf{x}_i w=∑iαiyixi, b b b可以通过支持向量计算得到。
六、分类决策函数 对于一个新的样本 x \mathbf{x} x,分类决策函数为: f ( x ) = sign ( w T x + b ) = sign ( ∑ i α i y i K ( x i , x ) + b ) f(\mathbf{x})=\text{sign}(\mathbf{w}^T\mathbf{x}+b)=\text{sign}(\sum_{i}\alpha_iy_iK(\mathbf{x}_i,\mathbf{x})+b) f(x)=sign(wTx+b)=sign(i∑αiyiK(xi,x)+b)
七、总结: 支持向量机通过寻找最优超平面将数据分开,在不同情况下(线性可分、线性不可分)使用不同的优化目标和约束。对于非线性问题,利用核技巧将数据映射到高维空间,使数据更容易分离。支持向量机在很多领域,如文本分类、图像识别、生物信息学等有着广泛的应用,它具有较好的泛化能力和理论基础,其性能取决于核函数的选择和参数的调整。
数学原理(多元分类)
一、一对多(One-vs-Rest)方法
1. 基本思想:
对于一个 K K K 类分类问题,将其拆分成 K K K 个二分类问题。 对于每一个类别 k k k ( k = 1 , 2 , ⋯ , K k = 1,2,\cdots,K k=1,2,⋯,K),构建一个 SVM 分类器,将类别 k k k 视为正类,而将其余 K − 1 K - 1 K−1 个类别视为负类。2. 分类器训练:
对于第 k k k 个分类器,我们训练一个 SVM 来区分类别 k k k 和其他类别。 假设我们有训练数据集 D = { ( x i , y i ) } D=\{(\mathbf{x}_i,y_i)\} D={(xi,yi)} 其中 y i ∈ { 1 , 2 , ⋯ , K } y_i\in\{1,2,\cdots,K\} yi∈{1,2,⋯,K} 。 对于第 k k k 个
SVM 分类器,我们重新标记数据集为: y i k = { 1 , y i = k − 1 , y i ≠ k y_i^k=\begin{cases} 1, & y_i = k\\ -1, & y_i\neq k \end{cases} yik={1,−1,yi=kyi=k然后,我们训练一个 SVM 分类器,其目标是找到超平面 w k T x + b k = 0 \mathbf{w}_k^T\mathbf{x}+b_k = 0 wkTx+bk=0
,通过最小化以下优化问题(以软间隔为例):
min w k , b k , ξ 1 2 ∣ ∣ w k ∣ ∣ 2 + C ∑ i = 1 m ξ i \min_{\mathbf{w}_k,b_k,\xi}\frac{1}{2}||\mathbf{w}_k||^2 + C\sum_{i = 1}^{m}\xi_i wk,bk,ξmin21∣∣wk∣∣2+Ci=1∑mξi 同时满足 y i k ( w k T x i + b k ) ≥ 1 − ξ i y_i^k(\mathbf{w}_k^T\mathbf{x}_i + b_k)\geq1-\xi_i yik(wkTxi+bk)≥1−ξi , ξ i ≥ 0 \xi_i\geq0 ξi≥0 , i = 1 , 2 , ⋯ , m i = 1,2,\cdots,m i=1,2,⋯,m3. 决策规则:
对于一个新的样本 x \mathbf{x} x ,我们使用这 K K K 个分类器进行预测,计算样本 x \mathbf{x} x 到每个超平面的距离(或决策函数的值):
f k ( x ) = w k T x + b k f_k(\mathbf{x})=\mathbf{w}_k^T\mathbf{x}+b_k fk(x)=wkTx+bk 其中 k = 1 , 2 , ⋯ , K k = 1,2,\cdots,K k=1,2,⋯,K最终将样本 x \mathbf{x} x 分类为具有最大 f k ( x ) f_k(\mathbf{x}) fk(x) 的类别,即: y = arg max k f k ( x ) y=\arg\max_{k} f_k(\mathbf{x}) y=argmaxkfk(x)
二、一对一(One-vs-One)方法
1. 基本思想:
对于一个 K K K 类分类问题,我们构建 C K 2 = K ( K − 1 ) 2 C_K^2=\frac{K(K - 1)}{2} CK2=2K(K−1) 个 SVM 分类器。 每个分类器只区分两个不同的类别。 对于每一对类别 ( i , j ) (i,j) (i,j) ( 1 ≤ i < j ≤ K 1\leq i < j\leq K 1≤i<j≤K),我们训练一个 SVM 分类器。2. 分类器训练:
对于类别 ( i , j ) (i,j) (i,j) ,我们提取所有属于类别 i i i 和类别 j j j 的样本,重新标记它们为 y i j y_{ij} yij ,其中 y i j = 1 y_{ij}=1 yij=1 表示属于类别 i i i , y i j = − 1 y_{ij}=-1 yij=−1 表示属于类别 j j j 。 然后训练一个
SVM 分类器,其超平面为 w i j T x + b i j = 0 \mathbf{w}_{ij}^T\mathbf{x}+b_{ij}=0 wijTx+bij=0 ,通过最小化:
min w i j , b i j , ξ 1 2 ∣ ∣ w i j ∣ ∣ 2 + C ∑ ( x , y i j ) ∈ D i j ξ \min_{\mathbf{w}_{ij},b_{ij},\xi}\frac{1}{2}||\mathbf{w}_{ij}||^2 + C\sum_{(\mathbf{x},y_{ij})\in D_{ij}}\xi wij,bij,ξmin21∣∣wij∣∣2+C(x,yij)∈Dij∑ξ 同时满足
y i j ( w i j T x + b i j ) ≥ 1 − ξ y_{ij}(\mathbf{w}_{ij}^T\mathbf{x}+b_{ij})\geq1-\xi yij(wijTx+bij)≥1−ξ , ξ ≥ 0 \xi\geq0 ξ≥03. 决策规则:
对于一个新的样本 x \mathbf{x} x ,我们使用这 C K 2 C_K^2 CK2 个分类器进行预测。 假设 n i j n_{ij} nij 是分类器 ( i , j ) (i,j) (i,j) 将样本 x \mathbf{x} x 分类为类别 i i i 的票数。我们将样本
x \mathbf{x} x 分类为得票最多的类别,即: y = arg max k ∑ i : i ≠ k n i k y=\arg\max_{k}\sum_{i: i\neq k}n_{ik} y=argkmaxi:i=k∑nik三、多分类的核函数
在多元分类问题中,无论是一对多还是一对一方法,都可以使用核函数将数据映射到高维空间,以处理非线性可分的数据。 对于核函数 K ( x , x ′ ) K(\mathbf{x},\mathbf{x}') K(x,x′) ,在训练和预测过程中,将内积
x T x ′ \mathbf{x}^T\mathbf{x}' xTx′ 替换为 K ( x , x ′ ) K(\mathbf{x},\mathbf{x}') K(x,x′) 。
- 线性核: K ( x , x ′ ) = x T x ′ K(\mathbf{x},\mathbf{x}')=\mathbf{x}^T\mathbf{x}' K(x,x′)=xTx′
- 多项式核: K ( x , x ′ ) = ( x T x ′ + c ) d K(\mathbf{x},\mathbf{x}')=(\mathbf{x}^T\mathbf{x}'+c)^d K(x,x′)=(xTx′+c)d ,其中 c c c 是常数, d d d 是多项式的次数。
- 径向基函数(RBF)核(高斯核): K ( x , x ′ ) = exp ( − γ ∣ ∣ x − x ′ ∣ ∣ 2 ) K(\mathbf{x},\mathbf{x}')=\exp(-\gamma||\mathbf{x}-\mathbf{x}'||^2) K(x,x′)=exp(−γ∣∣x−x′∣∣2)
,其中 γ \gamma γ 是一个参数,控制着核函数的宽度。四、误差校正输出码(Error-Correcting Output Codes)方法
基本思想: 将多分类问题编码为多个二分类问题。 对于 K K K 类问题,我们可以使用一个编码矩阵 M M M ,其中每一行对应一个类别,每一列对应一个二分类问题。矩阵元素 M i j ∈ { − 1 , 1 } M_{ij}\in\{-1,1\} Mij∈{−1,1} 。
训练过程: 对于每一列 j j j ,我们训练一个 SVM 分类器,使用重新标记的数据根据编码矩阵的元素。
决策规则: 对于一个新的样本 x \mathbf{x} x ,我们使用所有的 SVM 分类器进行预测,得到一个二进制码。然后将该二进制码与编码矩阵中的行进行比较,将样本分类为最接近的类别。
五、总结:
- 一对多方法:
简单直观,但可能存在类别不平衡问题,因为每个分类器的训练集大小不同,且对于每个样本,只考虑了该类别和其他类别,而不是类别之间的关系。- 一对一方法:
需要训练更多的分类器,但在实际应用中,通常能得到较好的性能,尤其是在类别之间的区分度较小时。- 误差校正输出码方法:
提供了更多的灵活性,可以利用纠错码的思想,但编码矩阵的设计和选择会影响性能。通过将多元分类问题转化为多个二分类问题,并使用 SVM进行二分类,结合不同的决策规则和核函数,支持向量机可以有效地解决多元分类问题。不同的方法有不同的优缺点,在实际应用中需要根据具体情况进行选择和调整,同时要注意核函数的选择和参数的调整(如 C C C 、 γ \gamma γ 等)以获得最佳性能。
手动实现
加载鸢尾花数据集,并仅使用前两个特征,方便可视化。
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
class SVM:
def __init__(self, learning_rate=0.001, lambda_param=0.01, n_iters=1000):
# 初始化 SVM 类
# learning_rate:学习率,用于控制梯度下降的步长
self.lr = learning_rate
# lambda_param:正则化参数,用于防止过拟合
self.lambda_param = lambda_param
# n_iters:迭代次数,用于控制训练的轮数
self.n_iters = n_iters
# 权重向量,初始化为 None,将在训练过程中更新
self.w = None
# 偏置项,初始化为 None,将在训练过程中更新
self.b = None
def fit(self, X, y):
# 训练 SVM 模型的方法
# X:输入的特征矩阵,形状为 (n_samples, n_features)
# y:标签向量,形状为 (n_samples,)
n_samples, n_features = X.shape
# 将标签向量 y 中的 0 转换为 -1,1 保持不变,以便后续计算
y_ = np.where(y <= 0, -1, 1)
# 初始化权重向量 w 为零向量,长度为特征数量
self.w = np.zeros(n_features)
# 初始化偏置项 b 为 0
self.b = 0
# 进行 n_iters 次迭代
for _ in range(self.n_iters):
# 遍历每个样本
for idx, x_i in enumerate(X):
# 计算样本 x_i 与权重向量 w 的内积,并减去偏置项 b,再乘以相应的标签 y_[idx]
condition = y_[idx] * (np.dot(x_i, self.w) - self.b) >= 1
# 如果满足条件(样本被正确分类且在间隔外)
if condition:
# 根据梯度下降更新权重向量 w,考虑正则化项
self.w -= self.lr * (2 * self.lambda_param * self.w)
else:
# 如果不满足条件(样本被错误分类或在间隔内)
# 根据梯度下降更新权重向量 w 和偏置项 b
self.w -= self.lr * (2 * self.lambda_param * self.w - np.dot(x_i, y_[idx]))
self.b -= self.lr * y_[idx]
def predict(self, X):
# 预测方法
# X:输入的特征矩阵,形状为 (n_samples, n_features)
# 计算样本与权重向量的内积并减去偏置项
approx = np.dot(X, self.w) - self.b
# 使用符号函数将结果转换为 -1 或 1,表示预测的类别
return np.sign(approx)
def main():
# 主函数,用于调用 SVM 类进行分类任务
# 加载鸢尾花数据集
iris = datasets.load_iris()
# 仅使用前两个特征,方便在二维平面上进行可视化
X = iris.data[:, :2]
# 获取样本的标签
y = iris.target
# 只考虑类别 0 和类别 1 的样本,将类别 0 转换为 -1,类别 1 保持为 1
X = X[(y == 0) | (y == 1)]
y = y[(y == 0) | (y == 1)]
y = np.where(y == 0, -1, 1)
# 创建 SVM 类的实例
svm = SVM()
# 调用 fit 方法对筛选后的样本进行训练
svm.fit(X, y)
# 对训练集进行预测
y_pred = svm.predict(X)
# 计算预测的正确率
accuracy = np.mean(y_pred == y)
# 打印正确率
print(f"Accuracy: {accuracy * 100:.2f}%")
# 可视化决策边界的函数
def plot_decision_boundary(svm, X, y):
# 获取特征矩阵 X 中第一个特征的最小值和最大值,并向外扩展 1 个单位
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
# 获取特征矩阵 X 中第二个特征的最小值和最大值,并向外扩展 1 个单位
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
# 使用 meshgrid 生成网格点,用于绘制决策边界
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.02),
np.arange(y_min, y_max, 0.02))
# 对网格点进行预测
Z = svm.predict(np.c_[xx.ravel(), yy.ravel()])
# 将预测结果重塑为与网格点相同的形状
Z = Z.reshape(xx.shape)
# 绘制决策边界,使用等高线图表示不同的类别区域
plt.contourf(xx, yy, Z, alpha=0.8)
# 绘制样本点,根据真实标签设置颜色,边缘为黑色
plt.scatter(X[:, 0], X[:, 1], c=y, edgecolors='k')
# 设置 x 轴标签
plt.xlabel('Sepal length')
# 设置 y 轴标签
plt.ylabel('Sepal width')
# 设置图形标题
plt.title('SVM Decision Boundary')
# 显示图形
plt.show()
# 调用 plot_decision_boundary 函数进行可视化
plot_decision_boundary(svm, X, y)
if __name__ == "__main__":
main()
运行结果:
函数库实现
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.svm import SVC
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
def main():
# 主函数,用于执行整个分类任务
# 加载鸢尾花数据集
iris = datasets.load_iris()
# 仅使用鸢尾花数据集的前两个特征,以便于在二维平面上进行可视化
X = iris.data[:, :2]
# 获取鸢尾花数据集的标签
y = iris.target
# 只考虑类别 0 和类别 1 的样本,将类别 0 转换为 -1,类别 1 保持为 1
X = X[(y == 0) | (y == 1)]
y = y[(y == 0) | (y == 1)]
y = np.where(y == 0, -1, 1)
# 数据标准化,将数据转换为均值为 0,方差为 1 的分布,有助于提高模型性能
scaler = StandardScaler()
# 对特征矩阵 X 进行标准化处理
X = scaler.fit_transform(X)
# 将数据集划分为训练集和测试集
# 测试集占总数据集的 30%,随机种子设置为 42,保证结果的可重复性
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 创建 SVM 分类器对象,使用线性核函数,正则化参数 C 设置为 1.0
svm = SVC(kernel='linear', C=1.0)
# 使用训练集训练 SVM 模型
svm.fit(X_train, y_train)
# 使用训练好的 SVM 模型对训练集进行预测
y_pred_train = svm.predict(X_train)
# 使用训练好的 SVM 模型对测试集进行预测
y_pred_test = svm.predict(X_test)
# 计算训练集的预测正确率
accuracy_train = np.mean(y_pred_train == y_train)
# 计算测试集的预测正确率
accuracy_test = np.mean(y_pred_test == y_test)
# 打印训练集的预测正确率
print(f"Training Accuracy: {accuracy_train * 100:.2f}%")
# 打印测试集的预测正确率
print(f"Test Accuracy: {accuracy_test * 100:.2f}%")
# 定义绘制决策边界的函数
def plot_decision_boundary(svm, X, y):
# 获取特征矩阵 X 中第一个特征的最小值并向外扩展 1 个单位
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
# 获取特征矩阵 X 中第二个特征的最小值并向外扩展 1 个单位
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
# 使用 meshgrid 生成网格点,用于绘制决策边界
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.02),
np.arange(y_min, y_max, 0.02))
# 对网格点进行预测
Z = svm.predict(np.c_[xx.ravel(), yy.ravel()])
# 将预测结果重塑为与网格点相同的形状
Z = Z.reshape(xx.shape)
# 绘制决策边界,使用等高线图表示不同的类别区域
plt.contourf(xx, yy, Z, alpha=0.8)
# 绘制样本点,根据真实标签设置颜色,边缘为黑色
plt.scatter(X[:, 0], X[:, 1], c=y, edgecolors='k')
# 设置 x 轴标签,并注明数据已经标准化
plt.xlabel('Sepal length (scaled)')
# 设置 y 轴标签,并注明数据已经标准化
plt.ylabel('Sepal width (scaled)')
# 设置图形标题
plt.title('SVM Decision Boundary')
# 显示图形
plt.show()
# 调用 plot_decision_boundary 函数绘制决策边界
plot_decision_boundary(svm, X, y)
if __name__ == "__main__":
main()
运行结果: