使用R语言进行支持向量机(SVM)垃圾邮件分类教程
2025-06-30
Table of Contents
1. 简介
什么是支持向量机 (SVM)?
支持向量机(Support Vector Machine, SVM)是一种强大且灵活的监督学习算法,可用于分类和回归分析。其核心思想是在特征空间中找到一个能将不同类别样本最大程度分开的决策边界(对于线性可分数据,这个边界是一个超平面)。SVM的目标是找到距离最近的训练数据点(即”支持向量”)最远的那个超平面,这个距离被称为”间隔”(margin)。最大化间隔有助于提高模型的泛化能力。
对于非线性可分的数据,SVM使用一种称为”核技巧”(kernel trick)的方法,将数据映射到更高维度的空间,使其在这个高维空间中变得线性可分。
在本教程中,我们将模拟一个垃圾邮件(Spam)和正常邮件(Ham)的数据集,并使用SVM来构建一个分类器。
2. 准备工作
加载必要的R包
我们将使用 e1071 包来实现SVM,dplyr 用于数据处理,ggplot2 用于数据可视化,caTools 用于数据切分。
# 如果尚未安装,请取消注释并运行以下代码
# install.packages("e1071")
# install.packages("dplyr")
# install.packages("ggplot2")
# install.packages("caTools")
showtext::showtext_auto()
library(e1071)
library(dplyr)
library(ggplot2)
library(caTools)
3. 生成模拟数据
为了演示,我们自己创建一个数据集。真实世界的垃圾邮件分类会使用成千上万个特征(如词频、n-grams等)。在这里,我们简化为几个典型的特征:
- word_freq_free: “免费”一词的出现频率。
- char_freq_dollar: $ 符号的出现频率。
- capital_run_length: 连续大写字母的平均长度。
- is_spam: 目标变量,标记邮件是否为垃圾邮件 (spam 或 ham)。
我们假设垃圾邮件通常含有更多的”免费”、“$”符号和更长的大写字母序列。
set.seed(42) # 为了结果的可重复性
# 生成1000封正常邮件 (ham)
ham_data <- data.frame(
word_freq_free = rnorm(1000, mean = 0.5, sd = 0.3),
char_freq_dollar = rnorm(1000, mean = 0.1, sd = 0.05),
capital_run_length = rnorm(1000, mean = 2, sd = 1),
is_spam = "ham"
)
# 生成800封垃圾邮件 (spam)
spam_data <- data.frame(
word_freq_free = rnorm(800, mean = 2.0, sd = 0.8),
char_freq_dollar = rnorm(800, mean = 0.8, sd = 0.4),
capital_run_length = rnorm(800, mean = 10, sd = 5),
is_spam = "spam"
)
# 合并数据并打乱顺序
full_data <- rbind(ham_data, spam_data)
full_data <- full_data[sample(nrow(full_data)), ]
# 将目标变量转换为因子类型
full_data$is_spam <- as.factor(full_data$is_spam)
# 查看数据结构
str(full_data)
## 'data.frame': 1800 obs. of 4 variables:
## $ word_freq_free : num 2.11 0.154 3.222 0.622 2.624 ...
## $ char_freq_dollar : num 1.0614 0.0668 1.2138 0.6152 0.4506 ...
## $ capital_run_length: num 13.064 3.223 7.576 0.675 10.285 ...
## $ is_spam : Factor w/ 2 levels "ham","spam": 2 1 2 2 2 1 1 2 2 2 ...
summary(full_data)
## word_freq_free char_freq_dollar capital_run_length is_spam
## Min. :-0.5115 Min. :-0.4556 Min. :-6.654 ham :1000
## 1st Qu.: 0.4411 1st Qu.: 0.0888 1st Qu.: 1.757 spam: 800
## Median : 0.7996 Median : 0.1501 Median : 2.937
## Mean : 1.1577 Mean : 0.4039 Mean : 5.568
## 3rd Qu.: 1.8530 3rd Qu.: 0.7276 3rd Qu.: 9.315
## Max. : 4.5396 Max. : 1.9956 Max. :25.129
4. 探索性数据分析 (EDA)
在建模之前,我们先通过可视化来观察数据的大致分布,看看不同类别的数据是否在视觉上可分。
ggplot(full_data, aes(x = word_freq_free, y = char_freq_dollar, color = is_spam)) +
geom_point(alpha = 0.6) +
labs(title = "邮件特征分布: '免费' vs '$' 符号",
x = "免费一词的频率",
y = "$符号的频率") +
theme_minimal()
从图中可以看出,两个类别的数据存在一定的重叠,但总体趋势上是可分的。这为我们使用SVM进行分类提供了基础。
5. 数据准备:划分训练集与测试集
我们将数据按7:3的比例划分为训练集和测试集。
sample_split <- sample.split(full_data$is_spam, SplitRatio = 0.7)
train_set <- subset(full_data, sample_split == TRUE)
test_set <- subset(full_data, sample_split == FALSE)
cat("训练集大小:", nrow(train_set), "\n")
## 训练集大小: 1260
cat("测试集大小:", nrow(test_set), "\n")
## 测试集大小: 540
6. 构建与评估SVM模型
6.1. 基础线性SVM模型
我们首先尝试使用一个简单的线性核SVM。cost参数是”惩罚”系数,它控制着对分类错误的惩罚程度。较高的cost会使模型更努力地正确分类所有训练样本,可能导致过拟合。
# 使用线性核训练模型
svm_linear <- svm(is_spam ~ ., data = train_set, kernel = "linear", cost = 1)
# 在测试集上进行预测
pred_linear <- predict(svm_linear, newdata = test_set)
# 创建混淆矩阵
confusion_matrix_linear <- table(Predicted = pred_linear, Actual = test_set$is_spam)
print("线性SVM混淆矩阵:")
## [1] "线性SVM混淆矩阵:"
print(confusion_matrix_linear)
## Actual
## Predicted ham spam
## ham 300 3
## spam 0 237
# 计算准确率
accuracy_linear <- sum(diag(confusion_matrix_linear)) / sum(confusion_matrix_linear)
cat("线性SVM准确率:", accuracy_linear, "\n")
## 线性SVM准确率: 0.9944444
6.2. 使用非线性核 (径向基核 - RBF)
真实世界的数据往往不是线性可分的。我们尝试使用更灵活的径向基核(Radial Basis Function, RBF),这是SVM中最常用的核之一。
# 使用径向基核训练模型
svm_radial <- svm(is_spam ~ ., data = train_set, kernel = "radial")
# 预测
pred_radial <- predict(svm_radial, newdata = test_set)
# 混淆矩阵
confusion_matrix_radial <- table(Predicted = pred_radial, Actual = test_set$is_spam)
print("径向基核SVM混淆矩阵:")
## [1] "径向基核SVM混淆矩阵:"
print(confusion_matrix_radial)
## Actual
## Predicted ham spam
## ham 300 0
## spam 0 240
# 准确率
accuracy_radial <- sum(diag(confusion_matrix_radial)) / sum(confusion_matrix_radial)
cat("径向基核SVM准确率:", accuracy_radial, "\n")
## 径向基核SVM准确率: 1
可以看到,对于这个数据集,径向基核的表现比线性核要好得多。
7. 模型调优 (Hyperparameter Tuning)
为了获得最佳性能,我们需要对模型的超参数进行调优。对于RBF核的SVM,最重要的两个超参数是: * cost: 惩罚系数。 * gamma: RBF核的参数,决定了单个训练样本的影响范围。
我们将使用 tune() 函数进行10折交叉验证来寻找最佳的 cost 和 gamma 组合。
# 进行调优
# 注意:这可能会花费一些时间
tuned_svm <- tune(svm, is_spam ~ ., data = train_set,
kernel = "radial",
ranges = list(
cost = c(0.1, 1, 10, 100),
gamma = c(0.1, 0.5, 1, 2)
))
# 查看最佳模型和参数
summary(tuned_svm)
##
## Parameter tuning of 'svm':
##
## - sampling method: 10-fold cross validation
##
## - best parameters:
## cost gamma
## 0.1 2
##
## - best performance: 0.003174603
##
## - Detailed performance results:
## cost gamma error dispersion
## 1 0.1 0.1 0.013492063 0.007529233
## 2 1.0 0.1 0.004761905 0.004098395
## 3 10.0 0.1 0.004761905 0.004098395
## 4 100.0 0.1 0.003968254 0.004182907
## 5 0.1 0.5 0.003968254 0.004182907
## 6 1.0 0.5 0.003968254 0.004182907
## 7 10.0 0.5 0.003968254 0.004182907
## 8 100.0 0.5 0.005555556 0.005356735
## 9 0.1 1.0 0.003968254 0.004182907
## 10 1.0 1.0 0.003968254 0.004182907
## 11 10.0 1.0 0.004761905 0.004098395
## 12 100.0 1.0 0.008730159 0.004505129
## 13 0.1 2.0 0.003174603 0.004098395
## 14 1.0 2.0 0.003968254 0.004182907
## 15 10.0 2.0 0.005555556 0.003833698
## 16 100.0 2.0 0.010317460 0.005356735
# 使用最佳参数训练最终模型
best_model <- tuned_svm$best.model
评估最终调优后的模型
# 预测
pred_tuned <- predict(best_model, newdata = test_set)
# 混淆矩阵
confusion_matrix_tuned <- table(Predicted = pred_tuned, Actual = test_set$is_spam)
print("调优后SVM混淆矩阵:")
## [1] "调优后SVM混淆矩阵:"
print(confusion_matrix_tuned)
## Actual
## Predicted ham spam
## ham 299 0
## spam 1 240
# 准确率
accuracy_tuned <- sum(diag(confusion_matrix_tuned)) / sum(confusion_matrix_tuned)
cat("调优后SVM准确率:", accuracy_tuned, "\n")
## 调优后SVM准确率: 0.9981481
有问题咨询
www.rdaima.com www.rdaizuo.com
专业R语言辅导 | Python编程 | 数据分析 Data analysis | 统计分析 Statistics | 数据挖掘 Data mining | 机器学习 Machine learning | 留学生作业代做代写|6.864|9.520|6-867|CS229|CS231n|CS236|CS224n|STATS 202|STATS 203|STAT 110|STAT 104|CS109|BIOS221|10-701|10-605|10-607|10-601|10-603|10-604|STAT 705|STAT 707|COMS4771|COMS5771|COMS5733|COMS4733|STAT4203|STAT4204|STAT4205|STAT4206|STAT 133|STAT 134|DATA C88|CS 265|STAT 101A|STAT 100A|CS273A|CSE250A|COGS118A|CS-GY.6923|BUSF-GB.2397|CS 542|STAT 581|MLMI 201|MLMI 202|COMP0087|COMP0088|COMP01011|COMP3008|INFR11136|INFR11218|DATA1001|CSC311H1|CSC411|CSC413|CSC414|CSC412|STA302|STA2453H|STAT 302|DSCI511|DSCI512|DSCI513|DSCI514|STAT 540|STAT 541|CPSC 587|STAT 517|COMP 551|COMP 520|STAT 520|STAT 521|STAT 4500|STAT 5805|STAT 5806|STAT 4600|COMP5805|COMP90051|COMP90053|COMP90054|COMP90057|MATH90010|MATH90011|MATH90012|STAT30001|COMP1730|STAT3001|STAT3002|STAT3003|STAT3004|STAT3005|STAT3006|MATH3001|COMP5311|COMP5312|COMP5313|COMP5314|COMP5315|COMP5316|COMP5317|COMP5318|STAT5001|STAT5002|STAT5003|STAT5004|FIT5097|FIT5098|FIT5099|FIT5100|MTH5001|MTH5002|MTH5003
请咨询 www.daixie.it.com www.rcodedaixie.com
8. 结论
在本教程中,我们学习了如何使用R语言和e1071包来构建一个支持向量机(SVM)分类器,并将其应用于模拟的垃圾邮件分类任务。
我们完成了以下步骤: 1. 生成了一个包含典型垃圾邮件特征的模拟数据集。 2. 通过探索性数据分析(EDA)对数据进行了可视化。 3. 将数据划分为训练集和测试集。 4. 分别训练了线性和非线性(径向基核)的SVM模型,并比较了它们的性能。 5. 使用交叉验证对非线性模型的超参数(cost和gamma)进行了调优,找到了最佳模型。 6. 评估了最终模型的性能,它在测试集上达到了很高的准确率。
这个例子展示了SVM在分类问题上的强大能力,尤其是当结合了核技巧和超参数调优时。在真实世界的应用中,特征工程(选择和创建有意义的特征)和更广泛的超参数搜索将是进一步提升模型性能的关键。