R语言如何无循环实现基于列名的间接索引计算列R?
高效提取DataFrame指定列的对应行值(替代for循环)
需求说明
现有包含A、B、C、D四列数值列,以及存储目标列名的NC列的DataFrame,需要生成列R:每行R的值为该行NC列指定列对应的该行数值。示例如下:
| A | B | C | D | NC | R |
|---|---|---|---|---|---|
| 9 | 5 | 5 | 10 | D | 10 |
| 4 | 10 | 5 | 6 | A | 4 |
示例数据生成代码:
set.seed(1) example <- data.frame(U = seq(10)) example %>% mutate(A = sample(10,10,replace = TRUE), B = sample(10,10,replace = TRUE), C = sample(10,10,replace = TRUE), D= sample(10,10,replace = TRUE), NC = sample(c("A","B","C","D"),10,replace = TRUE)) %>% select(A,B,C,D, NC) -> example
原有for循环实现(性能存在瓶颈):
for(i in 1:dim(example)[1]) { example$R[i] <- example[[example$NC[i]]][i] }
无循环高效实现方案
方案1:Base R矩阵索引法(轻量高效)
利用矩阵索引直接定位取值,是Base R中性能最优的方法之一:
example$R <- example[cbind(seq_len(nrow(example)), match(example$NC, colnames(example)))]
match(example$NC, colnames(example)):将NC列的列名转换为对应的列索引cbind:把行索引和列索引组合成矩阵,直接提取对应位置的数值
方案2:dplyr行操作法(tidy风格)
用dplyr的行操作函数实现,符合tidyverse语法习惯:
library(dplyr) example <- example %>% rowwise() %>% mutate(R = pick(all_of(NC)) %>% pull()) %>% ungroup()
rowwise():让后续操作按行执行pick(all_of(NC)):选中当前行NC指定的列pull():提取选中列的数值
方案3:purrr遍历法(简洁直观)
借助purrr的映射函数替代循环,代码更简洁:
library(purrr) example$R <- map2_dbl(seq_len(nrow(example)), example$NC, ~ example[[.y]][.x])
map2_dbl:同时遍历行索引和NC列的列名,逐个提取对应值并返回数值向量
方案4:data.table大数据最优解
如果处理超大数据集,data.table的性能优势显著:
library(data.table) setDT(example) example[, R := .SD[[NC]], by = .I]
setDT(example):将DataFrame转换为data.table格式by = .I:按行分组,.SD代表当前行的数据集,直接提取NC指定列的值
内容的提问来源于stack exchange,提问作者olivier
相关产品推荐
相关产品推荐

