在R

时间:2018-02-22 17:02:42

标签: r loops purrr

R中的

for循环通常被认为是缓慢的:很难避免意外的内存读/写。但是如何替换嵌套的for循环呢?哪种方法最好?

请注意,这是一个通用问题:下面的f函数只是一个示例,它可能更复杂或返回不同的对象。我只是想看看R中可以采用的所有不同方法,以避免嵌套for循环。

以此为例:

al <- c(2,3,4)
bl <- c("foo", "bar")
f <- function(n, c) { #Just one simple example function, could be much more complicated
    data.frame(n=n, c=c, val=n*nchar(c))
}
d <- data.frame()
for (a in al) { 
    for (b in bl) {
        d <- rbind(d, f(a, b))
        #one could undoubtedly do this a lot better
        #even keeping to nested for loops
    }
}

有人可以用这种绝对可怕的方式取而代之(以此为例):

eg <- expand.grid(al, bl)
d <- do.call(rbind,
    lapply(1:dim(eg)[1],
           function(i) {f(as.numeric(eg[i,1]), as.character(eg[i, 2]))}
           )
)

或使用library(purrr),这有点不那么优雅:

d <- map_dfr(bl, function(b) map2_dfr(al, b, f))

......有无数不同的方法。哪一个最简单,哪一个最快?

以下是对笔记本电脑上前三种方法的性能的快速评估: enter image description here

2 个答案:

答案 0 :(得分:1)

只需使用expand.gridnchar进行矢量化即可。无需forapply个循环:

eg <- expand.grid(c=bl, n=al, stringsAsFactors = FALSE)
eg$val <- eg$n * nchar(eg$c)

# RE-ORDER COLUMNS
eg <- eg[c("n", "c", "val")]

transform的单行:

eg <- transform(expand.grid(c=bl, n=al, stringsAsFactors = FALSE),
                val=n * nchar(c))[c("n", "c", "val")]

如果您在 f 功能中设置stringsAsFactors = FALSE

f <- function(n, c) {
  data.frame(n=n, c=c, val=n*nchar(c), stringsAsFactors = FALSE)
}

输出相当于for循环数据帧:

all.equal(d, eg)
# [1] TRUE

答案 1 :(得分:0)

n=rep(al,length(bl));e=rep(bl,length(al))
> cbind.data.frame(n,c=e,val=mapply(function(x,y)x*nchar(y),n,e))
  n   c val
1 2 foo   6
2 3 bar   9
3 4 foo  12
4 2 bar   6
5 3 foo   9
6 4 bar  12

或:

n=rep(al,length(bl));e=rep(bl,length(al))
cbind.data.frame(n,c=e,val=c(outer(al,bl,function(x,y)x*nchar(y))))
  n   c val
1 2 foo   6
2 3 bar   9
3 4 foo  12
4 2 bar   6
5 3 foo   9
6 4 bar  12