I am not sure if I use the do.call
the right way:
test <- function(test) {
string <- deparse(substitute(test))
start <- regexpr("\\(", string)
end <- regexpr(")", string) - 1
distribution <- substr(string, 0, start-1)
string.arguments <- substr(string, start+1, end)
v <- read.table(text=unlist(strsplit(string.arguments, ",")))
list.arguments <- lapply(t(v), function(x) x)
for (i in 1:1000000) {
do.call(distribution, list.arguments)
}
}
The goal here is to be able to send a distribution, such as rnorm
and rgamma
, followed by arguments to a function, instead of an evaluated function.
Here is a comparison of using do.call and just simply calling the function:
> system.time(test(rnorm(100, 1, 10)))
user system elapsed
17.772 0.000 17.820
> system.time(for(i in 1:1000000) { rnorm(100,0,1)} )
user system elapsed
13.940 0.004 14.015
The question is twofold:
do.call
is always going to be slower than calling a function directly, because it has to go through your arguments and find the function before calling it. The degree to which it's slower depends on how much additional computation it has in which to amortise this overhead.
> system.time(for(i in 1:1e6) do.call(rnorm, list(100)))
user system elapsed
13.55 0.00 13.58
> system.time(for(i in 1:1e6) rnorm(100))
user system elapsed
11.40 0.00 11.42
whereas:
> system.time(for(i in 1:1e2) do.call(rnorm, list(1e6)))
user system elapsed
9.14 0.00 9.15
> system.time(for(i in 1:1e2) rnorm(1e6))
user system elapsed
9.14 0.00 9.14
In addition, some of your slowdown is due to your regex'ing and other string manipulation which is unrelated to how fast do.call
inherently is. While fast because it's running on trivially small input, it's still needlessly complicated. Why not just do this:
test <- function(distrib, ..., N=1e6)
lapply(seq(N), function(x) distrib(...))
test(rnorm, 100, 1, 10)
or this:
test <- function(call, N=1e6)
{
call <- substitute(call)
lapply(seq(N), function(...) eval.parent(call))
}
test(rnorm(100, 1, 10))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With