data.table where子句中列的不同组合

时间:2019-01-16 13:06:09

标签: r data.table

我有一个包含1000多个二进制列的data.table,但是一个简单的例子是:

dt <- data.table(one=c(1,1,0), two=c(0,0,1), three=c(1,1,0), four=c(1,1,1))

我想计算预定义列数的每种组合都等于1的次数。因此,例如,如果我想计算每两列之间的“ 1”匹配项,我可以这样做:

a <- combn(names(dt),2)[1,]
b <- combn(names(dt),2)[2,]

for(i in 1:length(a)){
print(c(a[i], b[i], dt[get(a[i])==1 & get(b[i])==1,.N]))
}

我想改变合并的列数,我需要一种有效的方法来实现这一点。

我可以像这样用eval(parse())解决这个问题:

n <- 3 # number of columns to combine

for(i in 1:n){assign(paste0("a", i), combn(names(dt),n)[i,])}

for(i in 1:length(a1)){
  expr1 <- paste0("c(",paste0(rep("a", n), 1:n, "[i]", collapse=","), ")")
  expr2 <- paste0("dt[",paste0("get(",rep("a", n), 1:n, ")", sep=" ==TRUE ", collapse = " & "),",.N]")

  print(c(eval(parse(text=expr1)),  eval(parse(text=expr2))))
}

尽管如此,对上面的简单代码进行的微基准测试表明,get()eval(parse())快5倍。

有效的方法是什么?

2 个答案:

答案 0 :(得分:1)

这是个主意,

sapply(combn(dt, 3, simplify = FALSE), function(i){
                v1 <- sum(rowSums(i) == ncol(i));
                setNames(v1, paste(names(i), collapse = '-'))
               })

# one-two-three   one-two-four one-three-four two-three-four 
#             0              0              2              0 

答案 1 :(得分:1)

将指示的all1用作combn中的函数:

k <- 3
DF <- as.data.frame(dt)
all1 <- combn(names(DF), k, function(x) sum(apply(DF[, x] == 1, 1, all)))
data.frame(t(combn(names(DF), k)), all1)

给予:

   X1    X2    X3 all1
1 one   two three    0
2 one   two  four    0
3 one three  four    2
4 two three  four    0