SVM的代码实现

  1. 生成假数据集:创建一个简单的二分类数据集。
  2. 数据标准化:标准化特征。
  3. 定义线性核函数:选择一个简单的线性核。
  4. 定义优化问题:使用对偶问题进行求解。
  5. 求解对偶问题:通过简单的梯度上升法求解对偶问题。
  6. 确定支持向量:找到支持向量。
  7. 计算权重和偏置:计算超平面的参数。
  8. 进行预测:使用训练好的模型对新数据点进行预测。

1. 生成假数据集

我们创建一个简单的二分类数据集:

import numpy as np

# 生成假数据点
X = np.array([[2, 3], [3, 3], [4, 2], [1, 1], [2, 2], [2, 1]])
y = np.array([1, 1, 1, -1, -1, -1])  # 类别标签

2. 数据标准化

将数据标准化,使每个特征具有零均值和单位方差:

X_mean = np.mean(X, axis=0)
X_std = np.std(X, axis=0)
X = (X - X_mean) / X_std

3. 定义线性核函数

我们选择线性核函数:

def linear_kernel(x1, x2):
    return np.dot(x1, x2)

4. 定义优化问题

SVM 的对偶问题可以表示为:

max ⁡ α ∑ i = 1 n α i − 1 2 ∑ i = 1 n ∑ j = 1 n α i α j y i y j K ( x i , x j ) \max_{\alpha} \sum_{i=1}^{n} \alpha_i - \frac{1}{2} \sum_{i=1}^{n} \sum_{j=1}^{n} \alpha_i \alpha_j y_i y_j K(x_i, x_j) αmaxi=1nαi21i=1nj=1nαiαjyiyjK(xi,xj)

5. 求解对偶问题

通过简单的梯度上升法求解对偶问题:

def train_svm(X, y, C=1.0, max_iter=100, learning_rate=0.01):
    n_samples, n_features = X.shape
    alpha = np.zeros(n_samples)
    for _ in range(max_iter):
        for i in range(n_samples):
            gradient = 1 - y[i] * np.sum(alpha * y * np.array([linear_kernel(X[i], X[j]) for j in range(n_samples)]))
            alpha[i] += learning_rate * gradient
            alpha[i] = max(0, min(alpha[i], C))
    return alpha

alpha = train_svm(X, y)

下面我们逐行解释 train_svm 函数的代码:

def train_svm(X, y, C=1.0, max_iter=100, learning_rate=0.01):
  • 函数定义train_svm 是一个用于训练支持向量机的函数。
  • 参数说明
    • X:输入数据集,形状为 (n_samples, n_features),表示 n 个样本和每个样本的特征向量。
    • y:标签数组,长度为 n_samples,取值为 1 或 -1,表示每个样本的类别。
    • C:正则化参数,默认值为 1.0,控制对误分类的惩罚程度。
    • max_iter:最大迭代次数,默认值为 100,表示算法将运行的最大迭代次数。
    • learning_rate:学习率,默认值为 0.01,控制每次更新的步长。
    n_samples, n_features = X.shape
    alpha = np.zeros(n_samples)
  • 数据维度n_samplesn_features 分别表示样本数和特征数。
  • 初始化alpha 是拉格朗日乘子,初始化为零数组,长度为样本数。
    for _ in range(max_iter):
  • 迭代循环:主循环,控制最大迭代次数。
        for i in range(n_samples):
  • 样本循环:遍历每个样本。
            gradient = 1 - y[i] * np.sum(alpha * y * np.array([linear_kernel(X[i], X[j]) for j in range(n_samples)]))
  • 计算梯度
    • 线性核函数:计算所有样本与第 i i i 个样本的线性核(即点积)。
    • 梯度计算gradient 是对偶问题的梯度,计算公式为 1 − y i ∑ j = 1 n α j y j K ( x i , x j ) 1 - y_i \sum_{j=1}^{n} \alpha_j y_j K(x_i, x_j) 1yij=1nαjyjK(xi,xj)
    • linear_kernel(X[i], X[j]) 计算第 i i i 个样本和第 j j j 个样本的点积。
            alpha[i] += learning_rate * gradient
  • 更新拉格朗日乘子:按照梯度上升法更新 alpha
            alpha[i] = max(0, min(alpha[i], C))
  • 约束拉格朗日乘子:将 alpha[i] 限制在 0 到 C 之间,确保满足对偶问题的约束条件。
    return alpha
  • 返回结果:迭代结束后,返回更新后的 alpha 数组。

逐行解释总结

train_svm 函数实现了一个简化的支持向量机训练过程。主要步骤如下:

  1. 初始化 alpha 为零。
  2. 在最大迭代次数内,遍历所有样本,计算梯度并更新 alpha
  3. 每次更新 alpha 后,确保其在合法范围内(0 到 C)。
  4. 最终返回更新后的 alpha 值。

