data.table的CJ应该继续适应具有重复元素的参数吗?

gar*_*org 5 r data.table

(编辑:@Arun清理并修复了下面的代码,并在R-Forge的data.table中替换了'CJ'.功能请求:#4849;更快的CJ 和更新为什么expand.grid比data.table快? CJ?)

在我看来CJ,意味着研究满足的论证向量anyDuplicated(vector) == F.

有没有人用非独特的参数?

如果是这样,是否值得在我认为主要用途的100倍速度上进行平衡?

通过调整主要用途来降低速度的下限(这些样本参数的下限,而不是任何参数的下限):

比较:

Unit: milliseconds
                  expr        min         lq     median         uq      max neval
    dt1 <- CJ(a, b, c) 3149.15293 3166.59638 3204.95956 3472.70826 4414.919   100
dt2 <- fastCJ(a, b, c)   22.85207   23.16003   23.43691   24.04215 1208.855   100
Output identical: TRUE
Run Code Online (Sandbox Code Playgroud)

码:

library(microbenchmark)
library(data.table)

repTE <- function(x, times, each) {
  rep.int(rep.int(x, times=rep.int(each, times=length(x))), times=times)
}
fastCJ <- function(...) {
  arg_list <- list(...)
  l <- lapply(arg_list, sort.int, method="quick")
  seq_ct <- length(l)
  if (seq_ct > 1) {
    seq_lens <- vapply(l, length, numeric(1))
    tot_len <- prod(seq_lens)

    l <-lapply(
      seq_len(seq_ct),
      function(i) {
        if (i==1) {
          len <- seq_lens[1]
          rep.int(l[[1]], times=rep.int(tot_len/len, len))
        } else if (i < seq_ct) {
          pre_len <- prod(seq_lens[1:(i - 1)])
          repTE(l[[i]], times=pre_len, each=tot_len/pre_len/seq_lens[i])
        } else {
          rep.int(l[[seq_ct]], times=tot_len/seq_lens[seq_ct])
        }
      }
    )    
  } else {
    tot_len <- length(l[[1]])
  }

  setattr(l, "row.names", .set_row_names(tot_len))
  setattr(l, "class", c("data.table", "data.frame"))
  if (is.null(names <- names(arg_list))) {
    names <- vector("character", seq_ct)
  }
  if (any(tt <- names == "")) {
    names[tt] <- paste0("V", which(tt))
  }
  setattr(l, "names", names)
  data.table:::settruelength(l, 0L)
  l <- alloc.col(l)
  setattr(l, "sorted", names(l))

  return(l)
}

a <- factor(sample(1:1000, 1000))
b <- sample(letters, 26)
c <- runif(100)
print(microbenchmark( dt1 <- CJ(a, b, c), dt2 <- fastCJ(a, b, c)))
cat("Output identical:", identical(dt1, dt2))
Run Code Online (Sandbox Code Playgroud)

Mat*_*wle 1

为了完整起见,添加来自NEWS 的答案:

CJ() 在 1e6 行上速度提高了 90%(例如),#4849。现在,输入首先在组合之前而不是组合之后进行排序,并使用rep.int而不是rep(感谢 Sean Garborg 的想法、代码和基准),并且仅在 is.unsorted() 时才排序,#2321。

提醒:CJ = 交叉连接;即,连接其输入的所有组合。