支持向量机(SVM)算法理论与实践(通俗易懂版)

1. SVM是什么?(通俗解释)

支持向量机(SVM)是一种常用的分类算法。它的核心思想是:在所有能把两类数据分开的直线(或超平面)中,找到“离两类数据最近的点最远”的那一条

举个例子

假设你有一堆红球和蓝球,散落在桌面上(二维平面)。你要用一把尺子(直线)把红球和蓝球分开。你会怎么放这把尺子?

  • 你可能会发现,有很多种放法都能把红球和蓝球分开。
  • SVM的做法是:找一条让红球和蓝球离尺子最近的距离最大的直线。这样分得最“安全”,新来的球也更容易分对。

在这里插入图片描述


2. SVM的数学原理(简单版)

2.1 间隔(Margin)是什么?

  • 间隔就是“离分界线最近的点的距离”。
  • SVM要做的就是让这个距离最大。

2.2 SVM的目标

假设分界线的公式是 w 1 x 1 + w 2 x 2 + b = 0 w_1x_1 + w_2x_2 + b = 0 w1x1+w2x2+b=0,SVM的目标是:

找到 w 1 , w 2 , b w_1, w_2, b w1,w2,b,让所有点都被正确分开,并且最近的点离分界线的距离最大。

2.3 支持向量

  • 支持向量就是那些“离分界线最近的点”。
  • 只有这些点决定了分界线的位置,其他点怎么动都不会影响分界线。

举个例子,假如你有如下数据:

x1x2类别
12
23
20
31

SVM会找到一条直线,把红和蓝分开,并且让离直线最近的红球和蓝球距离最大。


3. SVM怎么处理分不开的情况?

现实中,数据可能分不开(有噪声、重叠)。SVM允许有些点分错,但会对分错的点进行“惩罚”,这叫软间隔

  • 惩罚的大小由参数 C C C 控制, C C C越大,越不允许分错。

4. SVM怎么处理非线性问题?

有时候,数据不是一条直线能分开的,比如像圆圈一样分布。SVM有个“核技巧”,可以把数据映射到高维空间,让它变得线性可分。

  • 常用的核函数有:线性核、多项式核、高斯核(RBF)。

举个例子:

  • 原空间:红球在圆心,蓝球在圆环上,一条直线分不开。
  • 映射到高维空间后,可以用一个平面分开。

5. SVM的优缺点

优点:

  • 分类效果好,尤其是间隔大的情况
  • 可以处理高维数据
  • 可以用核函数处理非线性问题

缺点:

  • 对大数据集训练慢
  • 对参数和核函数敏感
  • 不适合太多噪声的数据

6. SVM小结

  • SVM就是“最大间隔分界线”
  • 支持向量决定分界线
  • 可以处理分不开和非线性问题(软间隔、核技巧)

7. Python实现SVM(基于乳腺癌数据集)

理论讲完了,接下来我们用一个实际的数据集——乳腺癌数据集,来演示如何使用 sklearn 库实现 SVM 分类器。我们将使用线性核函数进行分类,并评估模型性能。

完整代码和数据集请前往 nano-ML获取

7.1 数据加载与初步探索

首先,我们加载乳腺癌数据集,并查看数据的基本情况。

import pandas as pd

# 加载数据
data = pd.read_csv('./data/data.csv')
print("数据集前5行:")
print(data.head())

# %%
# 查看数据基本信息和类别分布
print("\n类别分布:")
print(data['diagnosis_result'].value_counts())

运行结果:

数据集前5行:
   id diagnosis_result  radius  texture  perimeter  area  smoothness  \
0   1                M      23       12        151   954       0.143   
1   2                B       9       13        133  1326       0.143   
2   3                M      21       27        130  1203       0.125   
3   4                M      14       16         78   386       0.070   
4   5                M       9       19        135  1297       0.141   

   compactness  symmetry  fractal_dimension  
0        0.278     0.242              0.079  
1        0.079     0.181              0.057  
2        0.160     0.207              0.060  
3        0.284     0.260              0.097  
4        0.133     0.181              0.059  

类别分布:
diagnosis_result
M    62
B    38
Name: count, dtype: int64

从结果可以看到,数据集包含 iddiagnosis_result(诊断结果,即标签)、以及一些数值特征(如 radius, texture 等)。diagnosis_result 中 ‘M’ 代表恶性,‘B’ 代表良性。数据集中恶性(M)样本有 62 个,良性(B)样本有 38 个。

7.2 数据预处理