通过这种方法,我们得到了拉格朗日乘子 alpha,可以进一步用于计算权重向量和偏置,进而构建 SVM 模型进行分类预测。

6. 确定支持向量

支持向量是那些 α i > 0 \alpha_i > 0 αi>0的数据点:

support_vectors_idx = np.where(alpha > 1e-5)[0]
support_vectors = X[support_vectors_idx]
support_vector_labels = y[support_vectors_idx]

7. 计算权重和偏置

权重向量 w \mathbf{w} w 和偏置 b b b 的计算:

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

数学公式
w = ∑ i = 1 n α i y i x i w = \sum_{i=1}^{n} \alpha_i y_i x_i w=i=1nαiyixi

# 计算偏置 b
b = np.mean([y[i] - np.dot(w, X[i]) for i in support_vectors_idx])

数学公式
b = 1 ∣ S ∣ ∑ i ∈ S ( y i − w ⋅ x i ) b = \frac{1}{|S|} \sum_{i \in S} \left( y_i - w \cdot x_i \right) b=S1iS(yiwxi)

通过代码和公式的结合,可以更清晰地理解 SVM 模型的训练过程。

8. 进行预测

定义预测函数:

def predict(X):
    return np.sign(np.dot(X, w) + b)

# 进行预测
new_points = np.array([[3, 2], [1, 3]])
new_points = (new_points - X_mean) / X_std
predictions = predict(new_points)

下面我们逐行解释如何使用高斯核(RBF核)来修改预测函数。首先我们回顾一下高斯核的公式:

K ( x i , x j ) = exp ⁡ ( − ∥ x i − x j ∥ 2 2 σ 2 ) K(x_i, x_j) = \exp\left(-\frac{\|x_i - x_j\|^2}{2\sigma^2}\right) K(xi,xj)=exp(2σ2xixj2)

这里的 σ \sigma σ是高斯核的参数,决定了核函数的宽度。

代码解释

import numpy as np

def gaussian_kernel(x, y, sigma=1.0):
    return np.exp(-np.linalg.norm(x - y) ** 2 / (2 * sigma ** 2))
  1. 定义高斯核函数gaussian_kernel(x, y, sigma=1.0) 计算两个向量 xy 之间的高斯核值。np.linalg.norm(x - y) ** 2 计算向量 xy 之间的欧几里得距离平方,然后除以 2 σ 2 2\sigma^2 2σ2并取负数,再用 np.exp 计算指数函数,得到核值。
def predict(X, support_vectors, support_vector_labels, alphas, b, sigma=1.0):
    y_pred = np.zeros(X.shape[0])
    for i in range(X.shape[0]):
        kernel_sum = 0
        for alpha, sv_y, sv in zip(alphas, support_vector_labels, support_vectors):
            kernel_sum += alpha * sv_y * gaussian_kernel(X[i], sv, sigma)
        y_pred[i] = kernel_sum
    return np.sign(y_pred + b)
  1. 定义预测函数predict 函数接受新的数据点 X,支持向量 support_vectors,支持向量的标签 support_vector_labels,拉格朗日乘子 alphas,偏置 b,以及高斯核参数 sigma

  2. 初始化预测结果y_pred = np.zeros(X.shape[0]) 创建一个与 X 的样本数量相同的零向量,用于存储预测结果。

  3. 遍历每个新数据点for i in range(X.shape[0]) 逐个遍历每个新样本 X[i]

  4. 计算每个样本的核函数和kernel_sum = 0 初始化当前样本的核函数和。接下来,通过 for alpha, sv_y, sv in zip(alphas, support_vector_labels, support_vectors) 遍历每个支持向量的拉格朗日乘子 alpha,标签 sv_y,以及支持向量 sv,计算 alpha * sv_y * gaussian_kernel(X[i], sv, sigma) 并累加到 kernel_sum 中。

  5. 存储预测值y_pred[i] = kernel_sum 将当前样本的核函数和赋值给 y_pred[i]

  6. 返回最终预测结果return np.sign(y_pred + b)y_pred 加上偏置 b 后取符号,得到最终的预测结果。

假设我们已经训练好了一个使用高斯核的 SVM 模型,得到了支持向量、支持向量标签、拉格朗日乘子和偏置。使用上述 predict 函数,我们可以对新的数据点进行分类预测。

这样,我们通过逐行解释了如何修改预测函数以使用高斯核来处理非线性分类问题。

小结

以上代码展示了如何手动实现一个简单的线性支持向量机(SVM)模型。我们生成了一些假数据,进行了数据标准化,定义了线性核函数,通过梯度上升法求解对偶问题,确定支持向量,计算了模型参数,并进行了预测。

这个例子只是一个简化的版本,实际应用中,SVM 的训练过程涉及更多的细节和优化算法,如序列最小优化(SMO)等。通过这一例子,你可以理解 SVM 的基本原理和求解过程。

  • 18
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值