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
-
如果
simplify
是NA
或TRUE
,可以選擇提供向量原型來強製輸出類型。 - .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 purrr as_vector 將列表強製轉換為向量
- R purrr array-coercion 強製數組列出
- R purrr auto_browse 包裝一個函數,以便在出錯時自動 browser()
- R purrr as_mapper 將對象轉換為映射器函數
- R purrr attr_getter 創建屬性 getter 函數
- R purrr imap 將函數應用於向量的每個元素及其索引
- R purrr list_transpose 轉置列表
- R purrr map_if 有條件地將函數應用於向量的每個元素
- R purrr map2 映射兩個輸入
- R purrr pluck 安全地獲取或設置嵌套數據結構深處的元素
- R purrr insistently 將函數轉換為等待,然後在錯誤後重試
- R purrr map_depth 在給定深度映射/修改元素
- R purrr list_simplify 將列表簡化為原子或 S3 向量
- R purrr rerun 多次重新運行表達式
- R purrr quietly 包裝一個函數來捕獲副作用
- R purrr list_flatten 壓平列表
- R purrr pmap 同時映射多個輸入(“並行”)
- R purrr possibly 包裝函數以返回值而不是錯誤
- R purrr head_while 查找全部滿足謂詞的頭/尾。
- R purrr rbernoulli 從伯努利分布生成隨機樣本
- R purrr rate-helpers 創建延遲率設置
- R purrr keep_at 根據元素的名稱/位置保留/丟棄元素
- R purrr keep 根據元素的值保留/丟棄元素
- R purrr transpose 轉置列表。
- R purrr flatten 將列表的列表展平為簡單的向量
注:本文由純淨天空篩選整理自Hadley Wickham等大神的英文原創作品 Accumulate intermediate results of a vector reduction。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。