在使用 SVM 模型之前,我们需要进行一些数据预处理步骤:

  • 提取特征(去除 iddiagnosis_result 列)。
  • 对标签进行编码,将 ‘M’ 编码为 1(恶性),‘B’ 编码为 0(良性)。
  • 将数据集划分为训练集和测试集,通常按 8:2 的比例划分。为了保证训练集和测试集中各类样本的比例相似,我们使用 stratify 参数。
  • 对特征进行标准化(StandardScaler),因为 SVM 对特征的尺度比较敏感。
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

# 取特征和标签
X = data.iloc[:, 2:].values # 取第三列及之后的所有列作为特征
y = np.where(data['diagnosis_result'] == 'M', 1, 0) # 将 'M' 编码为 1, 'B' 编码为 0

# 划分训练集和测试集 (80% 训练集, 20% 测试集)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y # stratify=y 保证训练集和测试集的标签比例一致
)
print(f"训练集样本数: {len(y_train)}, 测试集样本数: {len(y_test)}")

# 特征标准化
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train) # 在训练集上拟合 StandardScaler 并进行转换
X_test = scaler.transform(X_test) # 在测试集上直接使用训练集拟合的 StandardScaler 进行转换

运行结果:

训练集样本数: 80, 测试集样本数: 20

成功将数据集划分为 80 个训练样本和 20 个测试样本,并完成了特征标准化。

7.3 SVM模型训练与预测(线性核)

现在,我们使用 sklearn 中的 SVC 类来构建和训练一个 SVM 分类器。这里我们先使用最简单的线性核(kernel='linear')。参数 C 控制软间隔的惩罚程度,random_state 用于保证结果的可复现性。

from sklearn.svm import SVC

# 创建并训练SVM分类器(线性核)
svm_clf = SVC(kernel='linear', C=1.0, random_state=42)
svm_clf.fit(X_train, y_train)
print("SVM模型已训练完成(线性核)")

# 在测试集上进行预测
y_pred = svm_clf.predict(X_test)
print("前10个预测结果:", y_pred[:10])
print("前10个真实标签:", y_test[:10])

运行结果:

SVM模型已训练完成(线性核)
前10个预测结果: [0 1 1 0 0 1 0 1 0 0]
前10个真实标签: [1 1 1 1 0 0 0 1 0 0]

模型已经训练完成,并在测试集上进行了预测。从前 10 个预测结果和真实标签来看,有一些预测是错误的,但大部分是正确的。接下来,我们将对模型的整体性能进行评估。

7.4 模型评估

我们使用准确率(accuracy)和分类报告(classification_report)来评估模型在测试集上的性能。分类报告包含精确率(precision)、召回率(recall)、F1-score 等指标,可以更全面地了解模型在每个类别上的表现。

from sklearn.metrics import accuracy_score, classification_report, confusion_matrix

# 计算准确率
acc = accuracy_score(y_test, y_pred)
print(f"测试集准确率:{acc:.4f}")

# 生成分类报告
print("分类报告:")
print(classification_report(y_test, y_pred, target_names=['良性(B)', '恶性(M)']))

运行结果:

测试集准确率:0.8000
分类报告:
              precision    recall  f1-score   support

    良性(B)       0.75      0.75      0.75         8
    恶性(M)       0.83      0.83      0.83        12

   accuracy                           0.80        20
  macro avg       0.79      0.79      0.79        20
weighted avg       0.80      0.80      0.80        20

从评估结果可以看出:

  • 模型在测试集上的准确率是 80%
  • 良性(B) 类别(标签 0):精确率为 0.75,召回率为 0.75,F1-score 为 0.75。这意味着在所有预测为良性的样本中,75% 是真正的良性;在所有真实良性的样本中,模型找出了 75%。
  • 恶性(M) 类别(标签 1):精确率为 0.83,召回率为 0.83,F1-score 为 0.83。这意味着在所有预测为恶性的样本中,83% 是真正的恶性;在所有真实恶性的样本中,模型找出了 83%。
  • support 表示测试集中每个类别的样本数。
  • macro avg 是每个类别指标的平均值,weighted avg 是每个类别指标按样本数加权的平均值。

对于乳腺癌诊断这个场景,恶性(M)样本的召回率通常更重要,因为我们希望尽量找出所有恶性病例(减少漏诊)。在这个简单的线性核模型中,恶性类别的召回率达到了 0.83。

这只是一个初步的线性 SVM 模型。在实际应用中,我们还可以尝试不同的核函数(如 RBF 核)、调整参数(如 C 和 gamma),并使用交叉验证等技术来寻找最优的模型配置,从而进一步提高分类性能。

以上内容为本人学习时整理,若有不当之处欢迎指正!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值