Skip to content

第4章:支持向量机

导入必要的库

python
import numpy as np
import matplotlib.pyplot as plt
from sklearn import svm
from sklearn.datasets import make_blobs
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report, confusion_matrix
import seaborn as sns
import time

代码解释

  1. import numpy as np 这行代码导入了numpy库,别名为np。numpy是一个强大的数学计算库,就像是我们手中的计算器,帮助我们进行各种数值运算。

  2. import matplotlib.pyplot as plt matplotlib是一个用于绘制图表和数据可视化的库,pyplot是matplotlib的一个模块,通常用于绘制各种类型的图表。这就像是我们手中的画笔,帮助我们画出漂亮的图形。

  3. from sklearn import svm 从sklearn库中导入svm模块,svm是Support Vector Machine(支持向量机)的缩写。这是一个强大的分类算法,就像是一个聪明的分类器,能够找到最佳的分类边界。

  4. from sklearn.datasets import make_blobs 从sklearn库的datasets模块导入make_blobs函数,这个函数可以帮助我们生成用于分类的模拟数据。这就像是我们自己创造一些数据来测试我们的模型。

  5. from sklearn.preprocessing import StandardScaler 从sklearn库的preprocessing模块导入StandardScaler类,这个类用于数据的标准化处理。这就像是我们把不同尺度的数据统一到一个标准尺度,让模型更容易学习。

  6. from sklearn.model_selection import train_test_split 从sklearn库的model_selection模块导入train_test_split函数,用于将数据集划分为训练集和测试集。这样我们可以评估模型在未见过的数据上的表现。

  7. from sklearn.metrics import classification_report, confusion_matrix 从sklearn库的metrics模块导入classification_report和confusion_matrix函数,用于评估模型的性能。classification_report提供了精确率、召回率等指标,confusion_matrix则显示了预测结果的混淆矩阵。

  8. import seaborn as sns 导入seaborn库,这是一个基于matplotlib的高级可视化库,可以帮助我们创建更美观的统计图表,特别适合绘制混淆矩阵。

  9. import time 导入time模块,用于记录模型训练的时间,帮助我们了解模型的训练效率。

为什么需要数据标准化?

在机器学习中,数据标准化是一个重要的预处理步骤:

  1. 消除不同特征之间的量纲差异
  2. 使得所有特征都在相似的尺度上
  3. 加快模型的收敛速度
  4. 提高模型的数值稳定性

生成数据

python
def generate_data(n_samples=100, centers=2, random_state=42):
    """
    生成随机数据
    参数:
        n_samples: 样本数量
        centers: 类别数量
        random_state: 随机种子
    返回:
        X: 特征矩阵
        y: 标签数组
    """
    try:
        print(f"生成{centers}{n_samples}个样本的随机数据...")
        X, y = make_blobs(n_samples=n_samples, centers=centers, random_state=random_state)
        return X, y
    except Exception as e:
        print(f"生成数据时出错: {str(e)}")
        return None, None

代码解释

我们定义了一个generate_data函数来生成随机数据。这个函数有三个参数:

  • n_samples:要生成的样本数量,默认为100
  • centers:数据类别的数量,默认为2
  • random_state:随机种子,设置为42以确保每次运行代码时生成的数据都是一样的

函数使用try-except结构来处理可能出现的错误,这样可以让程序更加健壮。在函数内部,我们使用make_blobs函数生成随机数据,并返回特征矩阵X和标签数组y。如果出现错误,函数会打印错误信息并返回None。

数据标准化

python
def preprocess_data(X):
    """
    数据预处理:标准化
    参数:
        X: 特征矩阵
    返回:
        标准化后的特征矩阵
    """
    try:
        print("对数据进行标准化处理...")
        scaler = StandardScaler()
        X_scaled = scaler.fit_transform(X)
        return X_scaled
    except Exception as e:
        print(f"数据预处理时出错: {str(e)}")
        return None

代码解释

我们定义了一个preprocess_data函数来对数据进行标准化处理。这个函数接收特征矩阵X作为输入,返回标准化后的特征矩阵。

函数内部使用StandardScaler类来进行标准化处理:

  1. 创建StandardScaler对象
  2. 使用fit_transform方法计算数据的均值和标准差,并将数据转换为标准正态分布(均值为0,标准差为1)

同样,我们使用了try-except结构来处理可能出现的错误,使程序更加健壮。如果出现错误,函数会打印错误信息并返回None。

训练和评估模型

python
def train_and_evaluate_model(X, y, kernel='linear'):
    """
    训练和评估SVM模型
    参数:
        X: 特征矩阵
        y: 标签数组
        kernel: 核函数类型
    返回:
        model: 训练好的模型
        metrics: 评估指标
    """
    try:
        # 划分训练集和测试集
        X_train, X_test, y_train, y_test = train_test_split(
            X, y, test_size=0.2, random_state=42
        )
        
        # 训练模型
        print(f"\n开始训练SVM模型 (kernel={kernel})...")
        start_time = time.time()
        
        model = svm.SVC(kernel=kernel)
        model.fit(X_train, y_train)
        
        training_time = time.time() - start_time
        print(f"模型训练完成,用时: {training_time:.2f}秒")
        
        # 评估模型
        train_score = model.score(X_train, y_train)
        test_score = model.score(X_test, y_test)
        
        # 预测
        y_pred = model.predict(X_test)
        
        # 计算评估指标
        metrics = {
            'train_score': train_score,
            'test_score': test_score,
            'training_time': training_time,
            'classification_report': classification_report(y_test, y_pred),
            'confusion_matrix': confusion_matrix(y_test, y_pred)
        }
        
        return model, metrics, X_test, y_test
    except Exception as e:
        print(f"训练模型时出错: {str(e)}")
        return None, None, None, None

