在R中高效对数据框多选定列执行Mutate批量操作
批量生成中心化、组内均值及组内中心化列的高效实现
问题描述
现有如下示例数据框:
example <- data.frame( ID_A = c(1101, 1101, 1102, 1102, 1103, 1103), ID_B = c(2101, 2101, 2102, 2102, 2103, 2103), A = c(1,2,3,1,2,3), B = c(2,2,3,2,2,3), C = c(3,2,3,3,2,3) )
需要针对A、B、C三列批量执行以下操作:
- 生成后缀为
.c的中心化列:使用scale(..., scale = FALSE)处理原列 - 生成后缀为
.cb的组内均值列:按ID_A分组,计算对应.c列的均值 - 生成后缀为
.cw的组内中心化列:用.c列减去对应的.cb列
已手动实现单列(C列)的操作,但需要高效的批量处理方案。期望输出结果如下:
example_solution <- data.frame( ID_A = c(1101, 1101, 1102, 1102, 1103, 1103), ID_B = c(2101, 2101, 2102, 2102, 2103, 2103), A = c(1,2,3,1,2,3), B = c(2,2,3,2,2,3), C = c(3,2,3,3,2,3), A.c = c(-1, 0, 1, -1, 0, 1), A.cb = c(-0.5, -0.5, 0.0, 0.0, 0.5, 0.5), A.cw = c(-0.5, 0.5, 1.0, -1.0, -0.5, 0.5), B.c = c(-0.3333333, -0.3333333, 0.6666667, -0.3333333, -0.3333333, 0.6666667), B.cb = c(-0.3333333, -0.3333333, 0.1666667, 0.1666667, 0.1666667, 0.1666667), B.cw = c(0.0, 0.0, 0.5, -0.5, -0.5, 0.5), C.c = c(0.3333333, -0.6666667, 0.3333333, 0.3333333, -0.6666667, 0.3333333), C.cb = c(-0.1666667, -0.1666667, 0.3333333, 0.3333333, -0.1666667, -0.1666667), C.cw = c(0.5, -0.5, 0.0, 0.0, -0.5, 0.5) )
解决方案
利用dplyr的across函数可以高效实现批量处理,无需重复编写单列逻辑,以下提供两种实现方式:
方法1:链式调用一次性完成
library(dplyr) library(stringr) example_processed <- example %>% # 生成.c中心化列 mutate(across(c(A, B, C), ~scale(., scale = FALSE), .names = "{.col}.c")) %>% # 按ID_A分组,生成.cb组内均值列 group_by(ID_A) %>% mutate(across(ends_with(".c"), ~mean(., na.rm = TRUE), .names = "{.col}b")) %>% # 生成.cw列(.c - .cb) mutate(across(ends_with(".c"), ~.x - get(str_replace(cur_column(), ".c$", ".cb")), .names = "{.col}w")) %>% ungroup()
方法2:拆分步骤更直观
如果希望逻辑更清晰,可以拆分操作步骤:
library(dplyr) library(stringr) # 1. 生成中心化列 example_processed <- example %>% mutate(across(c(A, B, C), ~scale(., scale = FALSE), .names = "{.col}.c")) # 2. 计算组内均值列 example_processed <- example_processed %>% group_by(ID_A) %>% mutate(across(ends_with(".c"), ~mean(., na.rm = TRUE), .names = "{.col}b")) %>% ungroup() # 3. 计算组内中心化列 example_processed <- example_processed %>% mutate(across(ends_with(".c"), ~.x - get(str_replace(cur_column(), "\\.c$", ".cb")), .names = "{.col}w"))
代码说明
across(c(A, B, C), ...):指定要批量处理的目标列集合.names = "{.col}.c":通过原列名拼接后缀自动生成新列名ends_with(".c"):筛选所有以.c结尾的列,避免重复指定列名str_replace(cur_column(), ".c$", ".cb"):动态匹配对应.cb列的名称,实现.c与.cb的对应运算
执行上述代码后,example_processed的结果与example_solution完全一致。
内容的提问来源于stack exchange,提问作者jo_
相关产品推荐
相关产品推荐

