r vector run-length-encoding

Encuentra las posiciones iniciales/finales/índices de carreras/valores consecutivos



vector run-length-encoding (2)

Problema: dado un vector atómico, encuentre los índices de inicio y fin de las ejecuciones en el vector.

Vector de ejemplo con carreras:

x = rev(rep(6:10, 1:5)) # [1] 10 10 10 10 10 9 9 9 9 8 8 8 7 7 6

Salida de rle() :

rle(x) # Run Length Encoding # lengths: int [1:5] 5 4 3 2 1 # values : int [1:5] 10 9 8 7 6

Salida deseada:

# start end # 1 1 5 # 2 6 9 # 3 10 12 # 4 13 14 # 5 15 15

La clase base rle no parece proporcionar esta funcionalidad, pero la clase Rle y la función rle2 sí. Sin embargo, dado lo pequeña que es la funcionalidad, apegarse a la base R parece más sensato que instalar y cargar paquetes adicionales.

Hay ejemplos de fragmentos de código ( here , here y en SO ) que resuelven el problema ligeramente diferente de encontrar índices de inicio y fin para ejecuciones que satisfacen alguna condición. Quería algo que fuera más general, se pudiera realizar en una línea y no implicara la asignación de variables o valores temporales.

Respondí mi propia pregunta porque estaba frustrado por la falta de resultados de búsqueda. ¡Espero que esto ayude a alguien!


Lógica central:

# Example vector and rle object x = rev(rep(6:10, 1:5)) rle_x = rle(x) # Compute endpoints of run end = cumsum(rle_x$lengths) start = c(1, lag(end)[-1] + 1) # Display results data.frame(start, end) # start end # 1 1 5 # 2 6 9 # 3 10 12 # 4 13 14 # 5 15 15

Tidyverse / dplyr way (centrado en el marco de datos):

library(dplyr) rle(x) %>% unclass() %>% as.data.frame() %>% mutate(end = cumsum(lengths), start = c(1, dplyr::lag(end)[-1] + 1)) %>% magrittr::extract(c(1,2,4,3)) # To re-order start before end for display

Debido a que los vectores de start y end tienen la misma longitud que el componente de values del objeto rle , resolver el problema relacionado de identificar puntos finales para ejecuciones que cumplan alguna condición es sencillo: filter o subconjunte los vectores de start y end utilizando la condición en los valores de ejecución.


Una posibilidad de data.table , donde .I y .N se utilizan para elegir índices relevantes, por grupo definido por rleid .

library(data.table) data.table(x)[ , .(start = .I[1], end = .I[.N]), by = rleid(x)][, rleid := NULL][] # start end # 1: 1 5 # 2: 6 9 # 3: 10 12 # 4: 13 14 # 5: 15 15