代码解释

我们定义了一个train_and_evaluate_model函数来训练和评估SVM模型。这个函数有三个参数:

  • X:特征矩阵
  • y:标签数组
  • kernel:核函数类型,默认为'linear'(线性核函数)

函数的主要步骤包括:

  1. 使用train_test_split函数将数据集划分为训练集(80%)和测试集(20%)
  2. 创建并训练SVM模型,同时记录训练时间
  3. 评估模型性能,包括:
    • 计算训练集和测试集的准确率
    • 使用模型进行预测
    • 生成分类报告(包含精确率、召回率等指标)
    • 计算混淆矩阵

同样使用了try-except结构来处理可能出现的错误。

支持向量

SVM 通过找到一个最优的超平面来实现分类:

  1. 最大化分类边界(margin)
  2. 只关注支持向量(最靠近分类边界的点)
  3. 可以通过核技巧处理非线性可分的数据

这就像是在选择两类点之间画一条线,使得:

  • 线两边的点尽可能分开
  • 线到最近的点的距离尽可能大

可视化结果

python
def plot_decision_boundary(model, X, y):
    """
    绘制决策边界
    参数:
        model: 训练好的SVM模型
        X: 特征矩阵
        y: 标签数组
    """
    try:
        print("\n绘制决策边界...")
        # 创建网格点
        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.arange(x_min, x_max, 0.02),
                            np.arange(y_min, y_max, 0.02))
        
        # 预测网格点的类别
        Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
        Z = Z.reshape(xx.shape)
        
        # 绘制结果
        plt.figure(figsize=(10, 8))
        plt.contourf(xx, yy, Z, alpha=0.4, cmap='coolwarm')
        plt.scatter(X[:, 0], X[:, 1], c=y, alpha=0.8, cmap='coolwarm')
        plt.title('SVM分类结果')
        plt.xlabel('特征1')
        plt.ylabel('特征2')
        plt.colorbar(label='类别')
        plt.show()
    except Exception as e:
        print(f"绘制决策边界时出错: {str(e)}")

def plot_confusion_matrix(cm):
    """
    绘制混淆矩阵
    参数:
        cm: 混淆矩阵
    """
    try:
        plt.figure(figsize=(8, 6))
        sns.heatmap(cm, annot=True, fmt='d', cmap='Blues')
        plt.title('混淆矩阵')
        plt.xlabel('预测标签')
        plt.ylabel('真实标签')
        plt.show()
    except Exception as e:
        print(f"绘制混淆矩阵时出错: {str(e)}")

代码解释

我们定义了两个可视化函数:

  1. plot_decision_boundary函数用于绘制决策边界:

    • 首先计算数据的范围,并稍微扩大以显示完整的分类边界
    • 使用np.meshgrid创建一个网格,网格点将用于绘制分类边界
    • 使用训练好的模型预测网格中每个点的类别
    • 使用plt.contourf绘制分类边界,使用plt.scatter绘制数据点
    • 添加标题、坐标轴标签和颜色条
  2. plot_confusion_matrix函数用于绘制混淆矩阵:

    • 使用seaborn库的heatmap函数绘制混淆矩阵
    • 设置合适的图形大小和颜色方案
    • 添加标题和坐标轴标签

两个函数都使用了try-except结构来处理可能出现的错误。

主函数

python
def main():
    # 生成数据
    X, y = generate_data(n_samples=200, centers=2)
    if X is None or y is None:
        return
    
    # 数据预处理
    X_scaled = preprocess_data(X)
    if X_scaled is None:
        return
    
    # 训练和评估模型
    model, metrics, X_test, y_test = train_and_evaluate_model(X_scaled, y)
    if model is None or metrics is None:
        return
    
    # 打印评估结果
    print("\n模型评估结果:")
    print(f"训练集准确率: {metrics['train_score']:.4f}")
    print(f"测试集准确率: {metrics['test_score']:.4f}")
    print(f"训练用时: {metrics['training_time']:.2f}秒")
    print("\n分类报告:")
    print(metrics['classification_report'])
    
    # 绘制混淆矩阵
    plot_confusion_matrix(metrics['confusion_matrix'])
    
    # 绘制决策边界
    plot_decision_boundary(model, X_scaled, y)

if __name__ == "__main__":
    main()

代码解释

主函数main()按照以下步骤执行:

  1. 生成200个样本的随机数据,分为2类
  2. 对数据进行标准化处理
  3. 训练SVM模型并进行评估
  4. 打印模型的评估结果,包括:
    • 训练集和测试集的准确率
    • 模型训练时间
    • 详细的分类报告
  5. 可视化结果:
    • 绘制混淆矩阵
    • 绘制决策边界

每个步骤都有错误检查,如果前面的步骤出错,程序会提前退出。

总结

支持向量机(SVM)是一个强大的分类算法,它通过找到一个最优的超平面来分隔不同类别的数据。在这个例子中,我们实现了一个完整的SVM分类器,包括:

  1. 数据准备:生成随机数据并进行标准化
  2. 模型训练:使用线性核函数训练SVM模型
  3. 模型评估:计算准确率、生成分类报告和混淆矩阵
  4. 结果可视化:绘制决策边界和混淆矩阵

SVM的一个重要特点是它只关注支持向量(即最靠近分类边界的点),这使得它对噪声数据具有较强的鲁棒性。在实际应用中,我们还可以使用其他核函数(如RBF核)来处理更复杂的非线性分类问题。

代码中使用了异常处理和函数模块化的设计,使得程序更加健壮和易于维护。同时,通过详细的评估指标和可视化结果,我们可以更好地理解模型的性能。

用心打造的机器学习教程