一、支持向量机的介绍

支持向量机(Support Vector Machine, SVM)是一种经典的监督学习模型,核心用于分类任务,也可通过改造用于回归(支持向量回归,SVR)。它的核心思想是:在特征空间中找到一个最优超平面,将不同类别的样本分开,且使两类样本到超平面的间隔最大化。
SVM 在小样本、高维特征场景下表现优异,是机器学习领域的基础算法之一,常被用于文本分类、图像识别、模式匹配等任务。

其应用场景:

图像识别:如手写数字识别、目标检测,利用高斯核处理高维像素特征。
文本分类:如垃圾邮件识别、情感分析,将文本转化为词向量后用线性核或 RBF 核分类。
故障诊断:基于设备传感器的高维特征,区分设备正常 / 故障状态。

二、实验

数据准备

ex6data1.mat:线性可分数据集,用于演示硬间隔与软间隔SVM

ex6data2.mat:非线性可分数据集,用于演示RBF核SVM

实验一:线性SVM分析

1.标准化

标准化是SVM中至关重要的预处理步骤,因为SVM对特征尺度敏感。标准化后,所有特征都转换为均值为0、方差为1的分布,这有助于提高模型的收敛速度和性能。

# 加载数据
mat_data = loadmat(mat_path)
X = mat_data['X']
y = mat_data['y'].ravel()

# 数据标准化
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

2硬间隔与软间隔SVM对比

2.1硬间隔SVM(C=1e10)

当惩罚系数C极大时,我们得到硬间隔SVM:

原理:不允许任何训练样本被误分类;特点:决策边界完全由支持向量决定,对噪声敏感

适用场景:数据完全线性可分且无噪声

2.2软间隔SVM(C=1.0)

原理:允许少量样本被误分,以换取更好的泛化能力;特点:通过松弛变量平衡准确率和模型复杂度

适用场景:大多数实际应用场景

3.实验结果

结论:

硬间隔SVM虽然训练集准确率达到100%,但支持向量数量高达527个,模型复杂度高

软间隔SVM在测试集上表现更佳,泛化能力更好

C值选择需要平衡分类准确率和模型复杂度

实验二:非线性SVM与核方法

1.当数据线性不可分时,我们需要引入核方法。RBF(径向基函数)核是最常用的核函数之一:

# RBF核SVM
svm_rbf = SVC(kernel='rbf', gamma=0.1, C=1.0)
svm_rbf.fit(X_scaled, y)

2.Gamma参数的影响分析

核心规律:

1.小gamma值 (γ→0)

决策边界更平滑;模型复杂度低;支持向量数量多;可能欠拟合

2.中等gamma值 (γ≈1)

平衡复杂度和泛化能力;在训练集和测试集上表现均衡;支持向量数量适中

3.大gamma值 (γ→∞)

决策边界高度复杂;可能过拟合;支持向量数量少;对噪声敏感
3.线性核与RBF核对比

# 线性核SVM
svm_linear = SVC(kernel='linear', C=1.0)
svm_linear.fit(X_scaled, y)

# RBF核SVM
svm_rbf = SVC(kernel='rbf', gamma=1.0, C=1.0)
svm_rbf.fit(X_scaled, y)

性能对比

4.核函数选择建议

线性核:特征数量大、样本数量少时,或数据近似线性可分

RBF核:大多数非线性问题,是默认选择

多项式核:需要显式控制多项式次数时

Sigmoid核:某些特定的神经网络场景

三、完整代码

实验一

import numpy as np
import matplotlib.pyplot as plt
from scipy.io import loadmat
from sklearn.svm import SVC
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import accuracy_score, classification_report
from sklearn.model_selection import train_test_split

# 解决中文显示和负号问题
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False


