首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >R中的匹配函数: match.fun对偏差(替代())与“直接”提供函数

R中的匹配函数: match.fun对偏差(替代())与“直接”提供函数
EN

Stack Overflow用户
提问于 2021-11-26 19:45:01
回答 2查看 149关注 0票数 0

fun1fun2fun3似乎如出一辙:

代码语言:javascript
运行
复制
fun1 <- function(fun, x) {
  fun(x)
}

fun1(mean, 1:10)
fun1(as.character, 1:10)
fun1(notafun, 1:10)

fun2 <- function(fun, x) {
  fun <- match.fun(fun)
  fun(x)
}

fun2(mean, 1:10)
fun2(as.character, 1:10)
fun2(notafun, 1:10)

fun3 <- function(fun, x) {
  fun <- deparse(substitute(fun))
  do.call(fun, list(x))
}

fun3(mean, 1:10)
fun3(as.character, 1:10)
fun3(notafun, 1:10)

一般情况下,有一种策略是可取的吗?到目前为止,我只注意到如果将match.fun指定为字符串,fun也可以工作。

我的用例是包中用于本地使用的非导出函数(如果不能将fun指定为字符串,它不是一个限制)。使用match.fun而不是“直接”提供函数有什么好处(如在fun1中)。

EN

Stack Overflow用户

回答已采纳

发布于 2021-11-27 05:25:21

首先是文件!以下是?match.fun的相关章节

在调用以函数为参数的内部函数时,提取所需的函数对象,同时避免与其他类型的对象进行不期望的匹配。如果FUN是一个函数,则返回它。如果它是一个符号(例如,用反引号括起来)或长度为1的字符向量,则将在调用者的父环境中使用get查找它。

因此,match.fun有两个主要好处:

  1. 给用户传递字符串和符号的选项,而不是函数。
  2. 提供类型安全,因为返回值始终是一个函数。这不仅使您的源代码更健壮,而且更透明:不需要阅读fun2的文档就可以知道它的参数fun必须指定一个函数。

它提供了这些好处,而几乎不需要付出性能代价:

代码语言:javascript
运行
复制
x1 <- mean
x2 <- "mean"
x3 <- quote(mean)
microbenchmark::microbenchmark(match.fun(x1), match.fun(x2), match.fun(x3), times = 1000L)
# Unit: nanoseconds
#           expr  min   lq     mean median   uq  max neval
#  match.fun(x1)  287  328  362.481    328  328 1681  1000
#  match.fun(x2) 1599 1681 1820.892   1681 1763 7544  1000
#  match.fun(x3) 1599 1640 1783.049   1681 1722 7339  1000

由于这些原因,在尝试评估函数调用(如在match.fun中)之前,使用fun2进行验证几乎总是比等待和希望可以评估调用(如fun1fun3)要好。即使您的函数没有导出,即使您从未传递字符串或符号,这个原则仍然有效,因为透明性(参见2)使您的源代码更易于阅读和维护。

您的fun3是唯一的,因为它允许用户传递未计算的表达式,但由于多种原因,这种方法是有问题的:

  1. ,它不会像预期的那样在其他功能中工作;参见@Hong Ooi的comment/answer.
  2. You不能将用双冒号或三冒号运算符或匿名函数访问的函数传递给函数: fun3(base::mean,1:10) # base::mean(1:10)中的错误:无法找到函数“base::fun3(函数(X)平均(X),1:10) #function(x) mean(x)中的错误( 1:10):#找不到函数“函数(X)平均(X)”fun3(match.fun(平均值),1:10)#match.fun(mean)中的错误(1:10):#找不到函数match.fun(mean)

  1. --即使它确实像您预期的那样工作--它主要是冒烟和镜像:如果deparse(substitute(fun))的结果是一个字符串,命名一个从调用环境中可以访问的函数,那么首先不需要deparse(substitute(fun)),因为fun无论如何都会对该函数进行评估。微基准::微基准(fun1(平均数,1:10),fun3(平均,1:10),时间= 1000 L)#单位:微秒# expr min lq平均中位数uq max内维尔#fun1(平均数,1:10) 2.009 2.378 2.700055 2.460 2.788 14.350 1000#fun3(平均,1:10) 9.020 10.127 10.991813 10.701 480 11.52.398 1000

总之,无论何时将函数作为参数使用match.fun都是很好的做法。如果您希望接受函数而不是字符串或符号,则可以避免match.fun,但在这种情况下,进行测试仍然是一种良好的实践:

代码语言:javascript
运行
复制
function(FUN, ...) {
  if (!is.function(FUN)) {
    stop("oops")
  }
  ## do stuff
}
票数 1
EN
查看全部 2 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70129354

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档