當前位置: 首頁>>代碼示例 >>用法及示例精選 >>正文


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。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。