文章目录
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 支持向量
- 支持向量就是那些“离分界线最近的点”。
- 只有这些点决定了分界线的位置,其他点怎么动都不会影响分界线。
举个例子,假如你有如下数据:
x1 | x2 | 类别 |
---|---|---|
1 | 2 | 红 |
2 | 3 | 红 |
2 | 0 | 蓝 |
3 | 1 | 蓝 |
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
从结果可以看到,数据集包含 id
、diagnosis_result
(诊断结果,即标签)、以及一些数值特征(如 radius
, texture
等)。diagnosis_result
中 ‘M’ 代表恶性,‘B’ 代表良性。数据集中恶性(M)样本有 62 个,良性(B)样本有 38 个。
7.2 数据预处理
在使用 SVM 模型之前,我们需要进行一些数据预处理步骤:
- 提取特征(去除
id
和diagnosis_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),并使用交叉验证等技术来寻找最优的模型配置,从而进一步提高分类性能。
以上内容为本人学习时整理,若有不当之处欢迎指正!