如何根据外部列向量过滤 R 数据表

How to filter R datatable based on external column vector

我有兴趣将 R 数据表过滤为 select 对应的行元素 到数字列的列表。

举个例子,假设我有:

DT<- data.table(a=c(1,2,3),b=c(4,5,6),c=c(7,8,9))

这给出了,

   a b c
1: 1 4 7
2: 2 5 8
3: 3 6 9

现在,我有一个名为 select 的外部向量,其中包含我想要 select 对应于行的列。

select <- c(2,3,1)

我想 return 一个新的数据表,每行值对应于 selected 列。

DTnew 
1: 4
2: 8
3: 3

如果我尝试类似 DT[,.SD[select]] 的操作,它 return 是一个新数据表,其中的整行对应于 select 列表。

> DT[,.SD[select]]
   a b c
1: 2 5 8
2: 3 6 9
3: 1 4 7

我怎样才能完成这个任务?

编辑:我没有说清楚,但是结果需要保留数据表行的原始顺序,因为它是一个基于时间序列的对象(我省略了ts索引以使问题更简单)。

更新 2:一些已发布解决方案的计时结果(使用数据表方法似乎在系统时间上要快得多,不确定如何总结用户和经过的结果 time/overhead,但我也想与整个过程都是数据表。我想我也应该问一下,当速度优先时,DT 用户来回进行基于矩阵的计算是否很常见。

library(data.table)
library(microbenchmark)

set.seed(123)

DT <- data.table(matrix(rnorm(10e3*10e3),nrow=10e3,ncol=10e3))
select<-sample(10e3,replace=FALSE)

op <- microbenchmark(
sol1 <- function(DT,select) DT[, V1 := .SD[[select]], by = select]$V1,

sol2 <- function(DT,select) {
x <- as.matrix(DT)
x[cbind(1:nrow(x), select)]
},

times=1000L)

Warning message:
In microbenchmark(sol1 <- function(DT, select) DT[, `:=`(V1, .SD[[select]]),  :
  Could not measure a positive execution time for 1019 evaluations.


> identical(sol1(DT,select),sol2(DT,select))
[1] TRUE
> op
Unit: nanoseconds
                                                                                    expr min lq   mean median uq   max neval cld
              sol1 <- function(DT, select) DT[, `:=`(V1, .SD[[select]]), by = select]$V1   0  0 25.136      0  1  9837  1000   a
 sol2 <- function(DT, select) {     x <- as.matrix(DT)     x[cbind(1:nrow(x), select)] }   0  0 52.477      0  1 39345  1000   a

方法二:

> system.time(replicate(10,sol1(DT,select)))
   user  system elapsed 
  64.07    0.25   64.33 
> system.time(replicate(10,sol2(DT,select)))
   user  system elapsed 
   4.97    2.25    7.22 

您可以使用矩阵索引对矩阵执行此操作:

x <- as.matrix(DT)
x[cbind(1:nrow(x), select)]
## [1] 4 8 3

如果您从数据框开始,您也可以使用矩阵对其进行索引:

x <- data.frame(a=c(1,2,3),b=c(4,5,6),c=c(7,8,9)) # or as.data.frame(DT)
x[cbind(1:nrow(x), select)]
## [1] 4 8 3

还有几个选项:

# extended example
DT       <- rbind(DT,DT)
select   <- c(select,rev(select))
expected <- c(4,8,3,1,8,6)

# create a new column with by
DT[, V1 := .SD[[select]], by = select]$V1

# or use ave
ave( seq(nrow(DT)), select, FUN = function(ii) DT[[ select[ii][1] ]][ii] )    

它们基本上都在做同样的事情:对于select中的每个值v,抓取相应的向量,DT[[v]];并将其子集化到 select==v.

的位置