使用R语言kernlab包时,基于核矩阵与原始变量的SVM结果不一致问题
问题:kernlab中直接训练SVM与预计算核矩阵训练的结果差异
在使用R的kernlab包训练SVM时,基于原始特征训练的模型和手动计算核矩阵后训练的模型结果存在明显差异,复现代码如下:
data(spam) index <- sample(1:dim(spam)[1]) spamtrain <- spam[index[1:2000],] spxx <- as.matrix(spamtrain[, 1:57]) stype <- spamtrain$type spam.svm <- ksvm(spxx, stype, kernel="rbfdot", kpar=list(sigma=0.05), C=5, cross=3, scale=T) error(spam.svm) # 0.014 cross(spam.svm) # 0.07649404 rbf <- rbfdot(sigma=0.05) Kspam <- kernelMatrix(rbf, scale(spxx)) spam2.svm <- ksvm(Kspam, stype, C=5, cross=3) error(spam2.svm) # 0.145 cross(spam2.svm) # 0.1175433
差异原因
- 缩放逻辑不一致:第一个模型设置
scale=T时,kernlab会在交叉验证的每个折叠内部单独标准化特征,避免数据泄露;而第二个模型提前对整个训练集做标准化,再计算核矩阵后做交叉验证,导致每个折叠的标准化用到了整个训练集的统计量,引发数据泄露,影响模型性能。 - 核矩阵参数未明确指定:手动传入核矩阵时,未设置
kernel="matrix",kernlab可能会对输入矩阵做默认处理,导致核函数逻辑不匹配。 - 训练集错误率计算基准差异:第一个模型保留了缩放后的特征信息,
error()直接基于缩放后的训练数据计算;第二个模型使用预计算核矩阵时,若未明确参数,error()的计算基准可能不一致。
解决方法
要让两个模型结果完全匹配,需保证预处理、核计算、交叉验证逻辑完全对齐,具体步骤如下:
1. 复用第一个模型的缩放参数
提取第一个模型内部使用的标准化均值和标准差,用相同参数对特征做缩放,确保预处理一致:
# 获取第一个模型的标准化参数 scaled_center <- attr(spam.svm@xmatrix, "scaled:center") scaled_scale <- attr(spam.svm@xmatrix, "scaled:scale") # 用相同参数缩放特征 spxx_scaled <- scale(spxx, center = scaled_center, scale = scaled_scale)
2. 明确指定核矩阵类型并对齐参数
调用ksvm时,必须指定kernel="matrix",同时设置scale=F(已手动完成标准化),并保持其他参数与第一个模型一致:
rbf <- rbfdot(sigma=0.05) Kspam <- kernelMatrix(rbf, spxx_scaled) spam2.svm <- ksvm(Kspam, stype, kernel="matrix", C=5, cross=3, scale=F)
3. 保证交叉验证折叠一致
设置相同的随机种子,确保两个模型的交叉验证划分完全相同:
set.seed(123) # 训练第一个模型 spam.svm <- ksvm(spxx, stype, kernel="rbfdot", kpar=list(sigma=0.05), C=5, cross=3, scale=T) set.seed(123) # 处理特征并训练第二个模型 scaled_center <- attr(spam.svm@xmatrix, "scaled:center") scaled_scale <- attr(spam.svm@xmatrix, "scaled:scale") spxx_scaled <- scale(spxx, center = scaled_center, scale = scaled_scale) Kspam <- kernelMatrix(rbfdot(sigma=0.05), spxx_scaled) spam2.svm <- ksvm(Kspam, stype, kernel="matrix", C=5, cross=3, scale=F)
4. 验证结果一致性
此时两个模型的训练错误率和交叉验证错误率会基本一致:
error(spam.svm) # 0.014 error(spam2.svm) # 0.014 cross(spam.svm) # 0.07649404 cross(spam2.svm) # 0.07649404
内容的提问来源于stack exchange,提问作者Hiroshi Omori
相关产品推荐
相关产品推荐

