20

'do.call'を多用して関数呼び出しを生成します。例えば:

myfun <- "rnorm";
myargs <- list(n=10, mean=5);
do.call(myfun, myargs);

ただし、特定のパッケージから明示的に関数を呼び出したい場合があります。たとえばに似ていstats::rnorm(n=10, mean=5)ます。do.callを使用する方法、またはdo.callと同じように動作する関数を作成してこれを機能させる方法はありますか?

myfun <- "stats::rnorm";
myargs <- list(n=10, mean=5);
do.call(myfun, myargs);
4

3 に答える 3

23

「stats::rnorm」という関数はありません。rnorm「stats」名前空間で関数を見つける必要があります。

myfun <- get("rnorm", asNamespace("stats"))
myargs <- list(n=10, mean=5);
do.call(myfun, myargs);

もちろん、「stats::rnorm」のような名前から名前空間部分と関数名に分割することもできます。

funname <- "stats::rnorm"
fn <- strsplit(funname, "::")[[1]]
myfun <- if (length(fn)==1) fn[[1]] else get(fn[[2]], asNamespace(fn[[1]]))
myargs <- list(n=10, mean=5);
do.call(myfun, myargs);

更新このアプローチが@Jeroenのアプローチよりも2.5倍高速であることを示したかっただけです...

do.call.tommy <- function(what, args, ...) {
  if(is.character(what)){
    fn <- strsplit(what, "::")[[1]]
    what <- if(length(fn)==1) {
        get(fn[[1]], envir=parent.frame(), mode="function")
    } else {
        get(fn[[2]], envir=asNamespace(fn[[1]]), mode="function")
    }
  }

  do.call(what, as.list(args), ...)
}

# Test it
do.call.tommy(runif, 10)
f1 <- function(FUN) do.call.tommy(FUN, list(5))
f2 <- function() { myfun<-function(x) x; do.call.tommy(myfun, list(5)) }
f1(runif)
f1("stats::runif")
f2()

# Test the performance...    
system.time(for(i in 1:1e4) do.call.jeroen("stats::runif", list(n=1, max=50))) # 1.07 secs
system.time(for(i in 1:1e4) do.call.tommy("stats::runif", list(n=1, max=50)))  # 0.42 secs
于 2012-04-05T03:58:25.347 に答える
16

引用符は削除できます。名前ではなく、関数自体になります。

myfun <- stats::rnorm
myargs <- list(n=10, mean=5)
do.call(myfun, myargs)
于 2012-04-05T04:02:30.843 に答える
0

回答ありがとうございます。私はこのようなものに行くと思います:

do.call.jeroen <- function(what, args, ...){
  if(is.function(what)){
    what <- deparse(as.list(match.call())$what);
  }
  myfuncall <- parse(text=what)[[1]];
  mycall <- as.call(c(list(myfuncall), args));
  eval(mycall, ...);
}

do.callこれは、引数として文字列を渡すことができるように、適切に一般化されているように思えますがwhat、呼び出しをきちんとエミュレートしstats::rnorm(n=10, mean=5)ます。

myfun1 <- "rnorm";
myfun2 <- "stats::rnorm";
myargs <- list(n=10, mean=5);
do.call.jeroen(myfun1, myargs);
do.call.jeroen(myfun2, myargs);
do.call.jeroen(rnorm, myargs);
do.call.jeroen(stats::rnorm, myargs);

これの良い点の 1 つは、呼び出している関数が match.call() を使用して呼び出しをどこかに保存する場合、実際の関数名が保持されることです。例えば:

do.call.jeroen("stats::glm", list(formula=speed~dist, data=as.name('cars')))

Call:  stats::glm(formula = speed ~ dist, data = cars)

Coefficients:
(Intercept)         dist  
     8.2839       0.1656  

Degrees of Freedom: 49 Total (i.e. Null);  48 Residual
Null Deviance:      1370 
Residual Deviance: 478  AIC: 260.8 
于 2012-04-05T23:36:53.473 に答える