机器学习课程笔记(Machine Learning)

支持向量机(Support Vector Machine, SVM)

Posted by 月月鸟 on December 18, 2021

本文介绍支持向量机(SVM)算法在机器学习中的基本原理、特点、注意事项,以及实现 SVM 模型的完整步骤。

1. 支持向量机的基本原理

支持向量机(SVM)是一种用于分类和回归分析的监督学习模型。它通过在特征空间中找到一个最优超平面,将不同类别的样本分开。

1.1 最大间隔分类

SVM 的目标是找到一个可以最大化类别间距的超平面。对于线性可分的数据,SVM 试图找到最远离数据点的决策边界:

\[\text{Maximize } \frac{2}{\|\mathbf{w}\|}\]

其中,(\mathbf{w}) 是决策边界的法向量。

1.1.1 线性可分

对于线性可分的样本,SVM 寻找能够最大化间隔的线性超平面,将数据分为两类。

  • 决策函数
\[f(\mathbf{x}) = \mathbf{w} \cdot \mathbf{x} + b\]
  • 决策边界:满足 ( f(\mathbf{x}) = 0 ) 的超平面。

1.2 非线性可分与核技巧

当数据线性不可分时,SVM 使用核技巧将数据映射到高维空间,以实现线性可分。常用的核函数有:

  • 线性核
\[K(\mathbf{x}, \mathbf{y}) = \mathbf{x} \cdot \mathbf{y}\]
  • 多项式核
\[K(\mathbf{x}, \mathbf{y}) = (\mathbf{x} \cdot \mathbf{y} + c)^d\]
  • 高斯核(RBF 核)
\[K(\mathbf{x}, \mathbf{y}) = \exp\left(-\frac{\|\mathbf{x} - \mathbf{y}\|^2}{2\sigma^2}\right)\]
  • Sigmoid 核
\[K(\mathbf{x}, \mathbf{y}) = \tanh(\alpha \mathbf{x} \cdot \mathbf{y} + c)\]

1.3 支持向量

在 SVM 中,支持向量是离决策边界最近的样本点。只有支持向量对构建超平面起作用。

1.4 软间隔与正则化

当数据存在噪声或重叠时,SVM 引入软间隔,通过加入松弛变量 (\xi_i) 允许部分样本位于间隔之内:

\[\min \frac{1}{2}\|\mathbf{w}\|^2 + C \sum_{i=1}^{n} \xi_i\]

其中 ( C ) 是正则化参数,用于平衡间隔最大化和误分类惩罚。

2. 实现步骤

我们使用 iris 数据集来进行一个简单的实现。iris 数据集常用于分类问题,包含四个特征和三种类别的鸢尾花。

2.1 数据准备

加载数据集,分割训练集和测试集,并对特征进行标准化。

import numpy as np
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report

# 加载iris数据集
data = load_iris()
X = data.data  # 特征数据
y = data.target  # 目标标签

# 将数据集分为训练集和测试集,80%用于训练,20%用于测试
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

scaler = StandardScaler()  # 标准化特征数据
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)

2.2 模型训练

实现支持向量机算法。

class SimpleSVM:
    def __init__(self, learning_rate=0.001, lambda_param=0.01, n_iters=1000):
        self.lr = learning_rate
        self.lambda_param = lambda_param
        self.n_iters = n_iters
        self.w = None
        self.b = None

    def fit(self, X, y):
        n_samples, n_features = X.shape

        # 初始化权重和偏置
        self.w = np.zeros(n_features)
        self.b = 0

        # 将类标签转换为-1和1
        y_ = np.where(y <= 0, -1, 1)

        # 梯度下降
        for _ in range(self.n_iters):
            for idx, x_i in enumerate(X):
                condition = y_[idx] * (np.dot(x_i, self.w) - self.b) >= 1
                if condition:
                    self.w -= self.lr * (2 * self.lambda_param * self.w)
                else:
                    self.w -= self.lr * (2 * self.lambda_param * self.w - np.dot(x_i, y_[idx]))
                    self.b -= self.lr * y_[idx]

    def predict(self, X):
        approx = np.dot(X, self.w) - self.b
        return np.sign(approx)

2.3 模型预测

对测试集进行预测。

# 创建SVM模型
svm = SimpleSVM()

# 训练模型
svm.fit(X_train, y_train)

# 预测测试集
y_pred = svm.predict(X_test)

2.4 模型评估

使用测试数据集评估模型性能。

accuracy = accuracy_score(y_test, y_pred)
conf_matrix = confusion_matrix(y_test, y_pred)
class_report = classification_report(y_test, y_pred)

print("\nAccuracy:", accuracy)
print("Confusion Matrix:\n", conf_matrix)
print("Classification Report:\n", class_report)

3. 优缺点

3.1 优点

  1. 有效性:在高维空间中表现良好。
  2. 支持非线性分类:通过核技巧可以处理非线性问题。
  3. 鲁棒性:对数据噪声和异常值不敏感。

3.2 缺点

  1. 计算复杂度高:在大规模数据集上训练时间较长。
  2. 参数选择复杂:选择合适的核函数和参数需要经验。
  3. 不适合大规模数据集:SVM 在处理大规模数据时计算开销大。

SVM 在小规模数据集和复杂分类问题上表现出色,通过选择合适的核函数和参数调整,可以有效处理线性和非线性问题。