Как получить позицию последнего ненулевого элемента

#r #tidyverse #base

#r #tidyverse #База

Вопрос:

У меня есть двоичная переменная, представляющая, произошло событие или нет:

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

Мне нужно получить переменную, которая указывала бы время, когда произошло последнее событие. Ожидаемый результат будет:

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

Как я могу получить это с помощью base R, tidyverse или любым другим способом?

Ответ №1:

Используя тот факт, что у вас есть двоичный вектор, следующее дает желаемый результат:

 cummax(seq_along(event) * event)
  

Комментарии:

1. Да! Это намного элегантнее, чем мое решение. Я думал о совокупных суммах, но я не думал о умножении индексов на двоичный вектор.

2. или без умножения cummax(ifelse(event, seq_along(event), 0))

3. @jogo Это решение имеет смысл, если тип event равен logical . Это работает даже для числового вектора из-за неявных преобразований R, но … эх.

Ответ №2:

Всякий раз, когда вам нужно заполнить повторения значением, подумайте о кодировании длины выполнения.

В этом случае вы можете определить длину пробега, а затем повторить индексы count == 0 соответствующего количества раз:

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

Альтернативно, замените прогоны в RLE, а затем инвертируйте его:

 rle = rle(event == 0)
nonzeros = which(event != 0)
rle$values = c(0, rep(nonzeros, each = 2))
result = inverse.rle(rle)
  

Ответ №3:

Вы также можете сделать что-то подобное-

 > 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
  

Ответ №4:

Другой вариант — найти индекс where event == 1 и повторить его на основе 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