使用outer而不是expand.grid

时间:2012-05-01 23:10:49

标签: r

我正在寻找尽可能快的速度并坚持做expand.grid所做的事情。我过去曾使用outer用于类似的目的来创建一个向量;像这样的东西:

v <- outer(letters, LETTERS, paste0)
unlist(v[lower.tri(v)])

基准测试表明,outer可能比expand.grid快得多,但这次我想创建两列,就像expand.grid(所有可能的2个向量组合)但我的方法与outer outer这个时间的外部基准测试速度不快。

我希望采用2个向量并尽可能快地创建每个可能的组合作为两列(我认为expand.grid可能是路线,但对任何基本方法都是开放的。

以下是outer方法和dat <- cbind(mtcars, mtcars, mtcars) expand.grid(seq_len(nrow(dat)), seq_len(ncol(dat))) FOO <- function(x, y) paste(x, y, sep=":") x <- outer(seq_len(nrow(dat)), seq_len(ncol(dat)), FOO) apply(do.call("rbind", strsplit(x, ":")), 2, as.integer) 方法。

outer

微基准测试显示# expr min lq median uq max # EXPAND.G 812.743 838.6375 894.6245 927.7505 27029.54 # OUTER 5107.871 5198.3835 5329.4860 5605.2215 27559.08 较慢:

outer

我认为我的outer使用速度很慢,因为我不知道如何使用do.call('rbind'直接创建一个长度为2的向量,我可以paste一起使用。我必须放慢outer并缓慢分裂。如何使用base(或expand grid中的其他方法)以比Unit: microseconds expr min lq median uq max 1 ERNEST 34.993 39.1920 52.255 57.854 29170.705 2 JOHN 13.997 16.3300 19.130 23.329 266.872 3 ORIGINAL 352.720 372.7815 392.377 418.738 36519.952 4 TOMMY 16.330 19.5960 23.795 27.061 6217.374 5 VINCENT 377.447 400.3090 418.505 451.864 43567.334 更快的方式执行此操作?

修改: 添加微基准测试结果。

**

{{1}}

**

enter image description here

4 个答案:

答案 0 :(得分:15)

rep.int的文档不太完整。在最常见的情况下,它不仅是最快的,因为您可以为times参数传递向量,就像使用rep一样。对于这两个序列,你可以直接使用它,比Tommy的时间缩短40%左右。

expand.grid.jc <- function(seq1,seq2) {
    cbind(Var1 = rep.int(seq1, length(seq2)), 
    Var2 = rep.int(seq2, rep.int(length(seq1),length(seq2))))
}

答案 1 :(得分:13)

使用rep.int

expand.grid.alt <- function(seq1,seq2) {
  cbind(rep.int(seq1, length(seq2)),
        c(t(matrix(rep.int(seq2, length(seq1)), nrow=length(seq2)))))
}

expand.grid.alt(seq_len(nrow(dat)), seq_len(ncol(dat)))

在我的电脑中,它比expand.grid快6倍。

答案 2 :(得分:4)

@ErnestA有一个很好的解决方案,非常值得回答!

......虽然可能会略微加快:

expand.grid.alt2 <- function(seq1,seq2) {
  cbind(Var1=rep.int(seq1, length(seq2)), Var2=rep(seq2, each=length(seq1)))
}

s1=seq_len(2000); s2=seq_len(2000)
system.time( for(i in 1:10) expand.grid.alt2(s1, s2) ) # 1.58
system.time( for(i in 1:10) expand.grid.alt(s1, s2) )  # 1.75
system.time( for(i in 1:10) expand.grid(s1, s2) )      # 2.46

答案 3 :(得分:3)

您可以单独创建两列。

library(microbenchmark)
n <- nrow(dat)
m <- ncol(dat)
f1 <- function()   expand.grid(1:n, 1:m)
f2 <- function()   
  data.frame( 
    Var1 = as.vector(outer( 1:n, rep(1,m) )),
    Var2 = as.vector(outer( rep(1,n), 1:m ))
  )
microbenchmark( f1, f2, times=1e6 )
# Unit: nanoseconds
#   expr min  lq median  uq    max
# 1   f1  70 489    490 559 168458
# 2   f2  70 489    490 559 168597