1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > 【支持向量机SVM系列教程1】线性SVM

【支持向量机SVM系列教程1】线性SVM

时间:2024-01-15 05:17:45

相关推荐

【支持向量机SVM系列教程1】线性SVM

文章目录

1 线性SVM1.1 优化的目标1.2 直观展示1.3 公式表达1.3.1 约束条件1.3.2 硬间隔形式1.3.3 软间隔形式 1.4 sklearn中的线性SVM1.4.1 原型1.4.2 常用参数1.4.3 常用属性1.4.4 常用方法 1.5 实例1:利用sklearn中的线性SVM实现分类可视化1.5.1 效果展示示例1.5.2 可视化函数的设计1.5.2.1 设计思路1.5.2.2 代码实现 1.5.4 观察标准化的作用1.5.5 数据集的加载1.5.6 定义不同的线性SVM分类器1.5.7 实现分类效果可视化的准备工作1.5.7.1 对各分类器的各个参数做标准化处理1.5.7.2 求解偏置 b \boldsymbol b b1.5.7.3 decision_function函数1.5.7.3 代码实现 1.5.8 分类效果可视化图片的绘制

1 线性SVM

1.1 优化的目标

线性SVM的优化目标,用一句话来概括就是:最大化间隔,同时尽可能减少分类错误。

下面首先从图片展示的角度来对这句话进行解释。

1.2 直观展示

假设有红色和蓝色两类样本(如下图所示),其中蓝色表示正样本(标签为1),红色表示负样本(标签为-1)。SVM要做的,就是找到一个合适的边界,使得该边界能够较好地将两类样本分开。寻找边界的直观过程如下:

如果想要画出一条边界将红蓝两类样本分开,实际上有非常多种画法:

这就出现了一个问题:到底要选哪一条?哪条是最优的分法?对此,我们可以尝试将边界的宽度扩大,使得边界变成很粗的直线,再来分开这两类样本。效果如下:

同样有很多种分隔的方法,无法确定具体要使用哪一种。若找准角度,使用一条粗的线分隔,如下图所示:

这样就找到了大间隔和决策边界,如下:

上图中一些字母和线条的含义如下:

margin:最优的分类间隔,所产生的分类结果最鲁棒,对未见样本的泛化能力最强中间线:决策边界

上面找的大间隔和决策边界是肉眼可以直观分出来的,那计算机要如何自己找到呢?

1.3 公式表达

1.3.1 约束条件

假设有如下数据集:

D = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . , ( x n , y n ) } D= \{ (x_1,y_1),(x_2,y_2),...,(x_n,y_n)\} D={(x1​,y1​),(x2​,y2​),...,(xn​,yn​)}

其中, x i ∈ R d x_i\in\mathbb{R}^d xi​∈Rd , y i ∈ { − 1 , + 1 } y_i\in\{-1,+1\} yi​∈{−1,+1} 。

决策边界为:

w T x + b = 0 \boldsymbol w^T\boldsymbol x+b=0 wTx+b=0

w \boldsymbol w w 为法向量,决定了决策边界的方向 b \boldsymbol b b 为偏置项,决定了决策边界与原点之间的距离

则样本被正确分类的条件为:

y i ( w T x i + b ) ⩾ 1 y_i(\boldsymbol w^T\boldsymbol x_i+b)\geqslant 1 yi​(wTxi​+b)⩾1

即:

