支持向量分类器与Mini 2D 据集的指南

2024年10月10日 由 alex 发表 38 0

介绍

“支持向量机(SVM)的分类工作原理非常简单--它试图找到分隔两个类别的最佳线"。


虽然前提听起来很简单,但 SVM 是一种充满数学技巧的算法。为什么它被称为 “机器”?为什么我们需要支持向量?为什么有些点突然变得不重要了?为什么必须是直线--哦,等等,超平面?还有优化公式,显然这个公式非常棘手,我们需要另一个版本,叫做对偶形式。但是等等,现在我们需要另一种叫做 SMO 的算法来解决这个问题?scikit-learn刚刚吐出的所有对偶系数是怎么回事?如果这还不够,当直线解不出来的时候,我们又要突然使用神奇的 “内核技巧”?我们为什么需要这些技巧?为什么所有教程都不显示实际数字?


在本文中,我试图阻止这种疯狂的支持向量。我将尝试用真实的数字(当然也包括其可视化)来解释实际发生的事情,但不包含复杂的数学,非常适合初学者。


定义

支持向量机是一种有监督的学习模型,主要用于分类任务,但也可用于回归。SVM 的目标是找到最适合将数据集划分为不同类别(叹气......)的线,最大化这些类别之间的差值。


16


“支持向量 "是最靠近直线的数据点,实际上也可以定义这条直线。那么 “机器 ”又是怎么回事呢?虽然其他机器学习算法也可以包含 “机器”,但 SVM 的命名可能部分是由于其开发时的历史背景。就是这样。


使用的数据集

要了解 SVM 如何工作,最好从样本较少、维度较小的数据集开始。我们将以这个简单的迷你 2D 数据集为例。


17


我们将不解释训练过程本身的步骤,而是从一个关键词到另一个关键词,看看 SVM 究竟是如何工作的:


第 1 部分:基本组件

决策边界

SVM 中的决策边界是算法确定的最能区分不同类别数据的线(在高维度中称为 “超平面”)。


这条线试图将大多数 “是 ”点保留在一边,而将大多数 “否 ”点保留在另一边。不过,由于数据不是线性可分的,因此这条边界并不完美--有些点可能会在 “错误 ”的一边。


一旦确定了这条线,就可以根据边界的哪一边对任何新数据进行分类。


18


线性可分性

线性可分性指的是我们是否能画出一条直线,将两类数据点完全分开。如果数据是线性可分的,SVM 就能在类与类之间找到一条清晰的硬边界。但是,当数据不可线性分离时,SVM 需要使用更先进的技术。


19


边距

SVM 中的边际是决策边界与每个类别中最接近的数据点之间的距离。这些最近的点称为支持向量。


SVM 的目标是最大化这个边际。边际越大,泛化效果越好,即能够正确地对新的、未见过的数据点进行分类。


不过,由于数据通常不是完全可分离的,SVM 可能会使用软边际方法。这就允许某些点在边际内,甚至在边界的错误一侧,以完美分离换取更强大的整体分类器。


20


硬边际与软边际

硬边际 SVM 的理想情况是,所有数据点都能被决策边界完全分开,不会出现错误分类。在这种情况下,边际是 “硬 ”的,因为它不允许任何数据点位于边界的错误一侧或边际内。


另一方面,软边际 SVM 允许一定的灵活性。它允许一些数据点被错误分类或位于边际内。这样,SVM 就能在以下两个方面找到良好的平衡:

  1. 最大化边际
  2. 最小化分类误差


21


距离计算

在 SVM 中,距离计算在训练和分类中都起着重要作用。点 x 与决策边界的距离由以下公式给出:


w - x + b| / ||w|||


其中,w 是垂直于超平面的权重向量,b 是偏置项,||w||| 是 w 的欧氏常态。


22


支持向量

支持向量是与超平面距离最近的数据点。它们之所以重要,是因为 它们 “支持 ”超平面,定义了超平面的位置。


支持向量的特殊之处在于,它们是确定决策边界的唯一重要点。所有其他点都可以移除,而不会改变边界的位置。这是 SVM 的一个关键特征--它根据最关键的点而不是所有数据点做出决策。


23


松弛变量

