根据包含列名的变量从不同列中选择值

时间:2015-10-23 19:37:41

标签: r data.table

我有一个像这样的data.table:

col1   col2   col3  new  
1       4     55    col1 
2       3     44    col2
3       34    35    col2
4       44    87    col3

我想填充另一列matched_value,其中包含new列中相应列名称的值:

col1   col2   col3  new    matched_value
1       4     55    col1        1
2       3     44    col2        3
3       34    35    col2        34
4       44    87    col3        87 

例如,在第一行中,new的值为“col1”,因此matched_value获取col1的值,即{1}。

如何在一个非常大的data.table上有效地在R中做到这一点?

2 个答案:

答案 0 :(得分:11)

使用晦涩的DT[, newval := .SD[[.BY[[1]]]], by=new] col1 col2 col3 new newval 1: 1 4 55 col1 1 2: 2 3 44 col2 3 3: 3 34 35 col2 34 4: 4 44 87 col3 87

的借口
new

工作原理。这会根据newname = .BY[[1]]中的字符串将数据分组。每个组的字符串值存储在.SD中。我们使用此字符串通过.SD[[newname]]选择.SD的相应列。 get(.BY[[1]])代表 D ata的 S ubset。

备选方案。 .SD[[.BY[[1]]]]应该可以替代{{1}}。根据@David运行的基准测试,这两种方式同样快速。

答案 1 :(得分:2)

我们可以match'new'列与数据集的列名称一起获取列索引,cbind与行索引(1:nrow(df1))并提取相应的元素基于行/列索引的数据集。它可以分配给新列。

df1$matched_value <- df1[-4][cbind(1:nrow(df1),match(df1$new, colnames(df1) ))]
df1
#  col1 col2 col3  new matched_value
#1    1    4   55 col1             1
#2    2    3   44 col2             3
#3    3   34   35 col2            34
#4    4   44   87 col3            87

注意:如果OP有data.table,则在子集化时会将一个选项转换为data.frame或使用with=FALSE

 setDF(df1) #to convert to 'data.frame'.

基准

set.seed(45)
df2 <- data.frame(col1= sample(1:9, 20e6, replace=TRUE),
col2= sample(1:20, 20e6, replace=TRUE), 
col3= sample(1:40, 20e6, replace=TRUE),
col4=sample(1:30, 20e6, replace=TRUE),
new= sample(paste0('col', 1:4), 20e6, replace=TRUE), stringsAsFactors=FALSE)
system.time(df2$matched_value <- df2[-5][cbind(1:nrow(df2),match(df2$new, colnames(df2) ))])
#   user  system elapsed 
#  2.54    0.37    2.92