我有一个像这样的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中做到这一点?
答案 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