3

I'd like to replace the following for-loop ...

data <- data.frame(x = c(2, 3, 3, 4, 5, 6, 5, 5, 6, 8, 9, 7, 6, 9, 10),
                   y = rep(0, 15))
for (i in 2:length(data$x)) {
  data$y[i] <- ifelse(data$x[i] > data$y[i-1], data$y[i-1] + 2, data$y[i-1] - 1)
}
data$y # 0  2  4  3  5  7  6  5  7  9  8  7  6  8 10

... and I want to use dplyr and tried the following:

data %>%
  mutate(y = if_else(x > lag(y), lag(y) + 2, lag(y) -1 ))

But obviously I didn't succeed. Any help would be much appreciated.

3
  • 1
    I might be wrong, but I think that ifelse or if_else or case_when don't help here. The for loop is going step-by-step through the data and calculates each y on the basis of the previous y. My guess was to use map. Commented Feb 11, 2020 at 10:34
  • 3
    What you want to look into is Reduce with the argument accumulate set to TRUE Commented Feb 11, 2020 at 10:36
  • Thanks, sounds promising, I'll give it a try. Commented Feb 11, 2020 at 10:44

2 Answers 2

4

You can use accumulate from purrr package for sequential operations:

data %>% 
  mutate( y = accumulate( .x = x[-1],
                          .init = 0,
                          .f = function(y,x) if_else(x > y, y + 2, y - 1) ) 
  )
Sign up to request clarification or add additional context in comments.

Comments

2

In case you are also interested in a base solution using Reduce as already suggested by @Sotos in the comments:

data$y <- Reduce(function(y,x) ifelse(x > y, y+2, y-1)
                 , data$x[-1], data$y[1], accumulate = TRUE)
data$y
# [1]  0  2  4  3  5  7  6  5  7  9  8  7  6  8 10

or

data$y <- Reduce(function(y,x) if(x > y) y+2 else y-1
                 , data$x[-1], data$y[1], accumulate = TRUE)

1 Comment

Thanks. Nice to have both!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.