dplyr 中带条件的递归函数

Recursive function with condition in dplyr

先上一个样本数据

        set.seed(123) 
        dat <- tibble(x = sample(-10:10, size = 11,replace = T))

        # A tibble: 11 x 1
              x
            <int>
        1    -4
        2     6
        3    -2
        4     8
        5     9
        6   -10
        7     1
        8     8
        9     1
        10    -1
        11    10

我有一个初始值为 2 的变量 y。我想通过在给定的时间步长中将 x 添加到 y 来计算 y 的最终值,使用:

      y[i] = y[i-1] + x[i]    

     dat %>% mutate(y = accumulate(x, ~ .x + .y, .init = 2)[-1])

            # A tibble: 11 x 2
                  x     y
                <int> <dbl>
            1    -4    -2
            2     6     4
            3    -2     2
            4     8    10
            5     9    19
            6   -10     9
            7     1    10
            8     8    18
            9     1    19
            10    -1    18
            11    10    28    

但是,我要施加的条件是在给定的时间步长中,y 不能 > 10 或为负数。如果 y > 10,则为 10,如果 y < 0,则为 0。因此,实际 y(在下面的 y1 中显示)应该是:

          # A tibble: 11 x 2
                  x     y    y1
                  <int> <dbl>
            1    -4    -2      0 (-2 converted to 0)
            2     6     4      6 
            3    -2     2      4
            4     8    10     10 (12 converted to 10)
            5     9    19     10 (19 converted to 10)
            6   -10     9      0  
            7     1    10      1
            8     8    18      9  
            9     1    19     10
            10    -1    18     9
            11    10    28    10  (19 converte to 10)

您只需要重新定义用于 accumulate 的函数:

library(tidyverse)
set.seed(123) 
dat <- tibble(x = sample(-10:10, size = 11,replace = T))
fn <- function(x, y) pmax(pmin(x + y, 10), 0)
dat %>% 
  mutate(y = accumulate(x, fn, .init = 2)[-1])
dat
# A tibble: 11 × 2
       x     y
   <int> <dbl>
1     -4     0
2      6     6
3     -2     4
4      8    10
5      9    10
6    -10     0
7      1     1
8      8     9
9      1    10
10    -1     9
11    10    10

工作原理:pmax 取两个值中的最大值,pmin 取最小值,因此您将 x+y 的总和包装到上限和下限中以限制结果在你需要的范围内。

kgolyaev 用非常相似的方法比我快了几分钟。

dat %>% mutate(y = accumulate(x, ~min(max(.x + .y, 0), 10), .init = 2)[-1])