{ w T x i + b ⩾ 1 ( y i = 1 ) w T x i + b ⩽ − 1 ( y i = − 1 ) \left\{\begin{aligned}\boldsymbol w^T\boldsymbol x_i+b \geqslant 1\quad (y_i=1 ) \\ \boldsymbol w^T\boldsymbol x_i+b \leqslant -1 \quad(y_i=-1 ) \end{aligned} \right. {wTxi​+b⩾1(yi​=1)wTxi​+b⩽−1(yi​=−1)​

满足该约束的 w \boldsymbol w w 和 b b b 便可以将训练集的样本正确分开。

接下来看看如何找到满足该条件的 w w w 和 b b b,使得间隔最大化。

1.3.2 硬间隔形式

分类间隔 m a r g i n margin margin 的计算公式为:

m a r g i n = 4 w T w w T w × w T w = 2 w T w margin = \sqrt{\frac{4\boldsymbol w^T\boldsymbol w}{\boldsymbol w^T\boldsymbol w×\boldsymbol w^T\boldsymbol w}}=\frac{2}{\sqrt{\boldsymbol w^T \boldsymbol w}} margin=wTw×wTw4wTw​ ​=wTw ​2​

则 SVM 线性分类器所要求解的问题转化为:

max ⁡ w , b 2 w T w s . t . y i ( w T x i + b ) ⩾ 1 \max_{w,b}\frac{2}{\sqrt{\boldsymbol w^T\boldsymbol w}} \\ s.t. \quad y_i(\boldsymbol w^T \boldsymbol {x_i}+b) \geqslant 1 w,bmax​wTw ​2​s.t.yi​(wTxi​+b)⩾1

这种形式称为SVM的基本型,它要求所有的样本均要被正确分类。这称为SVM问题的硬间隔形式

1.3.3 软间隔形式

硬间隔的约束条件如下:

y i ( w T x i + b ) − 1 ⩾ 0 y_i(\boldsymbol w^T \boldsymbol {x_i}+b)-1 \geqslant 0 yi​(wTxi​+b)−1⩾0

它要求所有的样本均被正确分类,这在某些有噪声的情况下是不现实的。如下图所示:

为了处理带噪声的情况,可以采用软间隔,该形式允许一部分样本样本不满足上述约束条件,但同时也要尽可能最大化间隔,并使得不满足约束条件的样本尽可能少。在这种情况下,目标函数可写为:

min ⁡ w , b 1 2 w T w + C ∑ i = 1 m l ( y i ( w T x i + b ) − 1 ) \min_{\boldsymbol w,b}\frac{1}{2}\boldsymbol w^T\boldsymbol w+C\sum_{i=1}^m l(y_i(\boldsymbol w^T \boldsymbol {x_i}+b)-1 ) w,bmin​21​wTw+Ci=1∑m​l(yi​(wTxi​+b)−1)

其中 l l l 表示损失函数。损失函数 l l l 一般有如下两种。为了方便表达,下面令 z = y i ( w T x i + b ) z = y_i(\boldsymbol w^T \boldsymbol {x_i}+b) z=yi​(wTxi​+b):

0/1损失函数:

l 0 / 1 = { 1 , z < 0 0 , o t h e r l_{0/1}= \left\{\begin{aligned} 1, \quad z < 0 \\ 0,\quad other \end{aligned} \right. l0/1​={1,z<00,other​

hinge损失函数:

l h i n g e ( z ) = m a x ( 0 , 1 − z ) ) l_{hinge}(z)=max(0,1- z)) lhinge​(z)=max(0,1−z))

上述两种损失函数的对比图如下:

可以看到, l 0 / 1 l_{0/1} l0/1​的 z < 0 z<0 z<0和 z ≥ 0 z \ge 0 z≥0 时均为常数,数学性质不好,用来做损失函数可能会导致梯度消失的情况产生;而 l h i n g e ( z ) l_{hinge}(z) lhinge​(z) 在 z < 1 z<1 z<1时为连续直线,可导,所以数学性质好于 l 0 / 1 l_{0/1} l0/1​。

l h i n g e ( z ) l_{hinge}(z) lhinge​(z) 函数也是线性SVM最常用的损失函数。sklearn将其设置为SVC的默认损失函数。

在上面分析结果的基础上,令:

ξ i = m a x ( 0 , 1 − z ) ⩾ 0 \xi_i = max(0,1- z) \geqslant 0 ξi​=max(0,1−z)⩾0

则软间隔的目标函数改写为:

min ⁡ w , b , ξ i 1 2 w T w + C ∑ i = 1 m ξ i s . t . y i ( w T x i + b ) ⩾ 1 − ξ i \min_{\boldsymbol w,b,\xi_i}\frac{1}{2}\boldsymbol w^T\boldsymbol w+C\sum_{i=1}^m \xi_i\\ s.t. \quad y_i(\boldsymbol w^T \boldsymbol {x_i}+b) \geqslant 1-\xi_i w,b,ξi​min​21​wTw+Ci=1∑m​ξi​s.t.yi​(wTxi​+b)⩾1−ξi​

其中, ξ \xi ξ叫做松弛变量,它能够给分错的样本加上惩罚。当 $\xi $ 等于0时,约束条件与基本型(硬间隔)相同,即要求每个样本均被正确分类。

在松弛变量 ξ \xi ξ前面带有一个参数 C C C ,它是线性SVM中一个非常重要的超参数,起到了平衡松弛变量的作用。该参数发挥的具体作用如下:

当 C C C 为有限值时,允许一些样本不满足约束,但 C C C 值越大, ξ \xi ξ应越小,表示惩罚强度越大、允许分错的样本越少;当 C C C→+∞时, ξ \xi ξ必须为0,目标函数才不会 → \to →+∞,这样就迫使所有样本均满足上面的约束,此时目标函数等价于基本型(硬间隔)的目标函数形式。

因为 C C C 对分类效果的影响非常大,所以它也是线性SVM中一个主要的调参对象。

sklearn中的LinearSVC类对这些原理均进行了实现,在理解了上述内容的基础上,就可以为sklearn调参过程提供一定的导向。

1.4 sklearn中的线性SVM

sklearn中的LinearSVC类对线性SVM进行了实现。下面就让我们来看看这个类的使用方法,以及我们如何将该类中的参数、方法、属性等与上面所介绍到的点进行一一对应。

1.4.1 原型

sklearn.svm.LinearSVC(penalty=’l2’, loss=’squared_hinge’, dual=True, tol=0.0001, C=1.0, multi_class=’ovr’, fit_intercept=True, intercept_scaling=1, class_weight=None, verbose=0, random_state=None, max_iter=1000)

1.4.2 常用参数

loss:字符串类型,表示损失函数

hinge: 使用 hinge loss 损失函数(标准SVM的损失函数)

squared_hinge:hinge loss 损失函数的平方

tol:浮点数类型,默认为 1 0 − 4 10^{-4} 10−4,表示对损失的容忍度,损失降低到 tol 时,停止训练

C:浮点数类型,表示惩罚系数,起到平衡松弛变量的作用。注意:C 必须为正数!

multi_class:字符串类型,指定多类分类问题的策略

ovr:默认参数,表示采用 one-vs-rest(一对多余)的分类策略crammer_singer:多类联合分类

max_iter:整型,默认为1000,表示训练的最大迭代次数

1.4.3 常用属性

coef_: 数组,给出各个特征的权重(对应 w \boldsymbol w w)intercept_: 数组,给出截距(对应 b \boldsymbol b b)classes_:样本中所有类别的标签(对应 y i \boldsymbol y_i yi​)support_vectors_:获取支持向量(即落在两条边界线之上或之间的样本点)

这4个属性常用于线性SVM分类效果的可视化。

1.4.4 常用方法

fit(X, y):训练模型predict(X):用模型进行预测,返回预测值score(X, y[, sample_weight]):返回预测的准确率decision_function(X):预测每个样本的置信度分数(在线性SVM中为各个样本到决策边界的有符号距离)

1.5 实例1:利用sklearn中的线性SVM实现分类可视化

在对sklearn中的线性SVM的API有个大概了解之后,接下来将围绕着该API的使用做一步步展开,对一个二分类的简单数据集做可视化。该实例的目的为:

涵盖该API中的多个点,尽量让对整个LinearSVC的使用有一个整体的认识;将对C调参的结果与可视化结合起来,使得读者可以从视觉上观察出调参的规律。

1.5.1 效果展示示例

我们要画出类似如下图的效果,实现二元分类效果的可视化,绘制出线性SVM分类中的决策边界、大间隔以及支持向量。效果图如下:

1.5.2 可视化函数的设计

1.5.2.1 设计思路

想要将线性SVM的分类效果可视化,需要定义可视化分类效果的函数。该函数的设计思路如下:

形参

svm_classifier:表示需要可视化分类效果的分类器xmin, xmax:横轴的范围

设计流程

利用分类器svm_classifier中的 coef_ 属性获取权值 w \boldsymbol w w。

其中w[0]表示第一个特征对应的权值,w[1]表示第二个特征对应的权值;

定义横轴,用来表示第一个特征 x 0 x_0 x0​;

定义纵轴,用第一个特征 x 0 x_0 x0​来表示第二个特征 x 1 x_1 x1​。 由公式:

w 0 x 0 + w 1 x 1 + b = 0 ( 1.5.2.1 ) w_0 x_0 + w_1 x_1+b=0\quad\quad (1.5.2.1) w0​x0​+w1​x1​+b=0(1.5.2.1)

得:

x 1 = − w o w 1 x 0 − b w 1 ( 1.5.2.2 ) x_1=-\frac{w_o}{w_1}x_0-\frac{b}{w_1} \quad\quad (1.5.2.2) x1​=−w1​wo​​x0​−w1​b​(1.5.2.2)

该式子实际上即为决策边界(上图中间黑实线)的计算公式;

定义求大间隔的公式:

m a r g i n = 2 w 0 2 + w 1 2 ( 1.5.2.3 ) margin=\frac{2}{\sqrt{w_0^2+w_1^2}}\quad\quad (1.5.2.3) margin=w02​+w12​ ​2​(1.5.2.3)

计算上下边界(上图两虚线),计算公式为:

u p _ l i n e = x 1 + m a r g i n 2 ( 1.5.2.4 ) d o w n _ l i n e = x 1 − m a r g i n 2 ( 1.5.2.5 ) up\_line=x_1+\frac{margin}{2} \quad\quad (1.5.2.4)\\ down\_line=x_1-\frac{margin}{2}\quad\quad (1.5.2.5) up_line=x1​+2margin​(1.5.2.4)down_line=x1​−2margin​(1.5.2.5)

利用 support_vectors_ 属性获取支持向量;

将上述求解结果用代码进行实现。

1.5.2.2 代码实现

按照上述思路,该函数的完整代码如下:

def plot_linear_svm_decision_margin_and_boundary(svm_classifier, xmin, xmax):# 获得分类器最终学到的的权值w = svm_classifier.coef_[0]# 获得分类器最终学到的偏置b = svm_classifier.intercept_[0]# 定义横轴为特征x0,范围为xmin到xmax,200等分x0 = np.linspace(xmin, xmax, 200)# 定义纵轴为特征x1,求取x1的公式为[2.1.2],该公式实际上也是决策边界的表达式x1 = -w[0]/w[1] * x0 - b/w[1]# 实现公式[2.1.3]求得大间隔margin,再除以二求得大间隔的一半margin_half = 1 / np.sqrt(w[0]**2 + w[1]**2)# 右上分界线的表达式up_line = x1 + margin_half# 左下分界线的表达式down_line = x1 - margin_half# 获得支持向量(即落在两条边界线上或之间的样本点)support_vecs = svm_classifier.support_vectors_# 画出支持向量,并在周围打上阴影做标注plt.scatter(support_vecs[:, 0], support_vecs[:, 1], s = 120, facecolors='red' )# 画出决策边界plt.plot(x0, x1, "k-", linewidth=2)# 画出两条分类边界plt.plot(x0, up_line, "k--", linewidth=2)plt.plot(x0, down_line, "k--", linewidth=2)

1.5.4 观察标准化的作用

在使用线性SVM完成分类任务之前,进行标准化是非常重要的步骤。如果不进行这一步,会对分类效果产生很大的负面影响。下面就以二维空间中几个分布稀疏的点为例,分别绘制未标准化前和未标准化后的分类情况,从而直观展示出标准化的重要性。代码如下:

# 画出几个分布稀疏的点Xs = np.array([[1, 50], [3, 30], [5, 20], [2, 85],[4, 70] ,[5, 80]]).astype(np.float64)ys = np.array([0, 0, 0,1, 1, 1])# 定义线性SVM分类器svm_clf = SVC(kernel="linear", C=100)# 使用分类器svm_clf对上述点进行拟合svm_clf.fit(Xs, ys)plt.figure(figsize=(10,4))# 第一个图展示未标准化的分类情况plt.subplot(121)plt.plot(Xs[:, 0][ys==1], Xs[:, 1][ys==1], "bo", label='Class 0')plt.plot(Xs[:, 0][ys==0], Xs[:, 1][ys==0], "gs", label='Class 1')plot_linear_svm_decision_margin_and_boundary(svm_clf, 0, 8)plt.xlabel("$x_0$", fontsize=14)plt.ylabel("$x_1$ ", fontsize=14, rotation=0)plt.title("Before Being Standardized", fontsize=14)plt.axis([0, 6, 0, 90])# 定义标准化类scaler = StandardScaler()# 使用标准化类对Xs中的点进行标准化,得到标准化后的数据X_scaled = scaler.fit_transform(Xs)# 使用分类器svm_clf对标准化后的点进行拟合svm_clf.fit(X_scaled, ys)# 第二个图展示标准化后的分类情况plt.subplot(122)plt.plot(X_scaled[:, 0][ys==1], X_scaled[:, 1][ys==1], "bo", label='Class 0')plt.plot(X_scaled[:, 0][ys==0], X_scaled[:, 1][ys==0], "gs",label='Class 1')plot_linear_svm_decision_margin_and_boundary(svm_clf, -2, 2)plt.xlabel("$x_0$", fontsize=14)plt.title("After Being Standardized", fontsize=14)plt.axis([-2, 2, -2, 2])

运行结果如下:

观察上面两张图,可以发现:

左图表示未标准化前的情况,横坐标的范围为0到6,纵坐标的范围为0到90,各个点的分布非常稀疏,导致整体的分类效果较差;右图表示标准化后的情况,横坐标和纵坐标的范围均缩小到个位数,导致数据点整体分布非常紧凑,分类的效果也比左图好得多。

由此可以看到:SVM线性分类中标准化的分类效果比未标准化好很多,所以在使用SVM做线性分类之前请务必先标准化

1.5.5 数据集的加载

线性SVM中一个很重要的参数是 C C C,该参数的选择会对分类效果造成很大影响。下面选取了鸢尾花数据集作为训练数据集,通过调整参数 C C C,并调用上面定义的可视化函数,在二维空间中实现了不同C值下分类效果的可视化,使得读者可以直观感受到 C C C 值调参对线性SVM分类效果的影响。数据集加载的代码如下:

# 加载鸢尾花数据集iris = datasets.load_iris()# 选取每个样本的第2、3个特征,组成二维数据集,便于可视化X = iris["data"][:, (2, 3)] # 属于类别2的样本标签置为1,否则置为0y = (iris["target"] == 2).astype(np.float64) # 由于SVM中要求类别的标签为-1或1,故需要对y做一下处理y = y *2 -1svm_clf = Pipeline([("scaler", StandardScaler()),("linear_svc", LinearSVC(C=1, loss="hinge", random_state=42)),])svm_clf.fit(X, y)

经过处理后的标签 y 就全都是1或-1,这样就符合二分类线性SVM对标签格式的要求。

1.5.6 定义不同的线性SVM分类器

下面定义了4个不同的线性分类器,目的是为了观察不同 C C C 值对分类效果的影响,所以必须保证除了 C C C 之外的其他参数均保持一致。

同时,对于每个分类器,在分类之前均需要对数据进行标准化操作。代码如下:

# 定义数据集的标准化方法scaler = StandardScaler()# 定义参数C不相同、其他参数相同的4个线性分类器svm_clf1 = LinearSVC(C=1, loss="hinge", random_state=42)svm_clf2 = LinearSVC(C=10, loss="hinge", random_state=42)svm_clf3 = LinearSVC(C=100, loss="hinge", random_state=42)svm_clf4 = LinearSVC(C=float("inf"), loss="hinge", random_state=42)# 对这4个分类器分别添加标准化方法,在对数据集的进行标准化后才拟合数据scaled_svm_clf1 = Pipeline([("scaler", scaler),("linear_svc", svm_clf1),])scaled_svm_clf2 = Pipeline([("scaler", scaler),("linear_svc", svm_clf2),])scaled_svm_clf3 = Pipeline([("scaler", scaler),("linear_svc", svm_clf3),])scaled_svm_clf4 = Pipeline([("scaler", scaler),("linear_svc", svm_clf4),])scaled_svm_clf1.fit(X, y)scaled_svm_clf2.fit(X, y)scaled_svm_clf3.fit(X, y)scaled_svm_clf4.fit(X, y)

1.5.7 实现分类效果可视化的准备工作

1.5.7.1 对各分类器的各个参数做标准化处理

标准化操作实际上分为如下两点:

数据集的标准化;分类器的参数 w \boldsymbol w w 和 b b b 的标准化。

步骤1上面已经实现,下面实现步骤2 。

在实现步骤2之前,需要先对sklearn中的标准化类 **StandardScaler() **的用法进行了解。

返回值

使用StandardScaler()类对样本 x x x 进行标准化的计算公式为:

z = x − u s z = \frac{x - u} s z=sx−u​

设数据集为 X X X。其中:

x x x 为当前样本 u u u 为 X X X中所有样本的各个特征所对应的均值 s s s 为各个特征的最大值与最小值之差 z z z (返回值)为样本经过标准化后的结果

原型

class sklearn.preprocessing.StandardScaler(X, copy=True, with_mean=True, with_std=True)

属性

scale_ndarray or None, shape (n_features,)

数据集中每个特征的最大值与最小值之差

mean_ndarray or None, shape (n_features,)

数据集中每个特征的平均值

var_ndarray or None, shape (n_features,)

数据集中每个特征的方差

方法

fit(X[, y]):计算数据集的均值和标准差,用于后续数据集的标准化

fit_transform(X[, y]):在fit(X[, y])求得的标准差的基础上对数据X进行标准化

transform(X[, copy]):在fit(X[, y])已求得的均值的基础上,对数据X进行标准化

上面用到的计算公式:

z = x − u s z = \frac{x - u} s z=sx−u​

实际上用的就是这种方法。

1.5.7.2 求解偏置 b \boldsymbol b b

偏置 b b b 的求解步骤如下:

求出 u ′ = − u / s \boldsymbol u^{'}=-{\boldsymbol u}/{s} u′=−u/s ,即每个特征经过缩放后的平均值的相反数,其shape为 ( 2 , ) (2, ) (2,);将 u ′ \boldsymbol u^{'} u′ 送入各分类器所对应的decision_function函数中。

1.5.7.3 decision_function函数

该函数是线性SVM分类器里的一种方法。

若形参X为样本,则求的是该样本到决策边界的有符号距离;若形参X为 u ′ \boldsymbol u^{'} u′,则求的是分类器对应的偏置 b b b,对应上面的求解过程。

1.5.7.3 代码实现

将上面三个小节整合成代码如下:

# 获取各分类器经过标准化后的偏置bb1 = svm_clf1.decision_function([-scaler.mean_ / scaler.scale_])b2 = svm_clf2.decision_function([-scaler.mean_ / scaler.scale_])b3 = svm_clf3.decision_function([-scaler.mean_ / scaler.scale_])b4 = svm_clf4.decision_function([-scaler.mean_ / scaler.scale_])# 获取各分类器经过标准化后的权重w1 = svm_clf1.coef_[0] / scaler.scale_w2 = svm_clf2.coef_[0] / scaler.scale_w3 = svm_clf3.coef_[0] / scaler.scale_w4 = svm_clf4.coef_[0] / scaler.scale_# 将标准化后的偏置和权值赋值给各个分类器,使得各个分类器的参数被正确标准化svm_clf1.intercept_ = np.array([b1])svm_clf2.intercept_ = np.array([b2])svm_clf3.intercept_ = np.array([b3])svm_clf4.intercept_ = np.array([b4])svm_clf1.coef_ = np.array([w1])svm_clf2.coef_ = np.array([w2])svm_clf3.coef_ = np.array([w3])svm_clf4.coef_ = np.array([w4])

由于后续需要标注出支持向量,所以还需要找出支持向量。

支持向量满足的公式为:

y i ( w T x i + b ) < 1 y_i(\boldsymbol w^T \boldsymbol {x_i}+b) < 1 yi​(wTxi​+b)<1

利用该公式,就可以获取不同分类器作用下的支持向量:

# 获取标准化后各分类器支持向量的索引,用于后续标注支持向量support_vectors_idx1 = (y * (X.dot(w1) + b1) < 1).ravel()support_vectors_idx2 = (y * (X.dot(w2) + b2) < 1).ravel()support_vectors_idx3 = (y * (X.dot(w3) + b3) < 1).ravel()support_vectors_idx4 = (y * (X.dot(w4) + b4) < 1).ravel()# 将标准化后各分类器的支持向量赋值给分类器的原支持向量svm_clf1.support_vectors_ = X[support_vectors_idx1]svm_clf2.support_vectors_ = X[support_vectors_idx2]svm_clf3.support_vectors_ = X[support_vectors_idx3]svm_clf4.support_vectors_ = X[support_vectors_idx4]

将上述代码封装成如下函数,可以使得代码更加简洁。

def standardize_svm_clf_parameters(svm_clf):b = svm_clf.decision_function([-scaler.mean_ / scaler.scale_])w = svm_clf.coef_[0] / scaler.scale_svm_clf.intercept_ = np.array([b])svm_clf.coef_ = np.array([w])support_vectors_idx = (y * (X.dot(w) + b) < 1).ravel()svm_clf.support_vectors_ = X[support_vectors_idx]svm_clfs = [svm_clf1, svm_clf2, svm_clf3,svm_clf4]for i in range(4):standardize_svm_clf_parameters(svm_clfs[i])

到此为止,所有的准备工作已经就绪。接下来就是将上面的过程整合起来,画图表示。

1.5.8 分类效果可视化图片的绘制

线性SVM中一个很重要的参数是 C C C,该参数的选择会对分类效果造成很大影响。下面将通过调整该参数 ,并调用上面定义的可视化函数,在二维空间中实现不同 C 值下分类效果的可视化,使得读者可以直观感受到 C C C 值调参对线性SVM分类效果的影响。

代码如下:

fig, axes = plt.subplots(nrows=2,ncols=2, figsize=(12,8), sharey=True)# 左上,C=1plt.sca(axes[0][0])plt.plot(X[:, 0][y==1], X[:, 1][y==1], "g^", label="Class 0")plt.plot(X[:, 0][y==-1], X[:, 1][y==-1], "bo", label="Class 1")plot_linear_svm_decision_margin_and_boundary(svm_clf1, 2.0, 8.0)plt.ylabel("$x_2$", fontsize=10, rotation=0)plt.legend(loc="upper left", fontsize=10)plt.title("$C = {}$".format(svm_clf1.C), fontsize=14)plt.axis([2.0, 8.0, 0.8, 3.0])# 右上,C=10plt.sca(axes[0][1])plt.plot(X[:, 0][y==1], X[:, 1][y==1], "g^")plt.plot(X[:, 0][y==-1], X[:, 1][y==-1], "bo")plot_linear_svm_decision_margin_and_boundary(svm_clf2, 2.0, 8.0)plt.title("$C = {}$".format(svm_clf2.C), fontsize=14)plt.axis([2.0, 8.0, 0.8, 3.0])# 左下,C=100plt.sca(axes[1][0])plt.plot(X[:, 0][y==1], X[:, 1][y==1], "g^")plt.plot(X[:, 0][y==-1], X[:, 1][y==-1], "bo")plot_linear_svm_decision_margin_and_boundary(svm_clf3, 2.0, 8.0)plt.xlabel("$x_1$", fontsize=10)plt.ylabel("$x_2$", fontsize=10, rotation=0)plt.title("$C = {}$".format(svm_clf3.C), fontsize=14)plt.axis([2.0, 8.0, 0.8, 3.0])# 右下,C → +∞plt.sca(axes[1][1])plt.plot(X[:, 0][y==1], X[:, 1][y==1], "g^")plt.plot(X[:, 0][y==-1], X[:, 1][y==-1], "bo")plot_linear_svm_decision_margin_and_boundary(svm_clf4, 2.0, 8.0)plt.xlabel("$x_1$", fontsize=10)plt.title("$C = {}$".format(svm_clf4.C), fontsize=14)plt.axis([2.0, 8.0, 0.8, 3.0])

运行结果如下:

这样就画出了不同 C 的取值下线性SVM的分类情况。用红色圈起来的部分表示支持向量。

可以看到,随着 C C C 的增加,分类间隔越窄,分类的要求越来越严格,允许分错的样本数越少。

从理论上讲,当 C → C\to C→ +∞ 时,若数据集中有噪声,数据集将不可分,进而产生错误。

对此,sklearn中对于 C → C\to C→ +∞ 的情况进行了默认优化,将硬间隔优化成了软间隔,从而规避了使用硬间隔导致不可分的情况。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。