class MATSVM_Analyzer:
    """MAT数据集SVM分析器"""

    def __init__(self, mat_path, random_state=42):
        """
        初始化分析器
        Parameters:
        - mat_path: MATLAB数据文件路径
        - random_state: 随机种子
        """
        self.mat_path = mat_path
        self.random_state = random_state
        self.models = {}
        self.results = {}
        self.load_data()

    def load_data(self):
        """加载MATLAB数据集"""
        try:
            mat_data = loadmat(self.mat_path)
            # 查找数据集中的变量名
            print("=" * 60)
            print("MAT文件中的变量:")
            for key in mat_data.keys():
                if not key.startswith('__'):
                    shape = mat_data[key].shape if hasattr(mat_data[key], 'shape') else 'scalar'
                    print(f"  {key}: {shape}")
            print("=" * 60)

            # 尝试常见的变量名
            X_keys = ['X', 'data', 'features']
            y_keys = ['y', 'labels', 'class']

            X = None
            y = None

            for key in X_keys:
                if key in mat_data and len(mat_data[key].shape) >= 2:
                    X = mat_data[key]
                    print(f"找到特征矩阵: {key}, 形状: {X.shape}")
                    break

            for key in y_keys:
                if key in mat_data:
                    y_temp = mat_data[key]
                    # 确保y是1D数组
                    if len(y_temp.shape) > 1:
                        y_temp = y_temp.ravel()
                    # 检查是否有多个类别
                    unique_classes = np.unique(y_temp)
                    if len(unique_classes) == 2:
                        y = y_temp
                        print(f"找到标签向量: {key}, 类别: {unique_classes.tolist()}")
                        break
                    elif len(unique_classes) > 2:
                        print(f"警告: {key}有{len(unique_classes)}个类别,这是多分类问题")
                        y = y_temp

            if X is None or y is None:
                raise ValueError("未找到合适的特征矩阵或标签向量")

            # 确保数据格式正确
            if len(X.shape) > 2:
                X = X.reshape(X.shape[0], -1)
                print(f"重塑特征矩阵形状为: {X.shape}")

            self.X_raw = X
            self.y_raw = y

            # 划分训练集和测试集
            self.X_train_raw, self.X_test_raw, self.y_train, self.y_test = train_test_split(
                X, y, test_size=0.3, random_state=self.random_state, stratify=y
            )

            # 数据标准化
            self.scaler = StandardScaler()
            self.X_train_scaled = self.scaler.fit_transform(self.X_train_raw)
            self.X_test_scaled = self.scaler.transform(self.X_test_raw)

            print(f"数据集信息:")
            print(f"  原始特征形状: {X.shape}")
            print(f"  训练集大小: {self.X_train_scaled.shape[0]}")
            print(f"  测试集大小: {self.X_test_scaled.shape[0]}")
            print(f"  类别分布: {np.unique(y, return_counts=True)}")

        except Exception as e:
            print(f"加载数据时出错: {e}")
            raise

    def train_comparison_models(self):
        """训练用于对比的SVM模型"""
        # 基础模型配置
        base_models = {
            '硬间隔SVM (C=1e10)': {'C': 1e10, 'kernel': 'linear'},
            '软间隔SVM (C=0.01)': {'C': 0.01, 'kernel': 'linear'},
            '软间隔SVM (C=0.1)': {'C': 0.1, 'kernel': 'linear'},
            '软间隔SVM (C=1.0)': {'C': 1.0, 'kernel': 'linear'},
            '软间隔SVM (C=10)': {'C': 10, 'kernel': 'linear'},
            'RBF核SVM (γ=0.1)': {'C': 1.0, 'kernel': 'rbf', 'gamma': 0.1},
            'RBF核SVM (γ=1.0)': {'C': 1.0, 'kernel': 'rbf', 'gamma': 1.0},
            'RBF核SVM (γ=10)': {'C': 1.0, 'kernel': 'rbf', 'gamma': 10},
        }

        print("\n" + "=" * 60)
        print("开始训练SVM模型...")
        print("=" * 60)

        for name, params in base_models.items():
            try:
                svm = SVC(**params, random_state=self.random_state)
                svm.fit(self.X_train_scaled, self.y_train)
                self.models[name] = svm
                print(f"✓ 训练完成: {name}")
            except Exception as e:
                print(f"✗ 训练失败 {name}: {e}")

        print(f"总共训练了 {len(self.models)} 个模型")

    def evaluate_all_models(self):
        """评估所有训练的模型"""
        print("\n" + "=" * 70)
        print("SVM模型性能评估")
        print("=" * 70)

        for name, model in self.models.items():
            # 训练集预测
            y_train_pred = model.predict(self.X_train_scaled)
            train_acc = accuracy_score(self.y_train, y_train_pred)

            # 测试集预测
            y_test_pred = model.predict(self.X_test_scaled)
            test_acc = accuracy_score(self.y_test, y_test_pred)

            # 支持向量数量
            n_support = len(model.support_vectors_) if hasattr(model, 'support_vectors_') else 0

            # 存储结果
            self.results[name] = {
                'train_accuracy': train_acc,
                'test_accuracy': test_acc,
                'n_support_vectors': n_support,
                'parameters': model.get_params(),
                'model': model
            }

            # 打印结果
            kernel = model.kernel
            C = model.C
            gamma = model.gamma if hasattr(model, 'gamma') else 'N/A'

            print(f"\n📊 模型: {name}")
            print(f"   核函数: {kernel} | C={C}" + (f" | γ={gamma}" if gamma != 'N/A' else ""))
            print(f"   训练集准确率: {train_acc:.4f}")
            print(f"   测试集准确率: {test_acc:.4f}")
            print(f"   支持向量数量: {n_support}")

            # 如果是线性核,显示权重向量
            if kernel == 'linear':
                if hasattr(model, 'coef_'):
                    weights = model.coef_[0]
                    print(f"   权重向量范数: {np.linalg.norm(weights):.4f}")

        print("=" * 70)

    def plot_decision_boundary_2d(self, model, X, y, title, ax):
        """
        绘制二维特征的决策边界(仅适用于2维特征)
        Parameters:
        - model: 训练好的SVM模型
        - X: 特征矩阵(2维)
        - y: 标签向量
        - title: 图表标题
        - ax: matplotlib坐标轴
        """
        if X.shape[1] != 2:
            ax.text(0.5, 0.5, f"特征维度为{X.shape[1]}\n无法可视化",
                    ha='center', va='center', transform=ax.transAxes)
            ax.set_title(title)
            return

        # 创建网格
        h = 0.02
        x_min, x_max = X[:, 0].min() - 0.5, X[:, 0].max() + 0.5
        y_min, y_max = X[:, 1].min() - 0.5, X[:, 1].max() + 0.5
        xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
                             np.arange(y_min, y_max, h))

        # 预测网格点
        Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
        Z = Z.reshape(xx.shape)

        # 绘制决策区域
        ax.contourf(xx, yy, Z, alpha=0.3, cmap=plt.cm.coolwarm)
        ax.contour(xx, yy, Z, colors='k', linestyles=['-'], linewidths=1, levels=[0])

        # 绘制数据点
        scatter = ax.scatter(X[:, 0], X[:, 1], c=y,
                             cmap=plt.cm.coolwarm, edgecolors='k', s=40, alpha=0.8)

        # 标记支持向量
        if hasattr(model, 'support_vectors_'):
            sv = model.support_vectors_
            ax.scatter(sv[:, 0], sv[:, 1],
                       facecolors='none', edgecolors='yellow',
                       s=150, linewidths=2, label='支持向量', alpha=0.8)

        # 标记误分类点
        y_pred = model.predict(X)
        misclassified = np.where(y_pred != y)[0]
        if len(misclassified) > 0:
            ax.scatter(X[misclassified, 0], X[misclassified, 1],
                       facecolors='none', edgecolors='red',
                       s=200, linewidths=2, label='误分类点', alpha=0.8)

        ax.set_xlabel('特征 1 (标准化)', fontsize=10)
        ax.set_ylabel('特征 2 (标准化)', fontsize=10)
        ax.set_title(title, fontsize=11, fontweight='bold')
        ax.legend(loc='best', fontsize=8)
        ax.grid(True, alpha=0.3)

    def visualize_model_comparison(self):
        """可视化多个模型的决策边界(仅当特征为2维时)"""
        if self.X_train_scaled.shape[1] != 2:
            print("特征维度不是2维,无法绘制决策边界图")
            return

        # 选择几个关键模型进行可视化
        key_models = ['硬间隔SVM (C=1e10)', '软间隔SVM (C=0.1)',
                      '软间隔SVM (C=1.0)', 'RBF核SVM (γ=1.0)']

        # 过滤出存在的模型
        available_models = [name for name in key_models if name in self.models]

        if not available_models:
            print("没有可用的模型进行可视化")
            return

        fig, axes = plt.subplots(2, 2, figsize=(14, 10))
        axes = axes.flatten()

        for idx, model_name in enumerate(available_models):
            if idx >= len(axes):
                break

            ax = axes[idx]
            model = self.models[model_name]
            result = self.results[model_name]

            title = f'{model_name}\n测试准确率: {result["test_accuracy"]:.3f}\n支持向量: {result["n_support_vectors"]}'

            # 使用测试集进行可视化
            self.plot_decision_boundary_2d(
                model,
                self.X_test_scaled,
                self.y_test,
                title,
                ax
            )

        plt.suptitle('SVM模型决策边界对比 (测试集)', fontsize=14, fontweight='bold')
        plt.tight_layout()
        plt.show()

    def analyze_c_parameter_effect(self, c_values=None):
        """
        分析C参数对线性SVM性能的影响
        Parameters:
        - c_values: C值列表,如果为None则使用默认值
        """
        if c_values is None:
            c_values = [0.001, 0.01, 0.1, 0.5, 1, 5, 10, 50, 100, 1000]

        train_accuracies = []
        test_accuracies = []
        n_support_vectors = []
        margin_sizes = []

        print("\n" + "=" * 70)
        print("C参数对线性SVM性能的影响分析")
        print("=" * 70)

        for C in c_values:
            try:
                # 训练线性SVM
                svm = SVC(C=C, kernel='linear', random_state=self.random_state)
                svm.fit(self.X_train_scaled, self.y_train)

                # 计算准确率
                train_acc = svm.score(self.X_train_scaled, self.y_train)
                test_acc = svm.score(self.X_test_scaled, self.y_test)

                # 支持向量数量
                n_sv = len(svm.support_vectors_)

                # 计算间隔大小(对于线性SVM)
                margin = 2.0 / np.sqrt(np.sum(svm.coef_ ** 2)) if hasattr(svm, 'coef_') else 0

                train_accuracies.append(train_acc)
                test_accuracies.append(test_acc)
                n_support_vectors.append(n_sv)
                margin_sizes.append(margin)

                print(f"C={C:7.3f} | 训练集准确率: {train_acc:.4f} | "
                      f"测试集准确率: {test_acc:.4f} | 支持向量: {n_sv:3d} | "
                      f"间隔: {margin:.4f}")
            except Exception as e:
                print(f"C={C:7.3f} | 训练失败: {e}")
                continue

        # 绘制C值影响图
        fig, axes = plt.subplots(2, 2, figsize=(14, 10))

        # 准确率随C值变化
        axes[0, 0].plot(c_values[:len(train_accuracies)], train_accuracies, 'o-',
                        label='训练集准确率', linewidth=2, markersize=6)
        axes[0, 0].plot(c_values[:len(test_accuracies)], test_accuracies, 's-',
                        label='测试集准确率', linewidth=2, markersize=6)
        axes[0, 0].set_xscale('log')
        axes[0, 0].set_xlabel('惩罚系数C (对数尺度)', fontsize=10)
        axes[0, 0].set_ylabel('准确率', fontsize=10)
        axes[0, 0].set_title('C值对准确率的影响', fontsize=12, fontweight='bold')
        axes[0, 0].legend(fontsize=9)
        axes[0, 0].grid(True, alpha=0.3)

        # 支持向量数量随C值变化
        axes[0, 1].plot(c_values[:len(n_support_vectors)], n_support_vectors, 'o-',
                        color='green', linewidth=2, markersize=6)
        axes[0, 1].set_xscale('log')
        axes[0, 1].set_xlabel('惩罚系数C (对数尺度)', fontsize=10)
        axes[0, 1].set_ylabel('支持向量数量', fontsize=10)
        axes[0, 1].set_title('C值对支持向量的影响', fontsize=12, fontweight='bold')
        axes[0, 1].grid(True, alpha=0.3)

        # 间隔大小随C值变化
        axes[1, 0].plot(c_values[:len(margin_sizes)], margin_sizes, 'o-',
                        color='purple', linewidth=2, markersize=6)
        axes[1, 0].set_xscale('log')
        axes[1, 0].set_xlabel('惩罚系数C (对数尺度)', fontsize=10)
        axes[1, 0].set_ylabel('间隔大小', fontsize=10)
        axes[1, 0].set_title('C值对间隔大小的影响', fontsize=12, fontweight='bold')
        axes[1, 0].grid(True, alpha=0.3)

        # 过拟合程度分析
        if len(train_accuracies) == len(test_accuracies):
            overfitting_gap = [train - test for train, test in zip(train_accuracies, test_accuracies)]
            axes[1, 1].plot(c_values[:len(overfitting_gap)], overfitting_gap, 'o-',
                            color='red', linewidth=2, markersize=6)
            axes[1, 1].set_xscale('log')
            axes[1, 1].set_xlabel('惩罚系数C (对数尺度)', fontsize=10)
            axes[1, 1].set_ylabel('过拟合程度 (训练-测试)', fontsize=10)
            axes[1, 1].set_title('C值对过拟合的影响', fontsize=12, fontweight='bold')
            axes[1, 1].grid(True, alpha=0.3)
            axes[1, 1].axhline(y=0, color='k', linestyle='--', alpha=0.5)

        plt.suptitle('线性SVM中C参数的影响分析', fontsize=14, fontweight='bold')
        plt.tight_layout()
        plt.show()

    def analyze_gamma_parameter_effect(self, gamma_values=None):
        """
        分析gamma参数对RBF核SVM性能的影响
        Parameters:
        - gamma_values: gamma值列表,如果为None则使用默认值
        """
        if gamma_values is None:
            gamma_values = [0.001, 0.01, 0.1, 0.5, 1, 5, 10, 50, 100]

        train_accuracies = []
        test_accuracies = []
        n_support_vectors = []

        print("\n" + "=" * 70)
        print("Gamma参数对RBF核SVM性能的影响分析")
        print("=" * 70)

        for gamma in gamma_values:
            try:
                # 训练RBF核SVM
                svm = SVC(C=1.0, kernel='rbf', gamma=gamma, random_state=self.random_state)
                svm.fit(self.X_train_scaled, self.y_train)

                # 计算准确率
                train_acc = svm.score(self.X_train_scaled, self.y_train)
                test_acc = svm.score(self.X_test_scaled, self.y_test)

                # 支持向量数量
                n_sv = len(svm.support_vectors_)

                train_accuracies.append(train_acc)
                test_accuracies.append(test_acc)
                n_support_vectors.append(n_sv)

                print(f"γ={gamma:7.3f} | 训练集准确率: {train_acc:.4f} | "
                      f"测试集准确率: {test_acc:.4f} | 支持向量: {n_sv:3d}")
            except Exception as e:
                print(f"γ={gamma:7.3f} | 训练失败: {e}")
                continue

        # 绘制gamma值影响图
        fig, axes = plt.subplots(1, 2, figsize=(14, 5))

        # 准确率随gamma值变化
        axes[0].plot(gamma_values[:len(train_accuracies)], train_accuracies, 'o-',
                     label='训练集准确率', linewidth=2, markersize=6)
        axes[0].plot(gamma_values[:len(test_accuracies)], test_accuracies, 's-',
                     label='测试集准确率', linewidth=2, markersize=6)
        axes[0].set_xscale('log')
        axes[0].set_xlabel('Gamma参数γ (对数尺度)', fontsize=10)
        axes[0].set_ylabel('准确率', fontsize=10)
        axes[0].set_title('Gamma值对准确率的影响', fontsize=12, fontweight='bold')
        axes[0].legend(fontsize=9)
        axes[0].grid(True, alpha=0.3)

        # 支持向量数量随gamma值变化
        axes[1].plot(gamma_values[:len(n_support_vectors)], n_support_vectors, 'o-',
                     color='green', linewidth=2, markersize=6)
        axes[1].set_xscale('log')
        axes[1].set_xlabel('Gamma参数γ (对数尺度)', fontsize=10)
        axes[1].set_ylabel('支持向量数量', fontsize=10)
        axes[1].set_title('Gamma值对支持向量的影响', fontsize=12, fontweight='bold')
        axes[1].grid(True, alpha=0.3)

        plt.suptitle('RBF核SVM中Gamma参数的影响分析', fontsize=14, fontweight='bold')
        plt.tight_layout()
        plt.show()

    def create_summary_report(self):
        """创建综合分析报告"""
        print("\n" + "=" * 80)
        print("SVM实验综合分析报告")
        print("=" * 80)

        # 找到最佳模型
        best_model_name = None
        best_test_acc = 0

        for name, result in self.results.items():
            if result['test_accuracy'] > best_test_acc:
                best_test_acc = result['test_accuracy']
                best_model_name = name

        print(f"\n🏆 最佳模型: {best_model_name}")
        print(f"   测试集准确率: {best_test_acc:.4f}")

        # 线性模型和RBF模型对比
        linear_models = {name: result for name, result in self.results.items()
                         if 'linear' in name.lower()}
        rbf_models = {name: result for name, result in self.results.items()
                      if 'rbf' in name.lower()}

        if linear_models:
            avg_linear_acc = np.mean([r['test_accuracy'] for r in linear_models.values()])
            print(f"\n📈 线性核SVM平均测试准确率: {avg_linear_acc:.4f}")

        if rbf_models:
            avg_rbf_acc = np.mean([r['test_accuracy'] for r in rbf_models.values()])
            print(f"📈 RBF核SVM平均测试准确率: {avg_rbf_acc:.4f}")

        # 支持向量分析
        total_sv = sum([r['n_support_vectors'] for r in self.results.values()])
        avg_sv = total_sv / len(self.results) if self.results else 0
        print(f"\n🔍 支持向量分析:")
        print(f"   平均支持向量数量: {avg_sv:.1f}")
        print(f"   支持向量占训练集比例: {avg_sv / len(self.y_train):.2%}")

        # 数据特征
        print(f"\n📊 数据特征:")
        print(f"   特征维度: {self.X_train_scaled.shape[1]}")
        print(f"   训练集大小: {len(self.y_train)}")
        print(f"   测试集大小: {len(self.y_test)}")

        print("\n" + "=" * 80)