软边际 SVM 中引入了松弛变量,用于量化每个数据点的误分类或违反边际的程度。它们之所以被称为 “松弛”,是因为它们在拟合数据时给了模型一些松弛或灵活性。


在 SVM 中,松弛变量 ξᵢ 的计算公式为:

ξᵢ = max(0, 1 - yᵢ(w - xᵢ + b))


其中

- w 是权重向量

- b 是偏差项

- xᵢ 是输入向量

- yᵢ 是相应的标签


该公式仅在类标签 yᵢ 为 {-1, +1} 格式时有效。它可以优雅地处理两个类别:

- 超出边际的正确分类点:ξᵢ = 0

- 分类错误或违反边距的点: ξᵢ > 0


使用{-1, +1} 标签可以保持 SVM 的数学对称性并简化优化,而不像{0, 1} 标签那样需要对每个类别进行单独分类。


24


25


硬边际的原始形式

原始形式是 SVM 最原始的优化问题形式。它直接表达了在特征空间中寻找最大边际超平面的目标。


简单来说,原始形式旨在:

  1. 找到一个能正确分类所有数据点的超平面。
  2. 最大化这个超平面与每个类别中最近的数据点之间的距离。


原始形式为:

  • 最小化: (1/2) ||w||²
  • 条件是:对于所有 i,yᵢ(w - xᵢ + b) ≥ 1


其中

- w 是权重向量

- b 是偏差项

- xᵢ 是输入向量

- yᵢ 是相应的标签(+1 或 -1)。

- ||w||²是 w 的欧几里得平方准则


26


27


软边际的原始形式

还记得软边际 SVM 是原始(硬边际)SVM 的扩展,允许一定程度的误分类吗?这一变化反映在原始形式中。


软边际 SVM 的基本形式变为:

  • 最小化: (1/2) ||w||² + C Σᵢ ξᵢ
  • 对于所有 i,yᵢ(w - xᵢ + b) ≥ 1 - ξᵢ;对于所有 i,ξᵢ ≥ 0。


其中

- C 是惩罚参数

- ξᵢ是松弛变量

- 所有其他变量与硬边际情况相同


28


29


双重形式

坏消息是:原始形式的求解过程缓慢而困难,尤其是对于复杂数据。


对偶形式提供了另一种解决 SVM 优化问题的方法,通常具有计算优势。其公式如下:

最大化: Σᵢ,ⱼ(αᵢyᵢ) - ½ΣᵢΣⱼ(αᵢαⱼyᵢyⱼ(xᵢ - xⱼ))

服从 对于所有 i,0 ≤ αᵢ ≤ C,Σᵢαᵢyᵢ = 0。


其中

- αᵢ 是拉格朗日乘数(对偶变量)

- yᵢ 是类别标签(+1 或 -1)

- xᵢ 是输入向量

- C 是正则化参数(αᵢ 的上限)

- (xᵢ - xⱼ) 表示 xᵢ 与 xⱼ 之间的点积


30


拉格朗日乘数

正如我们在对偶形式中注意到的那样,当我们将原始问题转化为对偶形式时,拉格朗日乘数 (αᵢ) 就会出现(这也是它们被称为对偶系数的原因)。如果你注意到了,权重和偏差已不复存在!


训练集中的每个数据点都有一个相关的拉格朗日乘数。好在拉格朗日乘数让事情更容易理解:

1. 解释:

- αᵢ = 0:该点被正确分类,且不在边际范围内。该点不影响判定边界。

- 0 < αᵢ < C:该点位于边距边界上。这些点称为 “自由 ”或 “无边界 ”支持向量。

- αᵢ = C:点在边际上或边际内(包括误分类点)。这些支持向量被称为 “有界 ”支持向量。


2. 与决策边界的关系:

w = Σᵢ(αᵢ yᵢ xᵢ)、

b = yᵢ - Σⱼ(αᵢ yⱼ(xⱼ - xᵢ))

其中 yᵢ 是任何(无边界)支持向量的标签。

这意味着最终的决策边界只由 αᵢ 不为零的点决定!


31


顺序最小优化

