r-将函数应用于数据n次

时间:2018-10-23 17:10:33

标签: r function iteration

我想每次使用函数的输出将相同的函数多次应用到向量上。

具有简单功能的简化示例仅用于演示:

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

# function to be applied n times
f1 <- function(x) {
  x^2 + x^3
 }

我想将f1上的a应用于n次,例如在这里说3次。

我听说purrr::reducepurrr::map()可能是个好主意,但无法使其正常工作。

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

4 个答案:

答案 0 :(得分: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

这是正在发生的事情。 Reduce

  

使用二进制函数将给定向量的元素和可能给定的初始值相继合并。

第一个参数是要使用的函数,它应该接受两个参数。第一个是此简化中函数上一个执行的值。在函数的第一次调用中,它使用提供的init=值。

  • 首次通话:

    f1(c(1,2,3), 1)
    # [1]  2 12 36
    
  • 第二通电话:

    f1(c(2,12,36), 2)
    # [1]    12  1872 47952
    
  • 第三次通话:

    f1(c(12,1872,47952), 3)
    # [1] 1.872000e+03 6.563711e+09 1.102629e+14
    

第二个参数1:3仅用于其长度。适当长度的任何东西都可以。

如果您不只是为了减少这种损失而重新定义f1,您可以随时这样做

Reduce(function(a,ign) f1(a), ...)

基准:

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

答案 1 :(得分:1)

i <- 1

while (i < 10) {
  i <- i + 1
  x <- f(x)
}

答案 2 :(得分:1)

这里是accumulate

的一个选项
library(tidyverse)
n <- 3
a %>% 
  accumulate(~ .x %>%
                 f1, .init = f1(a)) %>%
  extract2(n)
#[1] 1.872000e+03 6.563711e+09 1.102629e+14

注意:accumulatebase R的{​​{1}}选项Reduce相似

检查OP的输出

accumulate = TRUE

或使用f1(f1(f1(a))) #[1] 1.872000e+03 6.563711e+09 1.102629e+14 循环(不使用外部库)

for

答案 3 :(得分:1)

这是使用Reduce的另一种方法:

设置舞台

a <- 1:3
f1 <- function(x) x^2 + x^3

构建通话并对其进行评估

N <- 3   # how many times?
r <- Reduce(function(a,b) call("f1", a), rep(NA, N), init=a)
# f1(f1(f1(1:3)))
eval(r)
# [1] 1.872000e+03 6.563711e+09 1.102629e+14

替代2

# N defined as above
Reduce(function(x,y) y(x), replicate(N,f1), init=a)
# [1] 1.872000e+03 6.563711e+09 1.102629e+14

替代3(具有全局变量的递归方法)

doit <- function(N) {
  i <- 0
  function(fun, x){
    i <<- i +1
    if(i < N) Recall(fun, fun(x)) else fun(x)
  }
}
doit(3)(f1, a)
# [1] 1.872000e+03 6.563711e+09 1.102629e+14

...甚至

doit <- function(N, fun, x) (function(fun, x) 
    if((N <<- N - 1) > 0) 
      Recall(fun, fun(x)) else 
        fun(x))(fun, x)
doit(3, f1, a)
# [1] 1.872000e+03 6.563711e+09 1.102629e+14