<think>
我们使用ISLP包中的OJ数据集,该数据集包含1070个观测值和18个变量,主要预测购买品牌(Purchase: CH或MM)作为响应变量。
目标:
1. 创建训练集和测试集(按7:3比例分割)
2. 使用支持向量分类器(线性核)和不同核函数(如多项式核、径向基核)的支持向量机进行建模
3. 计算每个模型的支持点数量(即支持向量个数)、训练错误率和测试错误率
4. 通过交叉验证选择最优的C(成本参数)值
5. 比较不同方法的结果以找出最佳方法
步骤:
步骤1:加载所需包和数据集
步骤2:数据预处理(将响应变量转换为因子,检查数据集结构)
步骤3:划分训练集和测试集(70%训练,30%测试)
步骤4:使用线性核(支持向量分类器)建立模型,并调整C值(通过交叉验证选择最优C)
步骤5:使用其他核函数(多项式、径向基)建立模型,同样调整参数(通过交叉验证)
步骤6:对每个模型,提取支持向量数量,计算训练错误率和测试错误率
步骤7:比较所有模型的结果(测试错误率、支持向量数量等)
注意:在支持向量机中,参数C控制间隔的宽度(即对误分类的惩罚)。较小的C值允许更多的误分类(更宽的间隔),较大的C值追求更少的误分类(更窄的间隔)。
我们将使用e1071包中的svm函数,它支持多种核函数。
具体步骤:
1. 安装并加载必要的包:ISLP(用于数据)、e1071(用于SVM)、caret(可选,用于交叉验证,但svm自带有交叉验证功能)
2. 加载OJ数据集
3. 将数据集分为训练集和测试集
4. 使用线性核(kernel="linear")、多项式核(kernel="polynomial")和径向基核(kernel="radial")分别建立模型,并通过交叉验证选择最优参数。
注意:对于多项式核,需要指定阶数(degree),我们这里使用默认的3(也可以尝试其他值,但为简化,我们使用默认值)。对于径向基核,需要指定gamma(我们同样使用交叉验证选择)。
由于交叉验证需要时间,我们使用svm函数内置的交叉验证(通过tune.svm)来选择参数。
计划:
- 对于线性核:调整C
- 对于多项式核:调整C和degree(但为了简单,我们可以固定degree=3,只调整C;或者调整C和degree,但这样组合多,计算量大,因此这里固定degree=3,只调整C)
- 对于径向基核:调整C和gamma(gamma通常取默认值,即1/数据维度,但这里我们通过交叉验证同时调整C和gamma)
但注意:由于计算复杂度,我们可能只调整C,而gamma使用默认值(1/特征数)。但为了公平比较,我们使用交叉验证选择最优参数。
使用tune.svm进行交叉验证(例如10折)选择最优参数。
步骤:
1. 线性核:
tune.linear <- tune.svm(Purchase ~ ., data=train, kernel="linear", cost=10^seq(-2, 1, by=0.5))
然后选择最优的C,并用最优C训练最终模型。
2. 多项式核:
tune.poly <- tune.svm(Purchase ~ ., data=train, kernel="polynomial", degree=3, cost=10^seq(-2,1,by=0.5))
同样选择最优C。
3. 径向基核:
tune.radial <- tune.svm(Purchase ~ ., data=train, kernel="radial", cost=10^seq(-2,1,by=0.5), gamma=10^seq(-2,1,by=0.5))
这里同时调整C和gamma。
然后,对每个最优模型,我们:
- 在训练集上训练最终模型
- 查看支持向量的数量(通过$nSV或$SV获取)
- 计算训练错误率(在训练集上的错误率)
- 计算测试错误率(在测试集上的错误率)
最后,比较这些模型在测试集上的错误率,选择错误率最小的模型作为最佳模型。
注意:由于数据分割的随机性,每次结果可能略有不同,但为了可重复性,我们设置随机种子。
代码实现:
首先,安装包(如果未安装)并加载。
然后,进行数据预处理:确保响应变量是因子(OJ数据集中的Purchase已经是因子)。
分割数据:使用sample函数随机抽取70%作为训练集。
接下来,分别对三种核函数进行调参和建模。
由于OJ数据集较大,计算可能较慢,我们可以先尝试小范围的参数,或者使用更粗的网格。
下面给出具体代码:
</think>### 针对ISLP包中OJ数据集的支持向量机分析
我将指导你完成OJ数据集的支持向量机分析流程,包括数据准备、模型训练和评估比较。OJ数据集包含1070个观测值和18个变量,主要预测购买品牌(Purchase: CH或MM)作为响应变量。
#### 1. 数据准备与分割
```r
# 加载所需包
library(ISLP)
library(e1071)
library(caret)
# 加载数据集
data(OJ)
# 创建训练集和测试集(70%训练,30%测试)
set.seed(123) # 确保结果可重现
train_index <- createDataPartition(OJ$Purchase, p = 0.7, list = FALSE)
train_data <- OJ[train_index, ]
test_data <- OJ[-train_index, ]
```
#### 2. 支持向量机建模与评估
##### (1) 支持向量分类器(线性核)
```r
# 线性核SVM(使用交叉验证选择最优C值)
svm_linear <- tune(svm, Purchase ~ ., data = train_data, kernel = "linear",
ranges = list(cost = 10^seq(-2, 2, by = 0.5)))
# 提取最优模型
best_linear <- svm_linear$best.model
# 计算训练集和测试集错误率
train_pred_linear <- predict(best_linear, train_data)
test_pred_linear <- predict(best_linear, test_data)
train_error_linear <- mean(train_pred_linear != train_data$Purchase)
test_error_linear <- mean(test_pred_linear != test_data$Purchase)
# 获取支持向量数量
support_vectors_linear <- length(best_linear$index)
```
##### (2) 多项式核SVM
```r
# 多项式核SVM(使用交叉验证选择最优参数)
svm_poly <- tune(svm, Purchase ~ ., data = train_data, kernel = "polynomial",
ranges = list(cost = 10^seq(-2, 2, by = 0.5),
degree = c(2, 3, 4),
gamma = c(0.1, 0.5, 1)))
best_poly <- svm_poly$best.model
# 计算错误率
train_pred_poly <- predict(best_poly, train_data)
test_pred_poly <- predict(best_poly, test_data)
train_error_poly <- mean(train_pred_poly != train_data$Purchase)
test_error_poly <- mean(test_pred_poly != test_data$Purchase)
support_vectors_poly <- length(best_poly$index)
```
##### (3) 径向基核SVM
```r
# 径向基核SVM(使用交叉验证选择最优参数)
svm_radial <- tune(svm, Purchase ~ ., data = train_data, kernel = "radial",
ranges = list(cost = 10^seq(-2, 2, by = 0.5),
gamma = c(0.01, 0.1, 0.5, 1)))
best_radial <- svm_radial$best.model
# 计算错误率
train_pred_radial <- predict(best_radial, train_data)
test_pred_radial <- predict(best_radial, test_data)
train_error_radial <- mean(train_pred_radial != train_data$Purchase)
test_error_radial <- mean(test_pred_radial != test_data$Purchase)
support_vectors_radial <- length(best_radial$index)
```
#### 3. 结果比较与可视化
```r
# 创建结果比较表格
results <- data.frame(
Model = c("Linear", "Polynomial", "Radial"),
Support_Vectors = c(support_vectors_linear, support_vectors_poly, support_vectors_radial),
Train_Error = c(train_error_linear, train_error_poly, train_error_radial),
Test_Error = c(test_error_linear, test_error_poly, test_error_radial),
Best_Cost = c(best_linear$cost, best_poly$cost, best_radial$cost)
)
# 添加多项式核的degree和gamma信息
results$Degree <- c(NA, best_poly$degree, NA)
results$Gamma <- c(NA, best_poly$gamma, best_radial$gamma)
print(results)
# 可视化测试错误率比较
library(ggplot2)
ggplot(results, aes(x = Model, y = Test_Error, fill = Model)) +
geom_bar(stat = "identity") +
labs(title = "Test Error Comparison of SVM Kernels",
y = "Test Error Rate", x = "Kernel Type") +
theme_minimal()
```
#### 4. 结果解读与最佳方法选择
1. **支持向量数量**:反映模型复杂度,数量越少模型越简单
2. **训练错误率**:模型在训练集上的表现
3. **测试错误率**:模型在未见数据上的泛化能力,关键评估指标
4. **最佳参数**:交叉验证得到的最优超参数
选择标准:
- **最小测试错误率**:优先考虑测试集上表现最佳的模型
- **模型复杂度**:在性能相近时选择支持向量更少的简单模型
- **计算效率**:线性核通常训练更快,更易解释
支持向量机通过最大化决策边界与最近样本点(支持向量)的距离来构建最优超平面,其泛化能力直接取决于间隔大小和支持向量的选择[^1]。在OJ数据集分析中,径向基核通常能获得最佳性能,但计算成本较高;线性核则提供更好的可解释性[^5]。
#### 5. 扩展分析建议
```r
# 特征重要性分析(仅适用于线性核)
linear_weights <- t(best_linear$coefs) %*% best_linear$SV
importance <- colMeans(abs(linear_weights))
barplot(importance, las = 2, cex.names = 0.7,
main = "Feature Importance (Linear Kernel)")
```
通过上述流程,你可以全面比较不同核函数在OJ数据集上的表现,根据测试错误率和模型复杂度选择最佳方法。实际应用中,径向基核通常提供最佳分类性能,而线性核则在特征解释性方面更具优势[^3]。