查看原文
其他

第9.3节 SVM示例代码与线性不可分

空字符 月来客栈 2024-01-21

各位朋友大家好,欢迎来到月来客栈,我是掌柜空字符。

本期推送内容目录如下,如果本期内容对你有所帮助,欢迎点赞、转发支持掌柜!

  • 9.3 SVM示例代码与线性不可分
    • 9.3.1 线性SVM示例代码
    • 9.3.2 从线性不可分谈起
    • 9.3.3 将低维特征映射到高维空间
    • 9.3.4 SVM中的核技巧
    • 9.3.5 从高维到无穷维
    • 9.3.6 常见核函数
    • 9.3.7 小结
    • 引用

9.3 SVM示例代码与线性不可分

在前面两节内容中,笔者介绍了支持向量机的基本思想及对应的数学原理。不过说一千道一万,还是不如自己亲手来做一做。在接下来的内容中,笔者将首先介绍如何通过sklearn来搭建相应的SVM分类模型,然后将介绍如何处理SVM中的线性不可分问题。

9.3.1 线性SVM示例代码

在sklearn中可以通过from sklearn.svm import SVC 这行代码导入SVM分类模型。有读者可能会觉得奇怪,为什么导入的是一个叫SVC的东西?这是因为其实SVM不仅可以用来分类,它同样也能用于回归问题,因此SVC其实就是支持向量分类的意思。

进入SVC定义的地方便可以发现里面有很多超参数可以进行设置,代码如下:

1  def __init__(self,
2     C=1.0, 
3     kernel='rbf', 
4     degree=3, 
5     gamma='scale',
6     coef0=0.0,
7     decision_function_shape='ovr'):

在上述代码中只列举了SVM中常见的一些超参数。不过这里暂时只对Kernel参数进行介绍,其他的参数等介绍完相关原理后再进行解释。根据前面两节内容可知,SVM是一个线性分类器,因此这里只需将参数Kernel设置为Kernel='linear'便能达到这一目的。

在完成SVC的导入工作后,根据如下代码便可以使用线性SVM进行分类建模,完整实例代码参见Book/Chapter09/01_linear_svm.py文件,代码如下:

1 def train(x_train, x_test, y_train, y_test):
2     model = SVC(kernel='linear')
3     model.fit(x_train, y_train)
4     y_pre = model.predict(x_test)
5     print(f"准确率为:{model.score(x_test, y_test)}")
6     # 准确率为:0.975925925925926

上述代码便是通过sklearn实现线性SVM的全部代码。可以看出,在sklearn中使用一个模型的步骤依旧是笔者在第5.3.1节中总结的3步: 建模、训练和预测。同时,由于这里的超参数Kernel暂时只有一个取值,因此不需要进行模型选择。从最后在测试集上的结果来看,线性SVM分类器的表现在准确率上有着不错的结果。

9.3.2 从线性不可分谈起

根据9.2节内容中SVM的思想来看,到目前为止谈到的情况都是线性可分的,也就是说总能找到一个超平面将数据集分开。可事实上却是,在大多数场景中各个类别之间是线性不可分的,即类似于如图9-6所示的情况。

图 9-6 SVM线性不可分图

对于图9-6中这种情况应该怎么才能将其分开呢?在第4.2.4节中笔者介绍过,这类问题可以使用特征映射的方法将原来的输入特征映射到更高维度的空间,然后寻找一个超平面,以此将数据集中不同类别的样本进行分类,如图9-7所示。

图 9-7 SVM特征映射

如图9-7所示,现在我们已经用一个超平面完美地将不同类别的样本分开了。不过此时有读者可能会感到疑惑,这还是刚刚的数据集吗?之前明明在二维平面上,现在却显示到三维空间了。虽然数据集确确实实已经不是同一个数据集了,但是每个数据样本所对应的类别却依旧和原来的一样,只不过现在给它穿上了一件“马甲”。也就是说,假如是正样本,那么它穿上马甲变成后仍然属于正样本,只要能把进行正确分类,那么自然也就能够对进行分类了。

在介绍完特征映射的基本思想后,下面笔者就来介绍如何在SVM中将低维特征映射到高维空间中。

9.3.3 将低维特征映射到高维空间

所谓将低维特征映射到高维空间指的是用一定的映射关系,将原始特征映射到更高维度的空间。例如通过一个函数将一维特征映射到三维特征。在这里,笔者先直接给出SVM中权重的计算解析式,其具体由来可参见9.7.1节内容。

根据式(9.22)可知,假如此时已求得,那么对一个新输入的样本点其预测结果为

其中表示训练集中的样本点(其实就是支持向量),为新输入的样本点。表示之间的内积(Inner Product)。当且仅当式(9.23)大于0时,新输入样本的类别为

按照上面提到的通过函数将低维映射到高维的思想,只需要在预测时将之前的全部替换成,则此时有

虽然这样一来算是一定程度上解决了SVM中线性不可分的难题,但是又出现了一个新的问题——“维度爆炸”。

假设现有数据集,其样本点有3个维度,分别为(下面简写为)。现通过函数将其映射到某个9维空间中,并且假设映射后的9个维度分别为。如果此时要对新样本进行预测,则首先需要对进行计算

此时各位读者应该会发现这个过程的计算量太大了,整体复杂度为(分别为)、),其中为特征的维数,因此,若是在高维数据中进行更为复杂的映射,那么整个过程的时间复杂度将不可想象,而这就是“维度爆炸”,但是此时我们仔细想一想,“映射”和“预测”之间到底是什么关系?“映射”是作为一种思想将低维映射到高维,从而解决线性不可分到可分的问题,而“预测”时所计算的则是,但其实它就是一个值。不管最后采用的是什么样的映射规则,在预测时都只需计算这么一个值,因此,假如能通过某种“黑箱”直接计算出这个值岂不最好?那么有没有这样的“黑箱”呢?当然有,这一“黑箱”操作被称为核技巧(Kernel Trick)。

为你认可的知识付费,欢迎订阅本专栏阅读更多优质内容!


继续滑动看下一个

第9.3节 SVM示例代码与线性不可分

空字符 月来客栈
向上滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存