def main():
    """主函数:执行完整的SVM分析流程"""
    # 设置MAT文件路径
    mat_path = r"C:\Users\98189\PycharmProjects\机器学习\支持向量机\ex6data1.mat"

    try:
        print("🚀 开始MAT数据集SVM分析")
        print("=" * 70)

        # 1. 创建分析器并加载数据
        analyzer = MATSVM_Analyzer(mat_path, random_state=42)

        # 2. 训练多个SVM模型进行对比
        analyzer.train_comparison_models()

        # 3. 评估所有模型
        analyzer.evaluate_all_models()

        # 4. 可视化模型对比(仅当特征为2维时)
        analyzer.visualize_model_comparison()

        # 5. 分析C参数影响
        analyzer.analyze_c_parameter_effect()

        # 6. 分析Gamma参数影响
        analyzer.analyze_gamma_parameter_effect()

        # 7. 创建综合分析报告
        analyzer.create_summary_report()

        print("\n✅ SVM分析完成!")
        print("=" * 70)

    except FileNotFoundError:
        print(f"❌ 找不到文件: {mat_path}")
        print("请检查文件路径是否正确")
    except Exception as e:
        print(f"❌ 程序执行出错: {e}")
        import traceback
        traceback.print_exc()


if __name__ == "__main__":
    main()

