R 根据包含列名的变量从不同列中选择值
我有一个data.table,如下所示:R 根据包含列名的变量从不同列中选择值,r,data.table,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 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_值
从col1
中取值,即1
如何在R中对一个非常大的数据表有效地执行此操作?我们可以将“新”列与数据集的列名进行匹配,以获得列索引,
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
基准
set.seed(45)
df2使用晦涩的.BY
的借口:
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[[newname]]
选择.SD
的相应列.SD
代表S数据集Data
替代品get(.BY[[1]])
应该可以替代.SD[.BY[[1]]]]
。根据@David运行的一个基准测试,这两种方法同样快。您能给出一个等效的数据表语法吗?还有,它会很快吗?我有一个非常大的数据集,大约有2000万行。@user3664020行/列索引速度很快,但是cbind
ing可能是一个瓶颈。你有多少列?5列。这是数据表。可能使用fastmatch
?大概new
是一个因素,所以真正需要的是transform(dat,val=dat[cbind(1:nrow(dat),new)])
。非常快看起来像其他语言。它是如何工作的?等待解释!谢谢+1因为这个解决方案比我的dt[,matched_value:=as.integer(get(new)),by=1:nrow(dt)]
解决方案快。@David我想get
可能也一样快(也许更快?)。如果你做了get(.by[[1]],by=new
@Frank出于好奇,我已经测试了get(.by[[1]])和.SD[.by[[1]]
在10^6行上使用系统时间。这两者在时间上是无法区分的。@Frank请注意,在2020年,.SD[.BY[[1]]]]]
似乎不再适用于指示找不到.SD
的消息。幸运的是,get(.BY[[1]])
继续工作!
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
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