使用字符串在dplyr(或base R)中选择每行的列

5

我有一列填满了其他列的名称。我想获取每个列名中的值。

# three columns with values and one "key" column
library(dplyr)
data = data.frame(
  x = runif(10),
  y = runif(10),
  z = runif(10),
  key = sample(c('x', 'y', 'z'), 10, replace=TRUE)
)

# now get the value named in 'key'
data = data %>% mutate(value = VALUE_AT_COLUMN(key))

我相信答案与惰性求值版本的mutate有关,但是我却无法理解。

任何帮助都将不胜感激。


1
你也可以尝试使用 data[c("x", "y", "z")][cbind(seq_len(nrow(data)), match(data$key, names(data)))] 来避免对每一行进行分组(代价可能更低,但需要进行中间转换为“矩阵”)。 - alexis_laz
@alexis_laz 我更倾向于一种更可扩展的方法,不需要列出每一列。 - sharoz
1
根据列的排序方式,有很多编程方法可以提取所需的列;例如 data[1:3]data[unique(data$key)]data[!names(data) %in% "key"] 等。 - alexis_laz
那么,我现在有点困惑。你不再需要一个dplyr的解决方案了吗? - akrun
一个dplyr的解决方案会很理想,但我通常尽量避免需要另一个数据框架库。所以基本的R也可以。如果这样说让你感到困惑,我很抱歉。 - sharoz
4个回答

6
我们可以尝试使用 data.table。将 'data.frame' 转换为 'data.table' (setDT(data)),按行序分组,使用.SD来选择由 'key' 指定的列。
 library(data.table)
 setDT(data)[,  .SD[, key[[1L]], with=FALSE] ,1:nrow(data)]

另一个选项是,在按行序列分组后,将“key”转换为字符类(因为它是factor),然后使用get

 setDT(data)[, get(as.character(key)), 1:nrow(data)]

这里有一种使用 do 的选项

 library(dplyr)
 data %>% 
    group_by(rn = row_number()) %>%
    do(data.frame(., value= .[[.$key]]))

我可以使用其他库来完成这个任务,但我想避免需要导入另一个数据框架库。 - sharoz
@sharoz 使用 dplyr 中的 do 是可以实现的。 - akrun
2
你能把那个发表为一个答案吗? - sharoz
@sharoz发布了do选项。 - akrun

5

以下是基于 R 语言的解决方案:

data$value = diag(as.matrix(data[,data$key]))

1
有趣,不过我猜这并不是内存高效的。 - alexis_laz
2
不行!可能有更节省内存的基本方法,但如果你追求性能,那么你应该考虑使用data.tabledplyr。如果你不想加载更多的包并且你的数据不是非常庞大,那么这个方法也可以。 - Sam Dickson

5
为了实现内存高效和快速处理,您应该通过以下方式使用join来更新原始data.table:
data[.(key2 = unique(key)), val := get(key2), on=c(key="key2"), by=.EACHI][]

对于每个key2,计算data $ key中匹配行。这些行将使用包含在key2中的列的值进行更新。例如,key2 =“x”与行1,2,6,8,10相匹配。 data $ x [c(1,2,6,8,10)]是相应的值。by = .EACHI 确保对key2的每个值执行表达式get(key2)
由于此操作仅针对唯一值进行,因此应该比逐行运行快得多。而且,由于数据表是通过引用更新的,因此它应该非常高效(这也有助于提高速度)。

4

我感觉应该有一个基于R的解决方案,但我最好的办法是使用tidyr,先将数据转换为宽格式,然后筛选出符合所需键的观测值。

data %>%
  add_rownames("index") %>%
  gather(var, value, -index, -key) %>%
  filter(key == var)

一个几乎可行的基于R语言的解决方案:
data[cbind(seq_along(data$key), data$key)]

对于给定的数据,它可以工作,但因为它使用矩阵,所以存在两个严重的问题。其一是因为它只是强制性地进行了拆分,并通过因子水平而不是列名选择列,所以因子的顺序很重要。另一个问题是生成的输出为字符型而非数字型,因为在转换为矩阵时,由于关键列,会选择字符型。关键问题在于没有与矩阵行为类似的data.frame模拟。
当通过“[”索引数组时,“i”可以是具有与“x”的维数相同的列数的矩阵;然后结果是一个向量,其元素对应于“i”的每一行中的索引集合。
考虑到这些问题,我可能会选择tidyr解决方案,因为可变选择列意味着它们可能代表同一可观察单位的不同观测。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接