当前位置: 首页>>代码示例 >>用法及示例精选 >>正文


R purrr accumulate 累积向量缩减的中间结果


accumulate() 按顺序将 2 参数函数应用于向量的元素。该函数的每个应用程序都使用前一个应用程序的初始值或结果作为第一个参数。第二个参数是向量的下一个值。每个应用程序的结果都以列表形式返回。在处理整个向量之前,累加可以选择性地终止,以响应累加函数返回的 done() 信号。

accumulate() 相比,reduce() 以相同的方式应用 2 参数函数,但丢弃除最终函数应用之外的所有结果。

accumulate2() 按顺序将函数应用于两个列表 .x.y 的元素。

用法

accumulate(
  .x,
  .f,
  ...,
  .init,
  .dir = c("forward", "backward"),
  .simplify = NA,
  .ptype = NULL
)

accumulate2(.x, .y, .f, ..., .init, .simplify = NA, .ptype = NULL)

参数

.x

列表或原子向量。

.f

对于 accumulate() .f 是 2 参数函数。该函数将传递累积结果或初始值作为第一个参数。序列中的下一个值作为第二个参数传递。

对于 accumulate2() ,一个 3 参数函数。该函数将把累积结果作为第一个参数传递。 .x 中的下一个值将作为第二个参数传递。 .y 中的下一个值将作为第三个参数传递。

如果 .f 返回包含在 done() 中的值,则累加会提前终止。

...

传递给映射函数的附加参数。

我们现在通常建议不要使用 ... 将附加(常量)参数传递给 .f 。相反,使用简写匿名函数:

# Instead of
x |> map(f, 1, 2, collapse = ",")
# do:
x |> map(\(x) f(x, 1, 2, collapse = ","))

这使得更容易理解哪些参数属于哪个函数,并且往往会产生更好的错误消息。

.init

如果提供,将用作开始累加的第一个值,而不是使用 .x[[1]] 。如果您想确保 reduce.x 为空时返回正确的值,这非常有用。如果丢失,并且.x为空,将抛出错误。

.dir

作为字符串的累积方向, "forward" (默认)或 "backward" 之一。请参阅下面有关方向的部分。

.simplify

如果是 NA (默认值),则累积的结果列表会在可能的情况下简化为原子向量。如果是 TRUE ,结果会被简化,如果不可能就会出错。如果 FALSE ,结果不会简化,始终返回一个列表。

.ptype

如果 simplifyNATRUE ,可以选择提供向量原型来强制输出类型。

.y

对于 accumulate2() .y 是该对的第二个参数。它需要比要累加的向量短 1 个元素 (.x)。如果设置了 .init,则 .y 需要比初始值和 .x 的串联短一个元素。

.x 长度相同且名称与 .x 相同的向量。

如果提供 .init,则长度扩展 1。如果 .x 有名称,则初始值的名称为 ".init",否则返回的向量保持未命名。

如果 .dir"forward" (默认值),则第一个元素是初始值( .init 如果提供,或 .x 的第一个元素),最后一个元素是最终减少的值。如果积累正确,则此顺序相反。

如果 .f 返回包含在 done() 中的值,则累加会提前终止。如果完成框为空,则使用最后一个值,并且结果会短一个元素(但始终包含初始值,即使在第一次迭代时终止)。

生命周期

从 rlang 0.3.0 开始,accumulate_right() 已被软弃用,取而代之的是 .dir 参数。请注意,算法略有变化:累加值传递到右侧而不是左侧,这与右归约一致。

方向

.f 是像 +c() 这样的关联运算时,减少的方向并不重要。例如,使用二元函数 + 约简向量 1:3 会计算左侧的和 ((1 + 2) + 3),以及右侧的相同和 (1 + (2 + 3))

在其他情况下,方向对降低的值有重要影响。例如,从左侧减少 list() 向量会生成 left-leaning 嵌套列表(或树),而从右侧减少 list() 会生成 right-leaning 列表。