还记得我们还没有真正展示如何获得最佳拉格朗日乘数 (αᵢ)吗?解决这个问题的算法叫做顺序最小优化(SMO)。下面是我们如何获得这些值的简化视图:

  1. 开始时,所有 αᵢ 都为零。
  2. 每次重复选择并调整两个 αᵢ,以改进解决方案。
  3. 使用简单的数学方法快速更新这两对αᵢ。
  4. 确保所有更新都遵循 SVM 约束。
  5. 重复操作,直到所有 αᵢ 都 “足够好”。
  6. αᵢ > 0 的点成为支持向量。


这种方法无需大量计算即可高效地解决 SVM 优化问题,因此适用于大型数据集。


32


决策函数

使用对偶形式求解 SVM 优化问题并得到拉格朗日乘数后,我们就可以定义决策函数了。该函数决定了训练有素的 SVM 模型如何对未见过的新数据点进行分类。


f(x) = Σᵢ(αᵢyᵢ(xᵢ - x)) + b


这里,αᵢ 是拉格朗日乘数,yᵢ 是类别标签(+1 或-1),xᵢ 是支持向量,x 是待分类的输入向量。新点 x 的最终分类取决于 f(x) 的符号(“+”或“-”)。


请注意,该判定函数只使用支持向量(αᵢ 不为零的数据点)来对新输入进行分类,这也是 SVM 算法的核心原理


33


 支持向量分类器代码

使用以下代码可以获得上述结果:


import numpy as np
import pandas as pd
from sklearn.svm import SVC
# Create DataFrame
df = pd.DataFrame({
    '?': [0, 1, 1, 2, 3, 3, 2, 3, 0, 0, 1, 2, 3],
    '?': [0, 0, 1, 0, 1, 2, 3, 3, 1, 2, 3, 2, 1],
    'y': [1, -1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1, 1]
}, index=range(1, 14))
# Split into train and test
train_df, test_df = df.iloc[:8].copy(), df.iloc[8:].copy()
X_train, y_train = train_df[['?', '?']], train_df['y']
X_test, y_test = test_df[['?', '?']], test_df['y']
# Create and fit SVC model
svc = SVC(kernel='linear', C=2)
svc.fit(X_train, y_train)
# Add Lagrange multipliers and support vector status
train_df['α'] = 0.0
train_df.loc[svc.support_ + 1, 'α'] = np.abs(svc.dual_coef_[0])
train_df['Is SV'] = train_df.index.isin(svc.support_ + 1)
print("Training Data, Lagrange Multipliers, and Support Vectors:")
print(train_df)
# Print model parameters
w, b = svc.coef_[0], svc.intercept_[0]
print(f"\nModel Parameters:")
print(f"Weights (w): [{w[0]}, {w[1]}]")
print(f"Bias (b): {b}")
print(f"Decision function: f(?,?) = ({w[0]})? + ({w[1]})? + ({b})")
# Make predictions
test_df['ŷ'] = svc.predict(X_test)
print("\nTest Data and Predictions:")
print(test_df)


34


第2部分:内核技巧

正如我们到目前为止所看到的,无论我们如何设置超平面,我们都无法将两个类别完美地分离开来。


输入空间与特征空间

输入空间指的是数据特征的原始空间。在我们的高尔夫数据集中,输入空间是二维的,由温度和湿度组成。该空间中的每个数据点都代表了某人决定是否打高尔夫的特定天气条件。


另一方面,特征空间是输入空间的转换版本,SVM 在其中实际执行分类。有时,在输入空间中无法线性分离的数据,在映射到更高维度的特征空间后就变得可以分离了。


35


内核和隐式转换

核是一种计算两个数据点之间相似性的函数,它隐含地将两个数据点表示在一个更高的维度空间(特征空间)中。


比方说,有一个函数 φ(x) 可以将每个输入点 x 转换到更高维度的空间。例如:φ : ℝ² → ℝ³, φ(x,y) = (x, y, x² + y²)


常见核及其隐含变换:

a. 线性内核: K(x,y) = x - y

- 变换:

φ(x) = x(同一性)

- 这实际上不会改变空间,但对线性可分离数据很有用。


b. 多项式核: K(x,y) = (x - y + c)ᵈ

- 变换(在ℝ² 中,d = 2,c = 1):

