使用outer而不是expand.grid

Tyl*_*ker 21 r

我正在寻找尽可能快的速度,并留在基地做什么expand.grid.我过去曾outer用于类似的目的来创建一个向量; 这样的事情:

v <- outer(letters, LETTERS, paste0)
unlist(v[lower.tri(v)])
Run Code Online (Sandbox Code Playgroud)

基准测试表明我outer可以快得多,expand.grid但这次我想创建两个列,就像expand.grid(2个向量的所有可能的组合)一样,但是我的方法outer与外部这个时候没有基准.

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

这是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)
Run Code Online (Sandbox Code Playgroud)

微基准测试显示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
Run Code Online (Sandbox Code Playgroud)

我认为我的outer使用很慢,因为我不知道如何使用outer直接创建一个长度为2的向量,我可以do.call('rbind'在一起.我必须缓慢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
Run Code Online (Sandbox Code Playgroud)

**

在此输入图像描述

Joh*_*ohn 16

文档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))))
}
Run Code Online (Sandbox Code Playgroud)


Ern*_*t A 15

使用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)))
Run Code Online (Sandbox Code Playgroud)

在我的电脑上比它快6倍expand.grid.


Tom*_*mmy 5

@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
Run Code Online (Sandbox Code Playgroud)

  • @TylerRinker可以随意取消我的回答,因为还有其他运行速度更快的解决方案。没问题! (3认同)