为什么expand.grid比data.table';她是CJ?

为什么expand.grid比data.table';她是CJ?,r,data.table,R,Data.table,Mnel的猜测是对的。CJ返回一个data.table,其中每列都是一个键 > system.time(expand.grid(1:1000,1:10000)) user system elapsed 1.65 0.34 2.03 > system.time(CJ(1:1000,1:10000)) user system elapsed 3.48 0.32 3.79 它慢的真正原因是它没有关注CJ的默认用法:当参数向量满足

Mnel的猜测是对的。CJ返回一个data.table,其中每列都是一个键

> system.time(expand.grid(1:1000,1:10000))
   user  system elapsed 
   1.65    0.34    2.03 
> system.time(CJ(1:1000,1:10000))
   user  system elapsed 
   3.48    0.32    3.79 

它慢的真正原因是它没有关注CJ的默认用法:当参数向量满足
anyDuplicated(vector)==F

也许其他人使用CJ的方式有所不同,但对于唯一向量,还有改进的余地:

速度比较
单位:毫秒
expr最小lq中值uq最大neval

dt1感谢您的报告。这已在数据表1.8.9中修复。下面是最新提交(913)的计时测试:

发件人:

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


还可以查看新闻,了解其他值得注意的功能,这些功能已经发布并修复了bug;e、 例如,
CJ()
也会获得一个新的
排序的
参数。

可能是因为它在结果数据上设置了键。tablegood point。我会回答我自己的问题。
CJ
传递排序向量时可能会更快。谢谢你的提醒。“现在已经存档了。@迈克尔,我想最好的答案是我的更新,这个问题已经解决了。如果你能改变这一点,这样未来的用户就不会因为没有被修复而误解这一点,那将是非常好的。谢谢。+1将改善CJ,即使如此;问题评论中的FR链接。顺便说一句,
as.data.table
应该比
data.table
快。公平地说,您在第二行中看到的差异来自
data.table()
开销。如果您查看Matthew的建议,您将看到expand.grid,即使转换为data.table,仍然是fastsn的两倍。没有
key
as.data.table()
fastCJ(a,b,c)中的错误:找不到对象“seq_list”
a清理版本(由@Arun牵头)已替换R-Forge上data.table中的“CJ”,所以我会去那里,或者等待它。功能要求:
> DT <- CJ(1:100,1:100)
> key(DT)
[1] "V1" "V2"
> system.time(CJ(1:1000,1:10000))
   user  system elapsed 
   3.40    0.25    3.73 
> system.time(data.table(expand.grid(1:1000,1:10000),key=c("Var1","Var2")))
   user  system elapsed 
   4.14    0.68    4.90 
Unit: milliseconds
                  expr        min         lq     median         uq        max neval
    dt1 <- CJ(a, b, c) 2394.38929 2434.75660 2439.14362 2444.66607 2686.41990   100
dt2 <- fastCJ(a, b, c)   18.83701   25.33339   25.51254   25.70966   27.60622   100
Output identical: TRUE
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(...) {
  l <- lapply(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(seq_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))
system.time(expand.grid(1:1000,1:10000))
# user system elapsed
# 1.420 0.552 1.987

system.time(CJ(1:1000,1:10000))
# user system elapsed
# 0.080 0.092 0.171