关于支持向量机的一份介绍

在这篇文章中,我将介绍与支持向量机有关的东西,我们知道支持向量机主要分两类,就是线性支持向量机核支持向量机这两种(当然还有其他的,如多类支持向量机、 Nu-Support Vector Regression等),因此我将介绍它俩的联系与区别,但首先将会详细介绍它俩有关的知识及python实现。

一、 线性支持向量机

1.1 概念

线性支持向量机(Linear Support Vector Machine, Linear SVM)是一种用于分类和回归分析的监督学习模型,特别适用于数据在特征空间中是线性可分的情况。

线性SVM原本可用于进行二分类任务,但如果进行"一对多"等处理后,也可进行多分类任务。

下图就是iris数据集进行SVM后的图像:

1.2 数学模型

关于线性SVM的数学模型可以分为三来来看,分别是决策函数、原问题以及对偶问题。

(1)决策函数

线性SVM的决策函数是用来预测新输入样本所属类别的函数。在求解线性SVM的对偶问题之后,我们得到一系列拉格朗日乘子 αi,这些乘子用于构建最终的决策函数。其中拉格朗日乘子是对偶问题里的,暂且不谈。

我们知道SVM是用于划分类别的,所以我们可以用一个线性组合来描述:

我们将其记为:(W,b)。这样就会诞生一个空间中任意点到超平面的距离r。

然后我们假设这个超平面能正确分类样本,即方才的线性组合>0时,有yi = +1;反之小于0时,有yi = -1。

那么我将这个线性组合重写下就是:

如果用sign函数来表示,可以是这样:

(2)原问题

首先我们知道SVM问题就是一个优化问题,旨在数据线性可分的情况下去寻找一个最优的超平面将之划分,并使间隔最大化。

其中,距离超平面最近的几个训练样本使得其决策函数成立,它们就被称为是"支持向量"。而两个异类支持向量到超平面的和就是"间隔"。

为了间隔最大化,就有了原问题,所以可以写出以下式子:

(3)对偶问题

关于刚才的问题,我们要知道如果直接就用那些式子去找最优超平面会很复杂,所以我们我们需要对偶问题来帮助我们。而在对偶问题中就需要拉格朗日乘子,关于这个乘子,我们则需要了解下拉格朗日函数。

假如我们有目标函数f(x,y),我们要找到它的极值,但同时又存在一个g(x,y)=c(c为常数)来对其进行约束的话,我们就可以构造一个新函数来解决,这个新函数就是拉格朗日函数,表达式如下:

其中的λ(lambda)就是拉格朗日乘子。

而要解决这个式子就需要让其梯度为0,如下:

然后有:

最后就可分别求得x、y、λ的值了。

那么我们就来求取在对偶条件下的线性SVM的模型:

我们已知拉格朗日函数的形式,那么我们将相应的函数带入即可。首先是目标函数,因为我们要求取一个最优超平面,所以将刚才的原问题中的模型带入到f(x,y)的位置;然后是约束函数,因为要让间隔最大化,所以需要约束条件如此确保间隔的最大化;接下来是常数C,一般在没有先验条件的前提下,我们都会使用1作为默认值。(当C越大,模型越倾向于减少分类错误,C越小,模型的泛化能力越强)

那么就有了最后的模型:

1.3 python实现
python 复制代码
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.svm import SVC
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

# 加载Iris数据集
iris = load_iris()
X = iris.data[:, :2]  # 只取前两个特征:花萼长度和花萼宽度
y = iris.target
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 创建SVM模型
svm = SVC(kernel='linear', C=1)
# 训练模型
svm.fit(X_train, y_train)
y_pre = svm.predict(X_test)
accuracy = accuracy_score(y_test, y_pre)
print("Accuracy is: {}".format(accuracy))

# 绘制决策边界
def plot_decision_boundary(model, X, y):
    # 创建网格
    x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
    y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
    xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.01),
                         np.arange(y_min, y_max, 0.01))

    # 预测网格中的类别
    Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
    Z = Z.reshape(xx.shape)
    # 绘制背景色
    plt.contourf(xx, yy, Z, alpha=0.8)
    # 绘制训练数据点
    markers = ['o', 's', '^']
    for i, label in enumerate(np.unique(y)):
        plt.scatter(X[y == label, 0], X[y == label, 1], marker=markers[i], label=iris.target_names[label])

    # 绘制决策边界
    plt.contour(xx, yy, Z, colors='k', levels=[-1, 0, 1], linestyles=['--', '-', '--'])
    # 图像设置
    plt.title('Iris Dataset with SVM Decision Boundary')
    plt.xlabel('Sepal Length (cm)')
    plt.ylabel('Sepal Width (cm)')
    plt.legend()
    plt.show()

# 绘制决策边界
plot_decision_boundary(svm, X, y)

二、 核支持向量机

1.1 概念

核SVM利用核函数(Kernel Function)将输入数据映射到一个更高维的空间,在这个高维空间中,原本非线性可分的数据变得线性可分。

同样的,我给出一个用iris进行SVM分类后的图像,如下图:(其代码随后给出)

1.2 数学模型

我们来看核SVM的数学模型,其基本形式与线性的十分相似,我们令Φ(x )来表示将x 映射后的特征向量,于是之前的模型就发生了改变,便成为:的形式。然后其对偶问题也就变为:

最后经过一些重写、化简等就变为:

而这里的函数κ()就是"核函数"(kernal function)。

