替代deparse()的更快方法

时间:2019-12-04 00:42:59

标签: r

我维护一个依赖于反复调用deparse(control = c("keepNA", "keepInteger"))的程序包。 control始终相同,并且表达式也有所不同。 deparse()似乎花费大量时间重复使用.deparseOpts()解释同一组选项。

microbenchmark::microbenchmark(
    a = deparse(identity, control = c("keepNA", "keepInteger")),
    b = .deparseOpts(c("keepNA", "keepInteger"))
)
# Unit: microseconds
# expr min  lq  mean median  uq  max neval
#    a 7.2 7.4 8.020    7.5 7.6 55.1   100
#    b 3.0 3.2 3.387    3.4 3.5  6.0   100

在某些系统上,冗余.deparseOpts()调用实际上占用了deparse()flame graph here)的大部分运行时间。

我真的很想只调用一次.deparseOpts()然后将数字代码提供给deparse(),但是如果不调用.Internal()或直接调用C代码,这似乎是不可能的。从软件包开发的角度来看是最佳的。

deparse
# function (expr, width.cutoff = 60L, backtick = mode(expr) %in% 
#     c("call", "expression", "(", "function"), 
#     control = c("keepNA", "keepInteger", "niceNames", 
#         "showAttributes"), nlines = -1L) 
# .Internal(deparse(expr, width.cutoff, backtick, .deparseOpts(control), 
#     nlines))
# <bytecode: 0x0000000006ac27b8>
# <environment: namespace:base>

有一个方便的解决方法吗?

1 个答案:

答案 0 :(得分:4)

1)定义一个函数,该函数生成已重置其环境的deparse副本,以查找已更改为与身份函数相同的.deparseOpts版本。然后,在Run中运行该函数以创建deparse2并执行该函数。这样可以避免直接运行.Internal

make_deparse <- function() {
  .deparseOpts <- identity
  environment(deparse) <- environment()
  deparse
}

Run <- function() {
  deparse2 <- make_deparse()
  deparse2(identity, control = 65)
}

# test
Run()

2)执行此操作的另一种方法是定义一个构造函数,该函数创建一个环境,在该环境中放置deparse的修改后的副本,并向该副本添加跟踪以重新定义{{ 1}}作为身份函数。然后返回该环境。然后,我们有了一些使用它的函数,在本示例中,我们创建一个函数.deparseOpts进行演示,然后仅执行Run。这样可以避免使用Run

.Internal

3)第三种方法是通过添加新参数来重新定义make_deparse_env <- function() { e <- environment() deparse <- deparse suppressMessages( trace("deparse", quote(.deparseOpts <- identity), print = FALSE, where = e) ) e } Run <- function() { e <- make_deparse_env() e$deparse(identity, control = 65) } # test Run() ,该参数将deparse设置为默认值.deparseOpts并设置{{ 1}}的默认值是65。

identity