R语言基于列名模式对数据框列执行计算的实现方法
基于列名模式匹配批量计算数据框列的R风格实现
针对需要按列名匹配规则批量对列配对做计算的场景,以下两种写法比原始嵌套循环更符合R编程习惯,可读性和可维护性更高。
原始参考代码
df <- data.frame(xA1 = sample(x = 1:4, size = 10, replace = TRUE), yA1 = sample(x = 1:4, size = 10, replace = TRUE), xA2 = sample(x = 1:4, size = 10, replace = TRUE), yA2 = sample(x = 1:4, size = 10, replace = TRUE), xB1 = sample(x = 1:4, size = 10, replace = TRUE), yB1 = sample(x = 1:4, size = 10, replace = TRUE), xB2 = sample(x = 1:4, size = 10, replace = TRUE), yB2 = sample(x = 1:4, size = 10, replace = TRUE)) # 原始实现:双层for循环+逐行apply for (middle in c('A', 'B')) { for (right in 1:2) { df[paste0(middle, right)] <- apply(X = subset(df, select = c(paste0('x', middle, right), paste0('y', middle, right))), MARGIN = 1, FUN = weighted.mean, w = c(0.25, 0.75)) } }
优化实现方案
方案1:tidyverse 实现(可读性优先推荐)
用dplyr的列选择语法直接匹配列名模式,不需要手动拼接列名写嵌套循环,管道操作逻辑清晰,后续新增列分组时不需要修改核心计算逻辑:
library(dplyr) # 固定随机种子方便复现结果 set.seed(123) df <- tibble(xA1 = sample(x = 1:4, size = 10, replace = TRUE), yA1 = sample(x = 1:4, size = 10, replace = TRUE), xA2 = sample(x = 1:4, size = 10, replace = TRUE), yA2 = sample(x = 1:4, size = 10, replace = TRUE), xB1 = sample(x = 1:4, size = 10, replace = TRUE), yB1 = sample(x = 1:4, size = 10, replace = TRUE), xB2 = sample(x = 1:4, size = 10, replace = TRUE), yB2 = sample(x = 1:4, size = 10, replace = TRUE)) df <- df %>% mutate( across( .cols = starts_with("x"), .names = "{sub('^x', '', .col)}", ~ 0.25 * .x + 0.75 * cur_data()[[sub("^x", "y", cur_column())]] ) )
代码逻辑说明:
- 用
starts_with("x")选择器自动匹配所有x前缀的列,不需要硬编码A/B、1/2的遍历规则 .names参数自动提取列名后缀作为新列名,不需要手动拼接字符串- 直接用向量运算做加权计算,比逐行
apply效率更高 - 后续如果新增xC1、yC1、xA3、yA3这类列,代码不需要修改就能自动计算对应新列。
方案2:base R 实现(无第三方依赖)
如果不想加载额外包,可以用base R的向量运算实现,同样避免嵌套循环,运行效率更高:
set.seed(123) df <- data.frame(xA1 = sample(x = 1:4, size = 10, replace = TRUE), yA1 = sample(x = 1:4, size = 10, replace = TRUE), xA2 = sample(x = 1:4, size = 10, replace = TRUE), yA2 = sample(x = 1:4, size = 10, replace = TRUE), xB1 = sample(x = 1:4, size = 10, replace = TRUE), yB1 = sample(x = 1:4, size = 10, replace = TRUE), xB2 = sample(x = 1:4, size = 10, replace = TRUE), yB2 = sample(x = 1:4, size = 10, replace = TRUE)) # 自动提取所有x列的后缀 col_suffix <- gsub("^x", "", names(df)[startsWith(names(df), "x")]) # 批量计算加权均值 for(suf in col_suffix){ df[[suf]] <- 0.25 * df[[paste0("x", suf)]] + 0.75 * df[[paste0("y", suf)]] }
注意:原始代码中注释的
weighted.mean(x = c(df$xA1, df$yA1), w = c(0.25, 0.75))是把两列所有值合并为一个向量计算整体加权均值,和逐行计算配对值均值的逻辑不一致,使用时需要根据实际需求选择计算逻辑。
内容的提问来源于stack exchange,提问作者user1
相关产品推荐
相关产品推荐