也可以看看

reduce() 当您只需要最终减少的值时。

例子

# With an associative operation, the final value is always the
# same, no matter the direction. You'll find it in the first element for a
# backward (left) accumulation, and in the last element for forward
# (right) one:
1:5 |> accumulate(`+`)
#> [1]  1  3  6 10 15
1:5 |> accumulate(`+`, .dir = "backward")
#> [1] 15 14 12  9  5

# The final value is always equal to the equivalent reduction:
1:5 |> reduce(`+`)
#> [1] 15

# It is easier to understand the details of the reduction with
# `paste()`.
accumulate(letters[1:5], paste, sep = ".")
#> [1] "a"         "a.b"       "a.b.c"     "a.b.c.d"   "a.b.c.d.e"

# Note how the intermediary reduced values are passed to the left
# with a left reduction, and to the right otherwise:
accumulate(letters[1:5], paste, sep = ".", .dir = "backward")
#> [1] "a.b.c.d.e" "b.c.d.e"   "c.d.e"     "d.e"       "e"        

# By ignoring the input vector (nxt), you can turn output of one step into
# the input for the next. This code takes 10 steps of a random walk:
accumulate(1:10, \(acc, nxt) acc + rnorm(1), .init = 0)
#>  [1] 0.000000 1.928421 1.148285 1.729282 2.400668 2.431910 3.939412
#>  [8] 3.293159 3.488425 2.557862 3.334301

# `accumulate2()` is a version of `accumulate()` that works with
# 3-argument functions and one additional vector:
paste2 <- function(acc, nxt, sep = ".") paste(acc, nxt, sep = sep)
letters[1:4] |> accumulate(paste2)
#> [1] "a"       "a.b"     "a.b.c"   "a.b.c.d"
letters[1:4] |> accumulate2(c("-", ".", "-"), paste2)
#> [1] "a"       "a-b"     "a-b.c"   "a-b.c-d"

# You can shortcircuit an accumulation and terminate it early by
# returning a value wrapped in a done(). In the following example
# we return early if the result-so-far, which is passed on the LHS,
# meets a condition:
paste3 <- function(out, input, sep = ".") {
  if (nchar(out) > 4) {
    return(done(out))
  }
  paste(out, input, sep = sep)
}
letters |> accumulate(paste3)
#> [1] "a"     "a.b"   "a.b.c" "a.b.c"

# Note how we get twice the same value in the accumulation. That's
# because we have returned it twice. To prevent this, return an empty
# done box to signal to accumulate() that it should terminate with the
# value of the last iteration:
paste3 <- function(out, input, sep = ".") {
  if (nchar(out) > 4) {
    return(done())
  }
  paste(out, input, sep = sep)
}
letters |> accumulate(paste3)
#> [1] "a"     "a.b"   "a.b.c"

# Here the early return branch checks the incoming inputs passed on
# the RHS:
paste4 <- function(out, input, sep = ".") {
  if (input == "f") {
    return(done())
  }
  paste(out, input, sep = sep)
}
letters |> accumulate(paste4)
#> [1] "a"         "a.b"       "a.b.c"     "a.b.c.d"   "a.b.c.d.e"


# Simulating stochastic processes with drift
if (FALSE) {
library(dplyr)
library(ggplot2)

map(1:5, \(i) rnorm(100)) |>
  set_names(paste0("sim", 1:5)) |>
  map(\(l) accumulate(l, \(acc, nxt) .05 + acc + nxt)) |>
  map(\(x) tibble(value = x, step = 1:100)) |>
  list_rbind(id = "simulation") |>
  ggplot(aes(x = step, y = value)) +
    geom_line(aes(color = simulation)) +
    ggtitle("Simulations of a random walk with drift")
}
源代码:R/reduce.R

相关用法


注:本文由纯净天空筛选整理自Hadley Wickham等大神的英文原创作品 Accumulate intermediate results of a vector reduction。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。