user1357015
user1357015

Reputation: 11686

Carry value forward in dplyr chain

Suppose I have the following column

**CurrentStatus**
Current
NoChange
NoChange
NoChange
NoChange
Late

I want to mutate it so that if the value is "NoChange" it uses the prior value.

I tried:

myDF %>% mutate(CurrentStatus = ifelse(CurrentStatus == "NoChange", lag(CurrentStatus), CurrentStatus)

That doesn't seem to work -- I think it's because it does a vectorized calculation so it looks at all the lags at the same time. I need it to "roll forward". I was wondering what's the most efficient way to do this without a for loop. I specifically want to avoid a for loop as there are some grouping variables not shown that I need to be mindful of.

Thanks!

Upvotes: 5

Views: 652

Answers (2)

Nick Nassuphis
Nick Nassuphis

Reputation: 287

You could use something like this:

rfwd<-function(value,trigger)
{
  c("",value)[cummax(seq_along(value)*(trigger))+1]
}

and your answer would be rfwd(CurrentStatus,CurrentStatus!="NoChange")

> rfwd(LETTERS,seq_along(LETTERS)%%10==0)
 [1] ""  ""  ""  ""  ""  ""  ""  ""  ""  "J" "J" "J" "J" "J" "J" "J" "J" "J" "J" "T" "T" "T" "T" "T" "T" "T"

Upvotes: 0

akrun
akrun

Reputation: 887153

We can replace the 'NoChange' to NA and then use fill

library(tidyverse)
myDF %>%
    mutate(CurrentStatus = replace(CurrentStatus, CurrentStatus == "NoChange", NA)) %>%
    fill(CurrentStatus)
#  CurrentStatus
#1       Current
#2       Current
#3       Current
#4       Current
#5       Current
#6          Late

Or another option is na.locf from zoo

library(zoo)
myDF$CurrentStatus <-  with(myDF, na.locf(replace(CurrentStatus, 
              CurrentStatus == "NoChange", NA)))

Upvotes: 9

Related Questions