超全面讲透一个算法模型,SVM!!

文摘   2024-10-23 11:36   北京  

大家好,今儿和大家分享的是关于 SVM 的内容~

支持向量机(SVM, Support Vector Machine)是一个分类算法,可以帮助我们把数据分成不同的类别。

下面呢,我会用一个简单的例子一步步解释什么是支持向量机,以及它是如何工作的

需要本文PDF的朋友,可以文末获取~

假设的场景

我们有一群小动物,比如猫和狗,现在我们需要训练一个模型,让它能区分这些动物的照片。我们的任务就是让 SVM 帮我们画一条“线”,把猫和狗正确分开。

怎么分开猫和狗?

首先,我们可以把每只动物的照片转化为一些数据特征,比如:

  • 猫可能更轻一点,狗比较重(可以是“体重”)。
  • 猫的耳朵比较尖,狗的耳朵可能更圆(可以是“耳朵形状”)。

我们把这些特征画在一个二维平面上,每个点代表一只动物。假设猫的点在左边,狗的点在右边,那么我们现在就想找到一条线,把猫和狗分开,这就是 SVM 要做的事情。

1. 什么是支持向量?

在二维平面上,SVM 不仅仅是找一条能分开猫和狗的线,而是要找出最优的线。所谓“最优”,是指这条线离两类(猫和狗)的数据点尽量远。支持向量,就是离那条分割线最近的点,这些点决定了分割线的位置。

2. 什么是间隔?

SVM 会尽可能让线两侧的间隔(Margin)最大化。间隔就是从分割线到最接近的猫或狗的点的距离。如果我们找到的线让猫和狗都能分开,而且这条线到最靠近它的猫和狗的距离是最大的,那这条线就是我们要找的“最优分割线”。

具体步骤总结:

  • 把数据点画在平面上(如体重和耳朵形状)。
  • 找到一条线,分开猫和狗,并且让这条线尽可能远离两类动物。
  • 支持向量就是离线最近的那些点,它们帮助决定了这条线的位置。
  • 最大化间隔,确保我们找的线是最稳健的(即不容易受新数据影响)。

举个简单的例子:

想象一下你在沙滩上看到猫的脚印和狗的脚印。猫的脚印比较轻、比较小,狗的脚印比较重、比较大。你想用一根棍子(分割线)把这些脚印分开。SVM 会帮你找出一根棍子,这根棍子不仅能把脚印分得最清楚,还能离猫脚印和狗脚印都尽量远一些,这样即使来了一些新的脚印,你也能更好地判断它们是猫还是狗留下的。

SVM 的应用场景

SVM 常用于:

  • 图像分类(比如猫狗分类)
  • 文本分类(比如垃圾邮件分类)
  • 生物信息学(比如基因数据分类)

这样,SVM 就是一个非常实用的工具,能帮我们在各种复杂的场景下进行分类工作。

只要记住 SVM 就是在帮我们找到一条线来分开不同的东西,而且它会尽可能让这条线分得稳妥,这样就容易理解了!

我们接下来会详细介绍支持向量机(SVM)的公式推导,然后基于这些公式,创建一个完整的案例,手动实现SVM。

基本原理

SVM 的目标是找到一条超平面,能够将两类数据点分开,同时最大化两类之间的间隔。我们来推导 SVM 的基本公式。

线性可分的情况

我们有一个训练数据集 ,其中  是 d 维特征向量, 是标签(我们假设只有两类)。SVM 的目标是找到一个分割超平面:

其中, 是权重向量, 是偏置项。

对于每一个数据点 ,我们希望:

这保证了数据点  被正确分类,且远离超平面的间隔至少为 1。

最大化间隔

间隔定义为超平面到最近数据点的距离。间隔的大小可以写作:

SVM 的目标是最大化间隔,这等价于最小化 ,因此我们可以得到如下优化问题:

同时满足约束条件:

这是一个凸优化问题,可以通过拉格朗日乘子法来解决。

拉格朗日函数

为了将约束条件加入到优化目标中,我们引入拉格朗日乘子 

我们对    求导,得到拉格朗日对偶问题:

约束条件是:

通过求解这个问题,我们可以得到 ,从而计算出   

完整案例

这里,我们手动实现支持向量机,并使用虚拟数据集进行分类。在代码中,我们将用拉格朗日乘子法求解 SVM。

import numpy as np
import matplotlib.pyplot as plt

# 生成虚拟数据集
np.random.seed(1)
n_points = 1000
X_pos = np.random.randn(n_points, 2) + [22]  # 正类 (+1)
X_neg = np.random.randn(n_points, 2) + [-2-2]  # 负类 (-1)

# 合并数据
X = np.vstack((X_pos, X_neg))
y = np.hstack((np.ones(n_points), -1 * np.ones(n_points)))