实验二

import numpy as np
import matplotlib.pyplot as plt
from scipy.io import loadmat
from sklearn.svm import SVC
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import accuracy_score, classification_report
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.inspection import DecisionBoundaryDisplay

# 解决中文显示和负号问题
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False


class RBF_SVM_Analyzer:
    """RBF核SVM分析器:专注于MAT数据集和高斯核SVM分析"""

    def __init__(self, mat_path, random_state=42):
        """
        初始化RBF核SVM分析器

        Parameters:
        - mat_path: MATLAB数据文件路径
        - random_state: 随机种子
        """
        self.mat_path = mat_path
        self.random_state = random_state
        self.models = {}
        self.results = {}
        self.scaler = StandardScaler()
        self.load_and_prepare_data()

    def load_and_prepare_data(self):
        """加载MATLAB数据并进行预处理"""
        try:
            # 加载MAT文件
            mat_data = loadmat(self.mat_path)

            print("=" * 60)
            print("数据集信息")
            print("=" * 60)

            # 查找特征和标签
            X = None
            y = None

            # 尝试不同的变量名
            for key in ['X', 'data', 'features']:
                if key in mat_data:
                    X = mat_data[key]
                    print(f"特征矩阵: {key}, 形状: {X.shape}")
                    break

            for key in ['y', 'labels', 'Y']:
                if key in mat_data:
                    y_data = mat_data[key]
                    # 确保y是1D数组
                    if len(y_data.shape) > 1:
                        y = y_data.ravel()
                    else:
                        y = y_data

                    unique_classes = np.unique(y)
                    print(f"标签向量: {key}, 类别: {unique_classes.tolist()}")
                    print(f"类别分布: {dict(zip(*np.unique(y, return_counts=True)))}")
                    break

            if X is None or y is None:
                raise ValueError("无法找到特征矩阵或标签向量")

            # 确保特征矩阵是2D
            if len(X.shape) > 2:
                X = X.reshape(X.shape[0], -1)
                print(f"重塑特征矩阵形状为: {X.shape}")

            # 检查是否是二分类问题
            if len(np.unique(y)) > 2:
                print("⚠️ 警告: 这是一个多分类问题,SVM将使用一对一策略")

            # 划分训练集和测试集
            X_train, X_test, y_train, y_test = train_test_split(
                X, y, test_size=0.3, random_state=self.random_state, stratify=y
            )

            print(f"训练集大小: {X_train.shape[0]}")
            print(f"测试集大小: {X_test.shape[0]}")

            # 数据标准化
            self.X_train_raw = X_train
            self.X_test_raw = X_test
            self.y_train = y_train
            self.y_test = y_test

            self.X_train_scaled = self.scaler.fit_transform(X_train)
            self.X_test_scaled = self.scaler.transform(X_test)

            # 用于可视化的数据
            self.X_scaled_all = self.scaler.transform(X)
            self.y_all = y

            print("数据预处理完成")
            print("=" * 60)

        except Exception as e:
            print(f"数据加载失败: {e}")
            raise

    def train_rbf_models(self, gamma_values=None, C=1.0):
        """
        训练多个RBF核SVM模型

        Parameters:
        - gamma_values: gamma值列表
        - C: 惩罚系数,默认1.0
        """
        if gamma_values is None:
            gamma_values = [0.01, 0.1, 0.5, 1.0, 2.0, 5.0, 10.0, 20.0]

        print("\n" + "=" * 60)
        print("训练RBF核SVM模型")
        print("=" * 60)

        self.gamma_values = gamma_values

        for gamma in gamma_values:
            try:
                model_name = f"RBF_γ={gamma}_C={C}"
                print(f"正在训练: {model_name}...")

                svm = SVC(kernel='rbf', gamma=gamma, C=C,
                          random_state=self.random_state)
                svm.fit(self.X_train_scaled, self.y_train)

                # 评估模型
                train_acc = svm.score(self.X_train_scaled, self.y_train)
                test_acc = svm.score(self.X_test_scaled, self.y_test)

                self.models[model_name] = {
                    'model': svm,
                    'gamma': gamma,
                    'C': C,
                    'train_accuracy': train_acc,
                    'test_accuracy': test_acc,
                    'n_support_vectors': len(svm.support_vectors_)
                }

                print(f"✓ {model_name}: 训练集={train_acc:.4f}, 测试集={test_acc:.4f}, "
                      f"支持向量={len(svm.support_vectors_)}")

            except Exception as e:
                print(f"✗ 训练失败 gamma={gamma}: {e}")

        print(f"总共训练了 {len(self.models)} 个RBF核SVM模型")

    def train_comparison_models(self, C_values=None):
        """
        训练用于对比的线性核SVM模型

        Parameters:
        - C_values: C值列表
        """
        if C_values is None:
            C_values = [0.01, 0.1, 1.0, 10.0, 100.0]

        print("\n" + "=" * 60)
        print("训练线性核SVM模型用于对比")
        print("=" * 60)

        for C in C_values:
            try:
                model_name = f"Linear_C={C}"
                print(f"正在训练: {model_name}...")

                svm = SVC(kernel='linear', C=C, random_state=self.random_state)
                svm.fit(self.X_train_scaled, self.y_train)

                # 评估模型
                train_acc = svm.score(self.X_train_scaled, self.y_train)
                test_acc = svm.score(self.X_test_scaled, self.y_test)

                self.models[model_name] = {
                    'model': svm,
                    'gamma': 'linear',
                    'C': C,
                    'train_accuracy': train_acc,
                    'test_accuracy': test_acc,
                    'n_support_vectors': len(svm.support_vectors_)
                }

                print(f"✓ {model_name}: 训练集={train_acc:.4f}, 测试集={test_acc:.4f}, "
                      f"支持向量={len(svm.support_vectors_)}")

            except Exception as e:
                print(f"✗ 训练失败 C={C}: {e}")

    def plot_rbf_decision_boundary(self, model_info, title, ax, h=0.02):
        """
        绘制RBF核SVM的决策边界

        Parameters:
        - model_info: 模型信息字典
        - title: 图表标题
        - ax: matplotlib坐标轴
        - h: 网格步长
        """
        model = model_info['model']

        # 检查特征维度
        if self.X_train_scaled.shape[1] != 2:
            ax.text(0.5, 0.5, "特征维度不为2\n无法可视化决策边界",
                    ha='center', va='center', transform=ax.transAxes, fontsize=10)
            ax.set_title(title)
            return

        try:
            # 生成网格
            x_min, x_max = self.X_scaled_all[:, 0].min() - 0.5, self.X_scaled_all[:, 0].max() + 0.5
            y_min, y_max = self.X_scaled_all[:, 1].min() - 0.5, self.X_scaled_all[:, 1].max() + 0.5
            xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
                                 np.arange(y_min, y_max, h))

            # 预测网格点
            Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
            Z = Z.reshape(xx.shape)

            # 绘制决策区域
            ax.contourf(xx, yy, Z, alpha=0.3, cmap=plt.cm.coolwarm)
            ax.contour(xx, yy, Z, colors='k', linestyles=['-'], linewidths=1, levels=[0])

            # 绘制训练数据点
            ax.scatter(self.X_scaled_all[:, 0], self.X_scaled_all[:, 1],
                       c=self.y_all, cmap=plt.cm.coolwarm,
                       edgecolors='k', s=30, alpha=0.8)

            # 标记支持向量
            sv = model.support_vectors_
            ax.scatter(sv[:, 0], sv[:, 1],
                       facecolors='none', edgecolors='yellow',
                       s=100, linewidths=1.5, label='支持向量')

            # 计算并显示准确率
            train_acc = model_info['train_accuracy']
            test_acc = model_info['test_accuracy']
            n_sv = model_info['n_support_vectors']

            info_text = f"训练集准确率: {train_acc:.3f}\n测试集准确率: {test_acc:.3f}\n支持向量: {n_sv}"
            ax.text(0.02, 0.98, info_text, transform=ax.transAxes,
                    fontsize=8, verticalalignment='top',
                    bbox=dict(boxstyle='round', facecolor='white', alpha=0.8))

            ax.set_xlabel('特征 1 (标准化)', fontsize=9)
            ax.set_ylabel('特征 2 (标准化)', fontsize=9)
            ax.set_title(title, fontsize=11, fontweight='bold')
            ax.legend(loc='best', fontsize=8)
            ax.grid(True, alpha=0.3)

        except Exception as e:
            ax.text(0.5, 0.5, f"绘图错误: {str(e)[:50]}",
                    ha='center', va='center', transform=ax.transAxes, fontsize=9)
            ax.set_title(title)

    def visualize_gamma_comparison(self):
        """可视化不同gamma值的RBF核SVM对比"""
        # 获取所有RBF核模型
        rbf_models = {k: v for k, v in self.models.items() if 'RBF' in k}

        if not rbf_models:
            print("没有找到RBF核SVM模型")
            return

        # 按gamma值排序
        sorted_models = sorted(rbf_models.items(),
                               key=lambda x: x[1]['gamma'])

        # 创建子图
        n_models = len(sorted_models)
        n_cols = min(3, n_models)
        n_rows = (n_models + n_cols - 1) // n_cols

        fig, axes = plt.subplots(n_rows, n_cols,
                                 figsize=(4 * n_cols, 3.5 * n_rows))

        # 如果只有一个子图,axes不是数组
        if n_rows == 1 and n_cols == 1:
            axes = np.array([axes])

        # 将axes转换为一维数组
        axes = axes.flatten() if hasattr(axes, 'flatten') else np.array([axes])

        for idx, (name, model_info) in enumerate(sorted_models):
            if idx >= len(axes):
                break

            ax = axes[idx] if idx < len(axes) else None
            if ax is None:
                continue

            gamma = model_info['gamma']
            C = model_info['C']

            title = f'RBF核SVM\nγ={gamma}, C={C}'
            self.plot_rbf_decision_boundary(model_info, title, ax)

        # 隐藏多余的子图
        for idx in range(len(sorted_models), len(axes)):
            axes[idx].axis('off')

        plt.suptitle('RBF核SVM: Gamma参数对比', fontsize=14, fontweight='bold')
        plt.tight_layout()
        plt.show()

    def visualize_kernel_comparison(self):
        """可视化线性核与RBF核的对比"""
        # 获取线性核和RBF核模型
        linear_models = {k: v for k, v in self.models.items() if 'Linear' in k}
        rbf_models = {k: v for k, v in self.models.items() if 'RBF' in k}

        if not linear_models or not rbf_models:
            print("需要同时有线性核和RBF核模型进行对比")
            return

        # 找到最佳线性模型和最佳RBF模型
        best_linear = max(linear_models.items(),
                          key=lambda x: x[1]['test_accuracy'])
        best_rbf = max(rbf_models.items(),
                       key=lambda x: x[1]['test_accuracy'])

        # 创建对比图
        fig, axes = plt.subplots(1, 2, figsize=(12, 5))

        # 确保axes是数组
        axes = axes.flatten() if hasattr(axes, 'flatten') else axes

        titles = ['线性核SVM (最佳C值)', 'RBF核SVM (最佳γ值)']
        models_to_plot = [best_linear, best_rbf]

        for idx, ((name, model_info), ax) in enumerate(zip(models_to_plot, axes)):
            if ax is None:
                continue

            kernel_type = "Linear" if "Linear" in name else "RBF"

            if kernel_type == "Linear":
                title = f'{titles[idx]}\nC={model_info["C"]}, 测试集准确率={model_info["test_accuracy"]:.3f}'
            else:
                title = f'{titles[idx]}\nγ={model_info["gamma"]}, C={model_info["C"]}, 测试集准确率={model_info["test_accuracy"]:.3f}'

            self.plot_rbf_decision_boundary(model_info, title, ax)

        plt.suptitle('线性核 vs RBF核SVM对比', fontsize=14, fontweight='bold')
        plt.tight_layout()
        plt.show()

        # 打印对比结果
        print("\n" + "=" * 60)
        print("线性核 vs RBF核SVM性能对比")
        print("=" * 60)
        print(f"最佳线性核: {best_linear[0]}")
        print(f"  训练集准确率: {best_linear[1]['train_accuracy']:.4f}")
        print(f"  测试集准确率: {best_linear[1]['test_accuracy']:.4f}")
        print(f"  支持向量数量: {best_linear[1]['n_support_vectors']}")
        print(f"\n最佳RBF核: {best_rbf[0]}")
        print(f"  训练集准确率: {best_rbf[1]['train_accuracy']:.4f}")
        print(f"  测试集准确率: {best_rbf[1]['test_accuracy']:.4f}")
        print(f"  支持向量数量: {best_rbf[1]['n_support_vectors']}")
        print("=" * 60)

    def analyze_gamma_effect(self):
        """分析gamma参数对RBF核SVM性能的影响"""
        # 获取所有RBF核模型
        rbf_models = {k: v for k, v in self.models.items() if 'RBF' in k}

        if len(rbf_models) < 2:
            print("需要至少2个不同gamma值的RBF核模型进行分析")
            return

        # 提取数据
        gammas = []
        train_accs = []
        test_accs = []
        n_svs = []

        for name, info in rbf_models.items():
            gammas.append(info['gamma'])
            train_accs.append(info['train_accuracy'])
            test_accs.append(info['test_accuracy'])
            n_svs.append(info['n_support_vectors'])

        # 按gamma值排序
        sorted_indices = np.argsort(gammas)
        gammas = np.array(gammas)[sorted_indices]
        train_accs = np.array(train_accs)[sorted_indices]
        test_accs = np.array(test_accs)[sorted_indices]
        n_svs = np.array(n_svs)[sorted_indices]

        # 创建分析图表
        fig, axes = plt.subplots(2, 2, figsize=(12, 10))

        # 1. 准确率随gamma变化
        axes[0, 0].semilogx(gammas, train_accs, 'o-', label='训练集准确率',
                            linewidth=2, markersize=8)
        axes[0, 0].semilogx(gammas, test_accs, 's-', label='测试集准确率',
                            linewidth=2, markersize=8)
        axes[0, 0].set_xlabel('Gamma参数 (γ)', fontsize=10)
        axes[0, 0].set_ylabel('准确率', fontsize=10)
        axes[0, 0].set_title('Gamma对准确率的影响', fontsize=12, fontweight='bold')
        axes[0, 0].legend(fontsize=9)
        axes[0, 0].grid(True, alpha=0.3)

        # 2. 过拟合程度随gamma变化
        overfitting_gap = train_accs - test_accs
        axes[0, 1].semilogx(gammas, overfitting_gap, 'o-', color='red',
                            linewidth=2, markersize=8)
        axes[0, 1].set_xlabel('Gamma参数 (γ)', fontsize=10)
        axes[0, 1].set_ylabel('过拟合程度 (训练-测试)', fontsize=10)
        axes[0, 1].set_title('Gamma对过拟合的影响', fontsize=12, fontweight='bold')
        axes[0, 1].axhline(y=0, color='k', linestyle='--', alpha=0.5)
        axes[0, 1].grid(True, alpha=0.3)

        # 3. 支持向量数量随gamma变化
        axes[1, 0].semilogx(gammas, n_svs, 'o-', color='green',
                            linewidth=2, markersize=8)
        axes[1, 0].set_xlabel('Gamma参数 (γ)', fontsize=10)
        axes[1, 0].set_ylabel('支持向量数量', fontsize=10)
        axes[1, 0].set_title('Gamma对支持向量的影响', fontsize=12, fontweight='bold')
        axes[1, 0].grid(True, alpha=0.3)

        # 4. 支持向量比例随gamma变化
        sv_ratio = n_svs / len(self.y_train)
        axes[1, 1].semilogx(gammas, sv_ratio, 'o-', color='purple',
                            linewidth=2, markersize=8)
        axes[1, 1].set_xlabel('Gamma参数 (γ)', fontsize=10)
        axes[1, 1].set_ylabel('支持向量比例', fontsize=10)
        axes[1, 1].set_title('Gamma对支持向量比例的影响', fontsize=12, fontweight='bold')
        axes[1, 1].grid(True, alpha=0.3)

        plt.suptitle('RBF核SVM: Gamma参数影响分析', fontsize=14, fontweight='bold')
        plt.tight_layout()
        plt.show()

        # 打印分析结果
        print("\n" + "=" * 60)
        print("Gamma参数影响分析总结")
        print("=" * 60)
        print("小gamma值 (γ→0):")
        print("  - 决策边界更平滑,近似线性")
        print("  - 模型复杂度低,可能欠拟合")
        print("  - 支持向量数量多,泛化能力强")
        print("\n大gamma值 (γ→∞):")
        print("  - 决策边界更复杂,可能过拟合")
        print("  - 模型复杂度高,对训练集拟合好")
        print("  - 支持向量数量少,可能泛化能力差")
        print("\n建议:")
        print("  1. 使用交叉验证选择最佳gamma值")
        print("  2. 通常从 [0.1, 1, 10] 开始尝试")
        print("  3. 观察训练集和测试集准确率差距")
        print("=" * 60)

    def plot_3d_decision_boundary(self, model_info):
        """
        绘制3D决策边界(仅适用于2维特征)

        Parameters:
        - model_info: 模型信息字典
        """
        if self.X_train_scaled.shape[1] != 2:
            print("3D可视化仅适用于2维特征")
            return

        model = model_info['model']

        # 创建网格
        h = 0.05
        x_min, x_max = self.X_scaled_all[:, 0].min() - 0.5, self.X_scaled_all[:, 0].max() + 0.5
        y_min, y_max = self.X_scaled_all[:, 1].min() - 0.5, self.X_scaled_all[:, 1].max() + 0.5
        xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
                             np.arange(y_min, y_max, h))

        # 计算决策函数值
        Z = model.decision_function(np.c_[xx.ravel(), yy.ravel()])
        Z = Z.reshape(xx.shape)

        # 创建3D图形
        fig = plt.figure(figsize=(12, 8))
        ax = fig.add_subplot(111, projection='3d')

        # 绘制决策曲面
        surf = ax.plot_surface(xx, yy, Z, cmap=plt.cm.coolwarm,
                               alpha=0.6, linewidth=0, antialiased=True)

        # 绘制数据点
        ax.scatter(self.X_scaled_all[:, 0], self.X_scaled_all[:, 1],
                   np.zeros_like(self.y_all),  # 在z=0平面上绘制点
                   c=self.y_all, cmap=plt.cm.coolwarm,
                   s=50, edgecolors='k', depthshade=True)

        # 标记支持向量
        sv = model.support_vectors_
        sv_scores = model.decision_function(sv)
        ax.scatter(sv[:, 0], sv[:, 1], sv_scores,
                   facecolors='none', edgecolors='yellow',
                   s=150, linewidth=2, label='支持向量')

        # 设置标签
        ax.set_xlabel('特征 1', fontsize=10)
        ax.set_ylabel('特征 2', fontsize=10)
        ax.set_zlabel('决策函数值', fontsize=10)

        gamma = model_info['gamma']
        train_acc = model_info['train_accuracy']
        test_acc = model_info['test_accuracy']
        title = f'RBF核SVM 3D决策边界 (γ={gamma})\n训练集准确率={train_acc:.3f}, 测试集准确率={test_acc:.3f}'
        ax.set_title(title, fontsize=12, fontweight='bold')

        ax.legend(loc='best')
        plt.colorbar(surf, ax=ax, shrink=0.5, aspect=5)
        plt.show()

    def run_full_analysis(self):
        """运行完整的RBF核SVM分析"""
        print("🚀 开始RBF核SVM分析")
        print("=" * 60)

        # 1. 训练多个gamma值的RBF核SVM
        gamma_values = [0.1, 1.0, 10.0, 100.0]  # 与原始代码保持一致
        self.train_rbf_models(gamma_values=gamma_values, C=1.0)

        # 2. 训练对比的线性核SVM
        self.train_comparison_models(C_values=[0.01, 0.1, 1.0, 10.0])

        # 3. 可视化不同gamma值的RBF核SVM
        self.visualize_gamma_comparison()

        # 4. 可视化线性核与RBF核对比
        self.visualize_kernel_comparison()

        # 5. 分析gamma参数影响
        self.analyze_gamma_effect()

        # 6. 可选:绘制3D决策边界(用于最佳RBF模型)
        rbf_models = {k: v for k, v in self.models.items() if 'RBF' in k}
        if rbf_models and self.X_train_scaled.shape[1] == 2:
            best_rbf = max(rbf_models.items(),
                           key=lambda x: x[1]['test_accuracy'])
            print(f"\n绘制最佳RBF模型的3D决策边界: {best_rbf[0]}")
            self.plot_3d_decision_boundary(best_rbf[1])

        print("\n✅ RBF核SVM分析完成!")
        print("=" * 60)


def main():
    """主函数:执行RBF核SVM分析"""
    # 设置MAT文件路径
    mat_path = r"C:\Users\98189\PycharmProjects\机器学习\支持向量机\ex6data2.mat"

    try:
        # 创建分析器
        analyzer = RBF_SVM_Analyzer(mat_path, random_state=42)

        # 运行完整分析
        analyzer.run_full_analysis()

    except FileNotFoundError:
        print(f"❌ 找不到文件: {mat_path}")
        print("请检查文件路径是否正确")
    except Exception as e:
        print(f"❌ 程序执行出错: {e}")
        import traceback
        traceback.print_exc()


if __name__ == "__main__":
    main()

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