20

I've got a binary variable representing if event happened or not:

event <- c(0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0)

I need to obtain a variable that would indicate the time when the last event happened. The expected output would be:

last_event <- c(0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 13, 13, 13, 13)

How can I obtain that with base R, tidyverse or any other way?

jakes
  • 1,964
  • 3
  • 18
  • 50

4 Answers4

19

Taking advantage of the fact that you have a binary vector, the following gives your desired output:

cummax(seq_along(event) * event)
mgiormenti
  • 793
  • 6
  • 14
  • 6
    Yes! So much more elegant than my solution. I was thinking about cumulative sums but I didn’t think of multiplying the indices by the binary vector. – Konrad Rudolph Apr 11 '19 at 14:27
  • 3
    or without multiplication `cummax(ifelse(event, seq_along(event), 0))` – jogo Apr 11 '19 at 14:27
  • @jogo That solution makes sense if the type of `event` is `logical`. It does work even for a numeric vector due to R’s implicit conversions but … eh. – Konrad Rudolph Apr 11 '19 at 14:28
9

Whenever you need to fill repetitions with a value, think run-length encoding.

In this case, you can determine the run lengths and then repeat the indices of count == 0 an according number of times:

lengths = rle(event == 0)$lengths
nonzeros = which(event != 0)
runs = c(0, rep(nonzeros, each = 2))
result = rep(runs, lengths)

Alternative, substitute the runs in the RLE and then inverse it:

rle = rle(event == 0)
nonzeros = which(event != 0)
rle$values = c(0, rep(nonzeros, each = 2))
result = inverse.rle(rle)
Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
1

You can also do somthing like this-

> zero.locf <- function(x) {
  v <- x!=0
  c(0, x[v])[cumsum(v)+1]
}

> zero.locf(1:length(event)*event)

[1]  0  0  0  0  5  5  5  5  5  5  5  5 13 13 13 13
Rushabh Patel
  • 2,672
  • 13
  • 34
1

Another option is to find the index where event == 1 and repeat it based on length.

rep(c(0, which(event == 1)), tapply(event, cumsum(event == 1), length))
#[1]  0  0  0  0  5  5  5  5  5  5  5  5 13 13 13 13
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213