r - 对数据应用函数n次

adl*_*adl 2 iteration r function

我想每次使用函数的输出在矢量上应用相同的函数一定次数.

一个带有简单函数的简化示例,仅用于演示:

# sample vector
a <- c(1,2,3)

# function to be applied n times
f1 <- function(x) {
  x^2 + x^3
 }
Run Code Online (Sandbox Code Playgroud)

我想申请f1a,n次数,例如这里可以说3次.

我听说purrr::reduce或者purrr::map()可能是个好主意,但无法使其发挥作用.

期望的输出如果n = 3等于f1(f1(f1(a))).

r2e*_*ans 5

让我们使用Reduce(没有外部库要求,通常表现良好).我将稍微修改该函数以接受第二个(被忽略的)参数:

f1 <- function(x, ign) x^2 + x^3

Reduce(f1, 1:3, init = a)
# [1] 1.872000e+03 6.563711e+09 1.102629e+14
Run Code Online (Sandbox Code Playgroud)

这是正在发生的事情.Reduce:

使用二元函数连续组合给定向量的元素和可能给定的初始值.

第一个参数是要使用的函数,它应该接受两个参数.第一个是此减少中先前执行函数的值.在第一次调用函数时,它使用init=提供的值.

第二个参数1:3仅用于其长度.任何适当长度的东西都会起作用.

如果您不想重新定义f1这种减少,您可以随时进行

Reduce(function(a,ign) f1(a), ...)
Run Code Online (Sandbox Code Playgroud)

基准测试:

library(microbenchmark)
r <- Reduce(function(a,b) call("f1", a), 1:3, init=quote(a))
triple_f1 <- function(a) f1(f1(f1(a)))
microbenchmark::microbenchmark(
  base = Reduce(function(a,ign) f1(a), 1:3, a),
  accum = a %>% accumulate(~ .x %>% f1, .init = f1(a)) %>% extract2(3),
  reduc = purrr::reduce(1:3, function(a,ign) f1(a), .init=a),
  whil = { 
    i <- 1
    a <- c(1,2,3)
      while (i < 10) {
        i <- i + 1
        a <- f1(a)
      }
    },
  forloop = {
    out <- a
    for(i in seq_len(3)) out <- f1(out)
  },
  evaluated = {
    r <- Reduce(function(a,b) call("f1", a), 1:3, init=quote(a))
    eval(r)
  },
  precompiled = eval(r),
  anotherfun = triple_f1(a)
)
# Unit: microseconds
#         expr      min        lq       mean    median        uq      max neval
#         base    5.101    7.3015   18.28691    9.3010   10.8510  848.302   100
#        accum  294.201  328.4015  381.21204  356.1520  402.6510  823.602   100
#        reduc   27.000   38.1005   57.55694   45.2510   54.2005  747.401   100
#         whil 1717.300 1814.3510 1949.03100 1861.8510 1948.9510 2931.001   100
#      forloop 1110.001 1167.1010 1369.87696 1205.5010 1292.6500 9935.501   100
#    evaluated    6.702   10.2505   22.18598   13.3015   15.5510  715.301   100
#  precompiled    2.300    3.2005    4.69090    4.0005    4.5010   26.800   100
#   anotherfun    1.400    2.0515   12.85201    2.5010    3.3505 1017.801   100
Run Code Online (Sandbox Code Playgroud)