φ(x₁,x₂) = (1, √2x₁, √2x₂, x₁², √2x₁x₂, x₂²)

- 这就包含了 d 度以内的所有多项式项。


c. RBF 核: K(x,y) = exp(-γ||x - y||²)

- 变换(作为无穷级数):

φ(x₁,x₂)= exp(-γ||x||²) * (1, √(2γ)x₁, √(2γ)x₂, ..., √(2γ²/2!)x₁², √(2γ²/2!)x₁x₂, √(2γ²/2!)x₂², ..., √(2γⁿ/n!)x₁ⁿ, ...)

- 可以看作是一种随距离递减的相似度量。


36


内核技巧

核技巧的“技巧”部分在于,我们可以只使用核函数在更高维空间中进行操作,而不必显式计算转换 φ(x)。


注意,在对偶形式中,数据点仅以点积 (xᵢ · xⱼ) 的形式出现。这就是核技巧发挥作用的地方。我们可以将这个点积替换为核函数:(xᵢ · xⱼ) → K(xᵢ, xⱼ)


如果我们只使用原始形式,这个过程是无法完成的,这是为什么对偶形式更可取的主要原因之一!


这种替换隐式地将数据映射到一个更高维的空间,而无需显式计算转换。


37


使用核技巧的决策函数

对于一个新的点 x,得到的决策函数为:


f (x) = sign(Σᵢ αᵢyᵢK(xᵢ, x) + b)


其中求和是针对所有支持向量(即 αᵢ > 0 的点)进行的。


38


支持向量分类器(使用核技巧)代码摘要


以上结果可以通过以下代码获得:


import numpy as np
import pandas as pd
from sklearn.svm import SVC
# Create DataFrame
df = pd.DataFrame({
    '?': [0, 1, 1, 2, 3, 3, 2, 3, 0, 0, 1, 2, 3],
    '?': [0, 0, 1, 0, 1, 2, 3, 3, 1, 2, 3, 2, 1],
    'y': [1, -1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1, 1]
}, index=range(1, 14))
# Split into train and test
train_df, test_df = df.iloc[:8].copy(), df.iloc[8:].copy()
X_train, y_train = train_df[['?', '?']], train_df['y']
X_test, y_test = test_df[['?', '?']], test_df['y']
# Create and fit SVC model with polynomial kernel
svc = SVC(kernel='poly', degree=2, coef0=1, C=1)
svc.fit(X_train, y_train)
# Add Lagrange multipliers and support vector status
train_df['α'] = 0.0
train_df.loc[svc.support_ + 1, 'α'] = np.abs(svc.dual_coef_[0])
train_df['Is SV'] = train_df.index.isin(svc.support_ + 1)
print("Training Data, Lagrange Multipliers, and Support Vectors:")
print(train_df)
# Make predictions
test_df['ŷ'] = svc.predict(X_test)
print("\nTest Data and Predictions:")
print(test_df)


39


关键参数

在 SVM 中,关键参数是惩罚/正则化参数 C:

  • 大 C:尽力对所有训练点进行正确分类,可能会过度拟合
  • 小 C:允许更多错误分类,但旨在建立更简单、更通用的模型


当然,如果你使用的是非线性内核,你还需要调整与该内核相关的程度(和系数)。


结论

我们已经讨论了 SVM 中的许多关键概念(以及它们的工作原理),但主要思想是:一切都在于找到正确的平衡。你希望 SVM 能够学习数据中的重要模式,而不必过于努力地将每个训练数据放在超平面的正确一侧。如果它太严格,它可能会错过大局。如果它太灵活,它可能会看到实际上并不存在模式。诀窍是调整你的 SVM,以便它能够识别真实趋势,同时仍具有足够的适应性来处理新数据。找到正确的平衡,你就会拥有一个可以处理各种分类问题的强大工具。


文章来源:https://towardsdatascience.com/support-vector-classifier-explained-a-visual-guide-with-mini-2d-dataset-62e831e7b9e9
欢迎关注ATYUN官方公众号
商务合作及内容投稿请联系邮箱:bd@atyun.com
评论 登录
热门职位
Maluuba
20000~40000/月
Cisco
25000~30000/月 深圳市
PilotAILabs
30000~60000/年 深圳市
写评论取消
回复取消