我经常使用'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);发布于 2012-04-05 11:58:25
没有名为"stats::rnorm“的函数。您必须在"stats“名称空间中找到rnorm函数:
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-05 12:02:31
您可以删除引号:这将是函数本身,而不是它的名称。
myfun <- stats::rnorm
myargs <- list(n=10, mean=5)
do.call(myfun, myargs)发布于 2012-04-06 07:36:53
感谢您的回复。我想我想要这样的东西:
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);这样做的一个好处是,如果我调用的函数使用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 https://stackoverflow.com/questions/10022436
复制相似问题