Ale*_*son 4 optimization for-loop r
我需要区分两个向量的任意两个元素.如果A<-c(1,2)和B<-c(3,4)那么我的结果R应该是c(3-1,3-2,4-1,4-2).
有了这个片段
myfunction <- function(N)
{
A = runif(N)
B = runif(N)
R = c()
for(a in A){
for(b in B){
R=c(b-a,R)
}
}
R
}
print(system.time(result <- myfunction(300)))
Run Code Online (Sandbox Code Playgroud)
我得到这个时间
user system elapsed
14.27 0.01 14.39
Run Code Online (Sandbox Code Playgroud)
有没有更快的方法呢?
最快的基础解决方案是使用outer:
as.vector(outer(B,A,"-"))
Run Code Online (Sandbox Code Playgroud)
令我惊讶的map2_dbl是,实际上比outer以下快一点:
不出我的意料,map2_dbl似乎更快,但那是因为它没有计算A和B中每个值的组合:
test elapsed relative
3 CP(A, B) 7.54 47.125 # using expand.grid
2 JL(A, B) 0.16 1.000 # using map2_dbl
1 JM(A, B) 3.13 19.563 # using outer
Run Code Online (Sandbox Code Playgroud)
但:
> A <- 1:3
> B <- 3:1
> JL(A,B)
[1] -2 0 2
> JM(A,B)
[1] 2 1 0 1 0 -1 0 -1 -2
Run Code Online (Sandbox Code Playgroud)
这是两个长度为1000的向量,并且有100个重复.我没有包含你自己的解决方案,因为有两个原因,这个解决方案非常缓慢:
forR中的循环比过去快得多,但仍然不如使用循环编码C或等效的函数那样最优.这是测试代码中使用的函数的情况.R变成一个更大的值,所以R必须在内存中寻找一个新的位置来存储它.这实际上是代码中最大的瓶颈.尽量避免使用这种构造,因为它是代码速度极慢的最重要原因之一.基准代码:
library(tidyverse)
JM <- function(A,B){
as.vector(outer(B,A,"-"))
}
JL <- function(A,B){
map2_dbl(.x = A,
.y = B,
.f = ~ c(.x - .y))
}
CP <- function(A,B){
as.data.frame(expand.grid(A,B)) %>%
mutate(Var3 = Var2-Var1)
}
library(rbenchmark)
A <- runif(1000)
B <- runif(1000)
benchmark(JM(A,B),
JL(A,B),
CP(A,B),
replications = 100,
columns = c("test","elapsed","relative"))
Run Code Online (Sandbox Code Playgroud)