我想每次使用函数的输出将相同的函数多次应用到向量上。
具有简单功能的简化示例仅用于演示:
# 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::reduce
或purrr::map()
可能是个好主意,但无法使其正常工作。
如果n = 3
等于f1(f1(f1(a)))
,则期望的输出。
答案 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
注意:accumulate
与base 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
# 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
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