如何在R中对LASSO与KNN回归做标准化并对比输出?
问题分析与解决方案
核心问题拆解
- 标准化逻辑错误:你在KNN代码中误将目标变量
Salary也做了标准化,但LASSO的standardize=TRUE仅标准化自变量,目标变量保留原始尺度,导致两者预测值不在同一量级,MSE无法直接对比。 - 模型特性误解:KNN是基于距离的非参数模型,不存在类似LASSO的回归系数(beta),因此没有“对比系数”的基础,这是思路上的误区。
修正方案
一、统一标准化流程(确保MSE可对比)
无论使用LASSO还是KNN,标准化都应仅处理自变量,目标变量保留原始值;且测试集必须使用训练集的均值和标准差进行标准化(禁止用测试集自身统计量,避免数据泄露)。
1. 修正后的KNN代码
library(caret) fn.split <- function(d,p=0.2) { aux <- 1:length(d[,1]) id.test <- sort(sample(aux,size=floor(p*length(aux)), replace=FALSE)) d.test <- d[id.test,] d.train <- d[-id.test,] return(list(train=d.train,test=d.test)) } set.seed(34064064) hitters.na<-na.omit(Hitters) split.data<-fn.split(d=hitters.na,p=0.3) train<-split.data$train test<-split.data$test # 分离自变量与目标变量,仅对自变量做标准化 train_x <- train[, !names(train) %in% "Salary"] train_y <- train$Salary test_x <- test[, !names(test) %in% "Salary"] test_y <- test$Salary # 记录训练集自变量的均值、标准差(用于测试集标准化) norm_params <- lapply(train_x, function(col) { if(is.numeric(col)) list(mean = mean(col), sd = sd(col)) else NULL }) # 标准化训练集自变量 for (col in names(train_x)) { if(is.numeric(train_x[[col]])) { train_x[[col]] <- (train_x[[col]] - norm_params[[col]]$mean) / norm_params[[col]]$sd } } # 用训练集参数标准化测试集自变量(关键步骤) for (col in names(test_x)) { if(is.numeric(test_x[[col]])) { test_x[[col]] <- (test_x[[col]] - norm_params[[col]]$mean) / norm_params[[col]]$sd } } # 生成哑变量 train_x$League<-ifelse(train_x$League=="N",1,0) train_x$NewLeague<-ifelse(train_x$NewLeague=="N",1,0) train_x$Division<-ifelse(train_x$Division=="W",1,0) test_x$League<-ifelse(test_x$League=="N",1,0) test_x$NewLeague<-ifelse(test_x$NewLeague=="N",1,0) test_x$Division<-ifelse(test_x$Division=="W",1,0) # 合并数据并训练KNN train_processed <- cbind(train_x, Salary = train_y) knn.reg<-knnreg(Salary~.,data=train_processed,k=20) # 预测并计算原始尺度下的MSE pred <- predict(knn.reg, newdata = test_x) mse<- mean((test_y - pred)^2) print(mse)
2. LASSO代码验证
你的LASSO代码逻辑正确:glmnet的standardize=TRUE会自动标准化自变量,预测时将结果还原为目标变量的原始尺度,计算的MSE是原始Salary量级下的值,现在可与修正后的KNN的MSE直接对比。
二、关于“系数对比”的说明
KNN是非参数模型,不学习线性回归式的系数,仅通过样本间距离加权预测,因此不存在可与LASSO的beta系数对比的参数。若需对比特征重要性:
- LASSO可通过非零系数直接判断特征是否被选中;
- KNN可通过“移除某特征后MSE的变化幅度”评估该特征的贡献度。
三、额外优化建议
- 用
caret的preProcess功能替代手动标准化,更简洁且避免错误:
preProc <- preProcess(train_x, method = c("center", "scale", "dummy")) train_x_processed <- predict(preProc, train_x) test_x_processed <- predict(preProc, test_x)
- LASSO交叉验证可直接使用默认lambda序列,无需手动指定,通常效果更稳定。
内容的提问来源于stack exchange,提问作者SCZZI
相关产品推荐
相关产品推荐

