如何对训练集除指定列外的列标准化,并同步缩放测试集?
嘿,我太懂你这种手动折腾缩放的痛苦了——一会儿要找列索引,一会儿要存均值标准差,稍不注意就把测试集的统计量混进去了,完全是重复劳动!下面给你几个更优雅的解决方案,从基础R到专门的机器学习工具都有,挑你顺手的来:
方法一:基础R封装函数,复用性拉满
如果你习惯用基础R,可以把整个流程封装成一个函数,一次写好之后随时调用,再也不用重复敲代码:
# 定义通用缩放函数 scale_selected <- function(train_data, test_data, exclude_cols) { # 筛选出需要缩放的列(排除指定列) scale_cols <- setdiff(names(train_data), exclude_cols) # 计算训练集目标列的均值和标准差(自动忽略NA) train_means <- colMeans(train_data[scale_cols], na.rm = TRUE) train_sds <- apply(train_data[scale_cols], 2, sd, na.rm = TRUE) # 缩放训练集 train_scaled <- train_data train_scaled[scale_cols] <- scale(train_data[scale_cols], center = train_means, scale = train_sds) # 用训练集的统计量缩放测试集 test_scaled <- test_data test_scaled[scale_cols] <- lapply(scale_cols, function(col) { (test_data[[col]] - train_means[col]) / train_sds[col] }) %>% as.data.frame() # 返回缩放后的数据集+统计量(方便后续检查) list( train_scaled = train_scaled, test_scaled = test_scaled, scaling_stats = list(means = train_means, sds = train_sds) ) } # 示例用法 set.seed(123) train_df <- data.frame( id = 1:10, category = sample(c("A", "B"), 10, replace = TRUE), num1 = rnorm(10, 50, 10), num2 = rnorm(10, 20, 5), num3 = rnorm(10, 100, 20) ) test_df <- data.frame( id = 11:15, category = sample(c("A", "B"), 5, replace = TRUE), num1 = rnorm(5, 50, 10), num2 = rnorm(5, 20, 5), num3 = rnorm(5, 100, 20) ) # 调用函数,排除id和category列 result <- scale_selected(train_df, test_df, exclude_cols = c("id", "category")) # 查看结果 result$train_scaled result$test_scaled
方法二:tidyverse管道风格,代码更整洁
如果你平时用dplyr这类工具,用管道流处理会更符合你的代码习惯,可读性也更强:
library(dplyr) # 先从训练集提取缩放所需的均值和标准差 exclude_cols <- c("id", "category") scaling_stats <- train_df %>% select(-all_of(exclude_cols)) %>% summarize(across(everything(), list(mean = mean, sd = sd), na.rm = TRUE)) # 缩放训练集 train_scaled <- train_df %>% mutate(across(-all_of(exclude_cols), ~ (.x - scaling_stats[[paste0(cur_column(), "_mean")]]) / scaling_stats[[paste0(cur_column(), "_sd")]])) # 复用训练集的统计量缩放测试集 test_scaled <- test_df %>% mutate(across(-all_of(exclude_cols), ~ (.x - scaling_stats[[paste0(cur_column(), "_mean")]]) / scaling_stats[[paste0(cur_column(), "_sd")]]))
方法三:用caret一键搞定,机器学习场景首选
如果你的场景是机器学习预处理,caret包的preProcess绝对是最优解——它会自动帮你存储训练集的统计量,直接用predict就能处理测试集,完全不用手动管理均值和标准差:
library(caret) exclude_cols <- c("id", "category") # 基于训练集的目标列创建预处理对象(center=中心化,scale=标准化) pre_proc <- preProcess(train_df %>% select(-all_of(exclude_cols)), method = c("center", "scale")) # 一键缩放训练集和测试集 train_scaled <- predict(pre_proc, train_df) test_scaled <- predict(pre_proc, test_df)
几个小提醒:
- 如果数据里有NA,记得在计算均值/标准差时加上
na.rm = TRUE,避免出错; - 分类变量、ID列这类确实不需要缩放,排除它们是正确的操作;
- caret的preProcess还支持很多其他预处理方法(比如归一化、PCA、缺失值填充),如果后续有其他需求可以直接扩展。
内容的提问来源于stack exchange,提问作者DeltaIV
相关产品推荐
相关产品推荐

