### 实现线性可分支持向量机
### 硬间隔最大化策略
class Hard_Margin_SVM:
### 线性可分支持向量机拟合方法
def fit(self, X, y):
# 训练样本数和特征数
m, n = X.shape
# 初始化二次规划相关变量:P/q/G/h
self.P = matrix(np.identity(n + 1, dtype=np.float))
self.q = matrix(np.zeros((n + 1,), dtype=np.float))
self.G = matrix(np.zeros((m, n + 1), dtype=np.float))
self.h = -matrix(np.ones((m,), dtype=np.float))
# 将数据转为变量
self.P[0, 0] = 0
for i in range(m):
self.G[i, 0] = -y[i]
self.G[i, 1:] = -X[i, :] * y[i]
# 构建二次规划求解
sol = solvers.qp(self.P, self.q, self.G, self.h)
# 对权重和偏置寻优
self.w = np.zeros(n,)
self.b = sol['x'][0]
for i in range(1, n + 1):
self.w[i - 1] = sol['x'][i]
return self.w, self.b
### 定义模型预测函数
def predict(self, X):
return np.sign(np.dot(self.w, X.T) + self.b)
通过一个具体的示例来展示硬间隔支持向量机的代码是如何运行的,并为每个变量提供具体的数据样例。
示例数据和解释
假设我们有如下的二维数据集,其中每个样本有两个特征(即二维坐标),并且样本属于两个类别 y ∈ { − 1 , 1 } y \in \{-1, 1\} y∈{−1,1}。我们将使用硬间隔支持向量机来找到一个最大化分类间隔的超平面。
示例数据
特征矩阵 X X X(每一行是一个样本的坐标):
X = np.array([
[1, 2],
[2, 3],
[3, 3],
[2, 1],
[3, 2]
])
标签向量 y y y(每个样本的类别标签):
y = np.array([1, 1, 1, -1, -1])
这个数据集包含 5 个样本,分别对应两个类别(1 和 -1)。前 3 个样本属于类别 + 1 +1 +1,后两个样本属于类别 − 1 -1 −1。
代码中的每个变量解释
让我们一步步来分析代码中的每个变量。
(1) 训练样本数和特征数
m, n = X.shape
X.shape
返回
m
m
m 和
n
n
n,分别表示样本数量和特征数量:
- m = 5 m = 5 m=5 表示有 5 个样本。
- n = 2 n = 2 n=2 表示每个样本有 2 个特征(二维数据)。
(2) 初始化二次规划相关矩阵
self.P = matrix(np.identity(n + 1, dtype=np.float))
self.q = matrix(np.zeros((n + 1,), dtype=np.float))
self.G = matrix(np.zeros((m, n + 1), dtype=np.float))
self.h = -matrix(np.ones((m,), dtype=np.float))
我们将定义二次规划问题的参数矩阵:
-
self.P
:用于构建目标函数的二次项 1 2 w T P w \frac{1}{2} w^T P w 21wTPw,在支持向量机中,目标是最小化 1 2 ∥ w ∥ 2 \frac{1}{2} \|w\|^2 21∥w∥2,因此 P P P 是一个 ( n + 1 ) × ( n + 1 ) (n+1) \times (n+1) (n+1)×(n+1) 的单位矩阵(表示 w 1 , w 2 w_1, w_2 w1,w2 和 b b b)。self.P = np.identity(3) # 2 个特征 + 1 个偏置 # 输出 [[1. 0. 0.] [0. 1. 0.] [0. 0. 0.]]
-
self.q
:表示线性项 q q q,其值为 0,因为硬间隔 SVM 中我们只需要最小化 1 2 ∥ w ∥ 2 \frac{1}{2} \|w\|^2 21∥w∥2,不需要其他线性项。self.q = np.zeros(3) # 输出 [0. 0. 0.]
-
self.G
和self.h
:这些是约束条件,用于确保每个样本都正确分类并满足硬间隔条件 y i ( w T x i + b ) ≥ 1 y_i(w^T x_i + b) \geq 1 yi(wTxi+b)≥1。self.G = np.zeros((5, 3)) # 5 个样本,每个样本对应 (w1, w2, b) self.h = -np.ones(5) # 对应每个样本的约束 # 输出 G 和 h G = [[0. 0. 0.] [0. 0. 0.] [0. 0. 0.] [0. 0. 0.] [0. 0. 0.]] h = [-1. -1. -1. -1. -1.]
(3) 构建约束矩阵 G G G 和 h h h
接下来,我们要根据数据构建约束条件:
self.P[0, 0] = 0 # 偏置 b 不需要惩罚
for i in range(m):
self.G[i, 0] = -y[i] # 对偏置项的影响
self.G[i, 1:] = -X[i, :] * y[i] # 对 w 的影响
每一行 G [ i ] G[i] G[i] 对应样本 X [ i ] X[i] X[i] 的约束 y i ( w T x i + b ) ≥ 1 y_i(w^T x_i + b) \geq 1 yi(wTxi+b)≥1:
样本 X X X | 标签 y y y | 约束条件 |
---|---|---|
(1, 2) | 1 | w 1 ⋅ 1 + w 2 ⋅ 2 + b ≥ 1 w_1 \cdot 1 + w_2 \cdot 2 + b \geq 1 w1⋅1+w2⋅2+b≥1 |
(2, 3) | 1 | w 1 ⋅ 2 + w 2 ⋅ 3 + b ≥ 1 w_1 \cdot 2 + w_2 \cdot 3 + b \geq 1 w1⋅2+w2⋅3+b≥1 |
(3, 3) | 1 | w 1 ⋅ 3 + w 2 ⋅ 3 + b ≥ 1 w_1 \cdot 3 + w_2 \cdot 3 + b \geq 1 w1⋅3+w2⋅3+b≥1 |
(2, 1) | -1 | − w 1 ⋅ 2 − w 2 ⋅ 1 − b ≥ 1 -w_1 \cdot 2 - w_2 \cdot 1 - b \geq 1 −w1⋅2−w2⋅1−b≥1 |
(3, 2) | -1 | − w 1 ⋅ 3 − w 2 ⋅ 2 − b ≥ 1 -w_1 \cdot 3 - w_2 \cdot 2 - b \geq 1 −w1⋅3−w2⋅2−b≥1 |
更新后的 G G G 矩阵和 h h