支持向量机
一.概念

1.1核心定义:

监督学习: SVM 需要带标签(类别)的数据进行训练。
二元分类: 其基本形式用于区分两个类别。
广义线性分类器: 虽然决策边界在原始输入空间可能是非线性的(通过核技巧),但在变换后的高维特征空间中,它是一个线性决策边界(超平面)。所以称之为“广义线性”。
决策边界 = 最大边距超平面: 这是SVM最核心的思想。它的目标不是简单地找一个能分开数据的超平面,而是找那个能最大化两个类别最近数据点(支持向量)到该超平面距离(间隔)的超平面。这个最大间隔被认为是泛化能力最好的。

1.2线性可分情况(理想情况):

当数据在原始输入空间可以用一个超平面完美分开时,SVM的目标就是找到那个具有最大间隔的超平面。

这被形式化为一个凸二次规划优化问题。凸优化问题的好处是任何局部最优解也必然是全局最优解,且存在高效可靠的求解算法。

核心要素:

超平面: w·x + b = 0 (其中 w 是法向量,b 是偏置项)。
间隔: 两个类别最近点到超平面的距离之和 (2 / ||w||)。
最大化间隔: 等价于最小化 ||w||² / 2 (为了数学便利)。
约束条件: 所有样本点被正确分类 (y_i(w·x_i + b) >= 1,其中 y_i 是样本标签 +1 或 -1)。
支持向量: 那些满足 y_i(w·x_i + b) = 1 的点,它们直接定义了最大间隔和最终的决策边界。

1.3线性不可分情况(现实更常见):

当数据在原始输入空间无法用线性超平面完美分开时,SVM通过两种关键技术来处理:

松弛变量 (Slack Variables - ξ_i):

引入变量 ξ_i >= 0 来允许一些样本点违反原始严格的间隔约束(甚至被错误分类)。

约束条件变为 y_i(w·x_i + b) >= 1 - ξ_i。

优化目标变为最小化 ||w||² / 2 + C * Σξ_i。

惩罚参数 C: 这个超参数至关重要。它平衡了两个目标:

||w||² / 2: 最大化间隔(提高泛化能力)。

Σξ_i: 最小化分类错误(或违反间隔的程度)。

C 越大,对分类错误的惩罚越大,模型倾向于更小的间隔和更少的训练错误(可能过拟合)。

C 越小,对分类错误的容忍度越高,模型倾向于更大的间隔(可能欠拟合,但泛化可能更好)。

核技巧 (Kernel Trick):

核心思想:通过一个非线性映射函数 Φ,将原始输入空间 x 中的样本点映射到一个更高维(甚至无限维)的特征空间 Φ(x)。

关键洞察: 在原始空间线性不可分的数据,在高维特征空间中可能变得线性可分。

核技巧的威力: 我们不需要显式计算高维空间中的向量 Φ(x)!我们只需要定义一个核函数 K(x_i, x_j) = Φ(x_i)·Φ(x_j)。这个函数直接在原始输入空间上计算两个样本点在映射后高维空间中的内积。

常用核函数: 线性核 (K(x_i, x_j) = x_i·x_j), 多项式核, 径向基函数(RBF)核/高斯核 (K(x_i, x_j) = exp(-γ||x_i - x_j||²)) 等。

优化问题(包括目标函数和决策函数)中的所有点积 x_i·x_j 都被替换成核函数 K(x_i, x_j)。这样,我们就在高维空间有效地寻找最优分类超平面,而无需承担高维计算的开销。

1.4数学本质:

无论在线性可分还是不可分(使用核技巧)的情况下,SVM的训练最终都归结为求解一个凸二次规划 (Convex Quadratic Programming, QP) 问题。这是一个有成熟高效算法(如SMO算法)的优化问题类型,保证了能找到全局最优解。

2.1 线性可分

对于一个数据集合可以画一条直线将两组数据点分开,这样的数据成为线性可分,如下图所示:

2.2 线性不可分
对于线性不可分的数据集,我们无法找到这样一种直线,将不同类型的样本分割开来,SVM的方法好像就不适用了。

二、垃圾邮寄分类实现
2.1 邮寄预处理`#邮件预处理

#邮件预处理
def process_email(email_contents):
    #转换为小写
    email_contents = email_contents.lower()
    #移除HTML标签
    email_contents = re.sub(r'<[^<>]+>', ' ', email_contents)
    #处理URLs
    email_contents = re.sub(r'(http|https)://[^\s]*', 'httpaddr', email_contents)
    #处理电子邮件地址
    email_contents = re.sub(r'[^\s]+@[^\s]+', 'emailaddr', email_contents)
    #处理美元符号$
    email_contents = re.sub(r'[$]+', 'dollar', email_contents)
    #处理数字
    email_contents = re.sub(r'[0-9]+', 'number', email_contents)
    #分词
    words = re.split(r'[@$/#.-:&*+=\[\]?!(){},\'\">_<;%\s\n\r\t]+', email_contents)
    #移除空字符串
    words = [word for word in words if len(word) > 0]
    return words

2.2 词汇表处理

#词汇表处理
def get_vocab_dict():
    vocab_dict = {}
    with open('vocab.txt', 'r') as f:
        for line in f:
            idx, word = line.strip().split('\t')
            vocab_dict[word] = int(idx)
    return vocab_dict

2.3 特征提取

#特征提取
def email_features(words, vocab_dict):
    n = len(vocab_dict)
    features = np.zeros(n)
    for word in words:
        if word in vocab_dict:
            features[vocab_dict[word] - 1] = 1  #词汇表索引从1开始
    return features
 


2.4 SVM分类器训练与评估

#训练SVM分类器
def train_svm_classifier():
    #加载训练数据
    data = loadmat('spamTrain.mat')
    X_train = data['X']
    y_train = data['y'].ravel()
    #训练SVM模型
    C = 0.1  #正则化参数
    model = SVC(C=C, kernel='linear')
    model.fit(X_train, y_train)
    #评估训练集性能
    train_pred = model.predict(X_train)
    print(f"训练集准确率: {np.mean(train_pred == y_train) * 100:.2f}%")
    return model
 
#评估模型
def evaluate_model(model):
    #加载测试数据
    data = loadmat('spamTest.mat')
    X_test = data['Xtest']
    y_test = data['ytest'].ravel()
    #预测并评估
    test_pred = model.predict(X_test)
    print(f"测试集准确率: {np.mean(test_pred == y_test) * 100:.2f}%")
    return test_pred

2.5 预测新邮件

#预测新邮件
def predict_new_email(model, email_path):
    #读取邮件内容
    with open(email_path, 'r') as f:
        email_contents = f.read()
    #预处理邮件
    words = process_email(email_contents)
    #获取词汇表
    vocab_dict = get_vocab_dict()
    #提取特征
    features = email_features(words, vocab_dict)
    #预测
    prediction = model.predict([features])[0]
    print(f"\n邮件 {email_path} 的预测结果: {'垃圾邮件' if prediction == 1 else '非垃圾邮件'}")
    #显示前15个最能预测垃圾邮件的词汇
    vocab_list = sorted(vocab_dict.items(), key=lambda x: x[1])
    vocab_list = [word for word, idx in vocab_list]
    coef = model.coef_[0]
    top_indices = np.argsort(coef)[-15:][::-1]
    print("\n前15个最能预测垃圾邮件的词汇:")
    for idx in top_indices:
        print(f"{vocab_list[idx]:<15} 权重: {coef[idx]:.4f}")
 

更多推荐