而关于核函数其实存在多种选择,因为我自己也对其不够了解,所以只在此给出西瓜书上的常用核函数表,如下:

1.3 联系

在我们初步了解二者的概念后,我们就可以知道,其实KSVM(核SVM)就是线性SVM在原本处理不了的非线性数据上做出的一个拓展,旨在增加维度而能实现让SVM进行分类。

1.4 区别

适用范围:在线性SVM中,它适用于处理线性可分的数据集,即可以通过一个超平面(在二维空间中是一条直线,在高维空间中是一个超平面)来分隔不同类别的数据点;而KSVM中,它适用于处理非线性可分的数据集,即数据不能通过一个简单的超平面来分隔。在这种情况下,数据可能需要被映射到一个更高维的空间,才能找到一个合适的分隔超平面。

计算复杂度:线性SVM的复杂度相对较低,而KSVM因为核函数的缘故,计算复杂度较高。

实际应用:在线性可分数据集上,线性SVM通常比KSVM更快并且更简单。例如,在文本分类或一些简单的图像识别任务中,数据可能是线性可分的;在非线性可分数据集上,KSVM能够更好地捕捉数据中的复杂关系。例如,在手写数字识别、生物信息学等领域,数据通常是非线性可分的,KSVM能够提供更高的准确率。

1.5 python代码
python 复制代码
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.svm import SVC
from mpl_toolkits.mplot3d import Axes3D

# 加载Iris数据集
iris = datasets.load_iris()
X = iris.data[:, :3]  # 使用前三个特征
y = iris.target
# 使用线性核的支持向量机
svm = SVC(kernel='linear')
svm.fit(X, y)
# 创建3D图形
fig = plt.figure(figsize=(8, 6))
ax = fig.add_subplot(111, projection='3d')  # 使用add_subplot代替Axes3D
ax.view_init(elev=-152, azim=-26)  # 设置视角
# 掩码
mask_0 = y == 0
mask_1 = y == 1
mask_2 = y == 2
# 绘制散点图
ax.scatter(X[mask_0, 0], X[mask_0, 1], X[mask_0, 2], c='b', s=60, label="Setosa")
ax.scatter(X[mask_1, 0], X[mask_1, 1], X[mask_1, 2], c='r', marker='^', s=60, label="Versicolour")
ax.scatter(X[mask_2, 0], X[mask_2, 1], X[mask_2, 2], c='g', marker='s', s=60, label="Virginica")
# 设置坐标轴标签
ax.set_xlabel("Sepal length")
ax.set_ylabel("Sepal width")
ax.set_zlabel("Petal length")
# 添加图例
ax.legend()
# 绘制决策平面
w = svm.coef_[0]
a = -w[0] / w[2]
b = -w[1] / w[2]
xx, yy = np.meshgrid(np.linspace(X[:, 0].min(), X[:, 0].max(), 50),
                     np.linspace(X[:, 1].min(), X[:, 1].max(), 50))
zz = (-svm.intercept_[0] - a * xx - b * yy) / w[2]

# 画出平面
surf = ax.plot_surface(xx, yy, zz, rstride=1, cstride=1, color='none',
                       alpha=0.3, edgecolor='darkblue')
# 显示图形
plt.show()

三、 补足

此外,我们会发现在分类时偶尔会有些数据点分类错误或是在间隔内,那么我们就可以称它为"软间隔",那么我可以在这里完整描述下关于软间隔的含义:它适用于不完全线性可分的数据集,允许一定的误差。并通过调整C来控制惩罚程度,以达到最好的泛化能力。而于此相对的,硬间隔的含义就是:适用于 完全线性可分的数据集,不允许任何训练样本出现在间隔内或是被错误地分类。

因为在现实中大多不能做到硬间隔的分类,所以我们我们需要软间隔,更需要关于它而对原有的SVM模型进行修改,比如加入损失函数,引入松弛变量等,这样就能得到常说的"软间隔SVM"。

SVM处了能处理分类问题还能进行回归,这样就是"支持向量回归"了,即Support Vector Regression。

关于SVM的东西还有很多,我将在之后继续介绍。

此上

相关推荐
予安灵8 分钟前
图的邻接矩阵和邻接表存储
数据结构·算法·
南宫生15 分钟前
力扣-位运算-1【算法学习day.41】
java·学习·算法·leetcode
罗小罗同学26 分钟前
医学AI公开课·第一期|Machine Learning&Transformers in Med AI
人工智能·机器学习·医学人工智能·公开课
Felven29 分钟前
E. Negatives and Positives
算法
Beau_Will1 小时前
数据结构-树状数组专题(2)
数据结构·c++·算法
fanxiaohui121382 小时前
浪潮信息自动驾驶框架AutoDRRT 2.0,赋能高阶自动驾驶
运维·服务器·网络·人工智能·机器学习·金融·自动驾驶
济南信息学奥赛刘老师2 小时前
GESP考试大纲
开发语言·c++·算法·青少年编程
~yY…s<#>2 小时前
【刷题21】BFS解决FloodFill算法专题
数据结构·c++·算法·leetcode·宽度优先
rellvera2 小时前
【强化学习的数学原理】第03课-贝尔曼最优公式-笔记
笔记·机器学习
九圣残炎2 小时前
【从零开始的LeetCode-算法】3297. 统计重新排列后包含另一个字符串的子字符串数目 I
java·算法·leetcode