Search code examples
rif-statementpurrrresetaccumulate

Use purrr::accumulate function with two if/else conditions in R


I need to calculate a cumulative sum (the same constant is added in each iteration) but with two if/else conditions:

  1. Total cumulative sum can't be higher than 400;
  2. If the cumulative sum reached 400 on the previous iteration, then check the time. If it is nighttime (between 22 pm and 6 am) keep it to 400 before daytime starts, if it's daytime (between 6 am and 22 pm), reset it to 0 and start accumulating again).

When I try to write it, the second if/else doesn't work. Is it possible to use two conditions with accumulate()? Or maybe it can't account for time because this is an additional variable? I found an example with one if/else on Stack Overflow, so I guess I incorrectly incorporated a second if/else.

I would be grateful if someone can suggest any idea how to do it, including any other different way to solve my task.

k_in = 2                              # constant to add in each iteration
tmax = 24*2*60                        # two days in minutes
x <- tibble(time = c(1:tmax),         # vector of time in minutes
            time_h = time/60,         # vector of time in hours
            time2 = (time_h %% 24),   # vector of time in p.m - a.m 
            value = rep(k_in, tmax),  # value to accumulate
            
            Sum = accumulate(value, ~ifelse(.x + .y <= 400, .x + .y, 
                                               ifelse( (time2 >= 22 | time2 < 6), .x, -k_in + .y))))

This creates Sum column that accumulates up to 400 and continues to keep it at 400 even if it is daytime already.

If I change the second if/else to the opposite one it is just resetting and accumulating again up to 400 independently from day/night time.


Solution

  • You could try using accumulate2 and provide time2 as another argument. Then refer to arguments ..1, ..2, ..3 in order as follows:

    Sum = accumulate2(
            value[-1], 
            time2[-1],
            ~if(.x + .y <= 400) ..1 + ..2 else if (..3 >= 22 | ..3 < 6) ..1 else -k_in + ..2,
            .init = first(value))
    )