# 画出初始数据分布
plt.figure(figsize=(86))
plt.scatter(X_pos[:, 0], X_pos[:, 1], color='red', label='Positive (+1)')
plt.scatter(X_neg[:, 0], X_neg[:, 1], color='blue', label='Negative (-1)')
plt.title("Initial Data Distribution")
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.legend()
plt.show()


# 定义线性核函数
def linear_kernel(x1, x2):
    return np.dot(x1, x2)


# 构建SVM的优化目标函数(拉格朗日乘子法)
def fit_svm(X, y, C=1.0):
    n_samples, n_features = X.shape
    K = np.zeros((n_samples, n_samples))
    for i in range(n_samples):
        for j in range(n_samples):
            K[i, j] = linear_kernel(X[i], X[j])

    P = np.outer(y, y) * K
    q = -np.ones(n_samples)
    G = np.vstack((-np.eye(n_samples), np.eye(n_samples)))
    h = np.hstack((np.zeros(n_samples), C * np.ones(n_samples)))
    A = y.reshape(1-1)
    b = np.zeros(1)

    # 使用cvxopt求解器求解二次优化问题
    from cvxopt import matrix, solvers
    P = matrix(P)
    q = matrix(q)
    G = matrix(G)
    h = matrix(h)
    A = matrix(A, (1, n_samples), 'd')
    b = matrix(b)

    solvers.options['show_progress'] = False
    solution = solvers.qp(P, q, G, h, A, b)

    alphas = np.ravel(solution['x'])

    # 计算权重向量w
    w = np.sum(alphas[:, None] * y[:, None] * X, axis=0)

    # 计算偏置b
    sv = (alphas > 1e-5)
    b = np.mean(y[sv] - np.dot(X[sv], w))

    return w, b, alphas


# 训练SVM
w, b, alphas = fit_svm(X, y)

# 画出支持向量
plt.figure(figsize=(86))
plt.scatter(X_pos[:, 0], X_pos[:, 1], color='red', label='Positive (+1)')
plt.scatter(X_neg[:, 0], X_neg[:, 1], color='blue', label='Negative (-1)')
plt.scatter(X[alphas > 1e-5][:, 0], X[alphas > 1e-5][:, 1], s=100, facecolors='none', edgecolors='yellow',
            label='Support Vectors')

# 画出分割超平面
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.linspace(x_min, x_max, 100), np.linspace(y_min, y_max, 100))
Z = np.dot(np.c_[xx.ravel(), yy.ravel()], w) + b
Z = Z.reshape(xx.shape)

plt.contour(xx, yy, Z, levels=[-101], linestyles=['--''-''--'], colors='k')
plt.fill_between(xx[0], y_min, y_max, where=Z[0] > 0, color='red', alpha=0.1)
plt.fill_between(xx[0], y_min, y_max, where=Z[0] < 0, color='blue', alpha=0.1)
plt.title("SVM Decision Boundary and Support Vectors")
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.legend()
plt.show()

# 画出拉格朗日乘子的分布
plt.figure(figsize=(86))
plt.plot(np.arange(len(alphas)), alphas, 'ro', label='Lagrange Multipliers')
plt.title("Distribution of Lagrange Multipliers")
plt.xlabel('Data Index')
plt.ylabel('Alpha Value')
plt.legend()
plt.show()

# 分类结果的3D图
fig = plt.figure(figsize=(86))
ax = fig.add_subplot(111, projection='3d')
ax.scatter(X_pos[:, 0], X_pos[:, 1], alphas[:n_points], color='red', label='Positive (+1)')
ax.scatter(X_neg[:, 0], X_neg[:, 1], alphas[n_points:], color='blue', label='Negative (-1)')
ax.set_title("3D View of Data with Lagrange Multipliers")
ax.set_xlabel('Feature 1')
ax.set_ylabel('Feature 2')
ax.set_zlabel('Alpha')
ax.legend()
plt.show()

初始数据分布图:展示了正类(红色)和负类(蓝色)数据点的分布情况。

支持向量与分割平面图:展示了通过SVM找到的分割超平面(黑色线),同时标出了支持向量(黄色边框的数据点)。

拉格朗日乘子分布图:展示了每个数据点对应的拉格朗日乘子的值,支持向量的乘子值大于0。

3D图形:通过3D图展示了数据点的特征1、特征2和对应的拉格朗日乘子的分布。

这些图形帮助我们可视化 SVM 是如何工作的,并且展示了支持向量、分类边界和拉格朗日乘子的关系。

最后

需要原文PDF 的同学,扫码备注「文章PDF」即可!

最近准备了16大块的内容,124个算法问题的总结,完整的机器学习小册,免费领取~
今天给大家准备了关于「深度学习」的论文合集,往期核心论文汇总,分享给大家。
点击名片,回复「深度学习论文」即可~
如果你对类似于这样的文章感兴趣。
欢迎关注、点赞、转发~

机器学习和人工智能AI
让我们一起期待 AI 带给我们的每一场变革!推送最新行业内最新最前沿人工智能技术!
 最新文章