Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recursive function using dplyr

Tags:

r

dplyr

I have data:

dat <- tibble(
         day = 200:210,
         x = sample(-10:10, size = 11,replace = T))

I have a variable y with initial value of 2. I want to calculate the final value of y by adding x to y in a given time step following the following notation:

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

If I did this:

y <- 5
dat %>% mutate(y = y + x)

It adds y to each x.

# A tibble: 11 x 3
    day     x     y
  <int> <int> <dbl>
1   200     4     9
2   201     3     8
3   202    -4     1
4   203    -7    -2
5   204    -3     2
6   205     1     6
7   206    -5     0
8   207    -1     4
9   208    -4     1
10  209    -2     3
11  210     4     9

The answer should be:

  # A tibble: 11 x 3
    day     x     y
  <int> <int> <dbl>
1   200     4     9
2   201     3     12
3   202    -4     8
4   203    -7     1
5   204    -3     -2
6   205     1     -1
7   206    -5     -6
8   207    -1     -7
9   208    -4     -11
10  209    -2     -13
11  210     4     -9

How do I achive this using dplyr package? Or any other method that is quick and fast.

EDIT

If I want to impose a condition such that y cannot exceed 10 or be negative .If it exceeds 10, make it 10 and if it is negative, make it zero. How do I achieve this:

A tibble: 11 x 3

      day     x     y     y1
  1   200     4     9     9
  2   201     3     12    10
  3   202    -4     8     6
  4   203    -7     1     0 
  5   204    -3     -2    0
  6   205     1     -1    0
  7   206    -5     -6    0
  8   207    -1     -7    0  
  9   208    -4     -11   0
  10  209    -2     -13   0
  11  210     4     -9    0
like image 744
89_Simple Avatar asked Feb 19 '18 14:02

89_Simple


2 Answers

We could use accumulate from purrr. With accumulate, do the recursive sum of 'x' elements while initiating with a value of 5 (.init = 5) and remove the first element of accumulate output ([-1])

library(purrr)
library(dplyr)
dat %>%
     mutate(y = accumulate(x, ~ .x + .y, .init = 5)[-1])
# A tibble: 11 x 3
#     day     x      y
#   <int> <int>  <dbl>
# 1   200     4   9.00
# 2   201     3  12.0 
# 3   202    -4   8.00
# 4   203    -7   1.00
# 5   204    -3 - 2.00
# 6   205     1 - 1.00
# 7   206    -5 - 6.00
# 8   207    -1 - 7.00
# 9   208    -4 -11.0 
#10   209    -2 -13.0 
#11   210     4 - 9.00

A similar approach in base R would be

dat$y <- Reduce(function(u, v)  u + v , dat$x, init = 5, accumulate = TRUE)[-1]
dat$y
#[1]   9  12   8   1  -2  -1  -6  -7 -11 -13  -9
like image 78
akrun Avatar answered Nov 11 '22 20:11

akrun


df %>% mutate(y = 5 + cumsum(x))

or, with your extra conditions

df %>% mutate(y = (5 + cumsum(x)) %>% pmin(10) %>% pmax(0))
like image 32
IceCreamToucan Avatar answered Nov 11 '22 21:11

IceCreamToucan