【问题标题】:R pass function to accumulateR传递函数来累积
【发布时间】:2021-10-20 08:26:29
【问题描述】:

我想使用这个累积示例更改数据场中变量的固定“增长”。原文示例: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。有什么帮助吗?

【问题讨论】:

    标签: r purrr accumulate


    【解决方案1】:

    由于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) 作为第一个返回值传递,这不是我们想要的。为了解决这个问题,我们将其从 pmap'd 列表中删除,并将 b[1] 添加为 accumulate 的初始化值 (.init=)。

    顺便说一句:这是将growth当前 值应用于b上一个 值。

    另一个顺便说一句:您对fill_in 的使用使用了if_else。虽然它有效,但它是不必要和不合适的。如果要查找if 一个长度始终为1 的对象,则使用if(以及可选的else);如果希望以逻辑的向量为条件,则使用ifelse/if_else。虽然可以使用 if_else 当您知道它总是长度为 1 时,但存在开销和可能发生的其他完全不必要的事情(在基础 R 中,ifelse 具有非- 微不足道的类数据,因此应管理其使用)。

    由于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))
    

    【讨论】:

    • 非常感谢!这就是我要找的。还有一个问题,你怎么定义fill_in2?
    • 对不起,是的,我添加了它(加上一些注释)。查看我的编辑。
    猜你喜欢
    • 2021-07-13
    • 2012-07-18
    • 2016-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-13
    • 2014-12-10
    • 1970-01-01
    相关资源
    最近更新 更多