R传递函数累加

R pass function to accumulate

我想使用这个累积示例来更改数据场中变量的固定“增长”。原始示例:https://community.rstudio.com/t/row-wise-iteration-in-a-dataframe-where-each-row-depends-on-previous-values/38725/2

library(dplyr)
library(purrr)

x <- tibble(a = c(1:10),
            b = c(seq(100, 140, 10), rep(NA_real_, 5)) )

x$growth = runif(10, 0.001, 0.09)

fill_in <- function(prev, new, growth = 0.03) {
  if_else(!is.na(new), new, prev * (1 + growth))
}

x <- x %>%
  mutate(b = accumulate(b, fill_in))

这可行,但我不能用 x$growth 替换 0.03。有帮助吗?

由于 accumulate(和 accumulate2)的结构,我们不能只迭代 b,我们需要为每个点包含类似 c(b, growth) 的内容。为此,我们将传递一个 list 向量,而不是传递 b,它可以通过以下方式生成:

with(x, pmap(list(b, growth), c))
# [[1]]
# [1] 100.0000000   0.0265944
# [[2]]
# [1] 110.00000000   0.07115916
# [[3]]
# [1] 120.00000000   0.03739895
# [[4]]
# [1] 130.00000000   0.07958855
# [[5]]
# [1] 140.00000000   0.08470159
# [[6]]
# [1]          NA 0.005054528
# [[7]]
# [1]         NA 0.04800139
# [[8]]
# [1]         NA 0.08042529
# [[9]]
# [1]         NA 0.05007772
# [[10]]
# [1]         NA 0.04163871

有了这个,我们现在可以积累:

fill_in2 <- function(prev, new) if (is.na(new[1])) prev[1]*(1+new[2]) else new[1]
options(pillar.sigfig = 5)
x %>%
  mutate(b = accumulate(pmap(list(b, growth), c)[-1], .init = b[1], fill_in2))
# # A tibble: 10 x 3
#        a      b    growth
#    <int>  <dbl>     <dbl>
#  1     1 100    0.026594 
#  2     2 110    0.071159 
#  3     3 120    0.037399 
#  4     4 130    0.079589 
#  5     5 140    0.084702 
#  6     6 140.71 0.0050545
#  7     7 147.46 0.048001 
#  8     8 159.32 0.080425 
#  9     9 167.30 0.050078 
# 10    10 174.27 0.041639 

我同时执行 pmap(..)[-1].init=b[1] 的原因是因为 accumulate 的默认行为,.x 的第一个元素按原样传递;在这种情况下,这会将 c(100, 0.0266) 作为第一个 return 值传递,这不是我们想要的。为了解决这个问题,我们将其从 pmap 列表中删除并添加 b[1] 作为 accumulate.

的初始化值 (.init=)

顺便说一句:这是使用 growth 当前 值应用于 b 先前 值.

另一个顺便说一句:您对 fill_in 的使用使用了 if_else。虽然它有效,但它是不必要和不合适的。如果正在寻找 if 一个长度始终为 1 的对象,则使用 if(以及可选的 else);如果有人希望以 向量 为条件,则使用 ifelse/if_else。当你知道 if_else 总是长度为 1 时可以使用 if_else ,但是有开销并且可能发生其他完全不必要的事情(并且在基础 R 中, ifelse 有后果和副作用-对非平凡 class 数据的影响,因此应对其使用进行管理)。

由于 accumulate 一次仅使用一行数据调用您的函数,因此使用 if 更为合适。


数据

set.seed(123)
x <- tibble(a = c(1:10),
            b = c(seq(100, 140, 10), rep(NA_real_, 5)),
            growth = runif(10, 0.001, 0.09))