R: contar las ocurrencias consecutivas de valores en una sola columna

Deseo crear un número secuencial dentro de cada ejecución de valores iguales, como un contador de ocurrencias, que se reinicia una vez que el valor en la fila actual es diferente de la fila anterior.

Encuentre un ejemplo de entrada y resultado esperado a continuación.

dataset <- data.frame(input = c("a","b","b","a","a","c","a","a","a","a","b","c")) dataset$counter <- c(1,1,2,1,2,1,1,2,3,4,1,1) dataset # input counter # 1 a 1 # 2 b 1 # 3 b 2 # 4 a 1 # 5 a 2 # 6 c 1 # 7 a 1 # 8 a 2 # 9 a 3 # 10 a 4 # 11 b 1 # 12 c 1 

Mi pregunta es muy similar a esta: secuencia acumulativa de ocurrencias de valores .

Necesitas usar sequence y rle :

 > sequence(rle(as.character(dataset$input))$lengths) [1] 1 1 2 1 2 1 1 2 3 4 1 1 

Una versión más eficiente y más directa de la función escrita a continuación está disponible ahora en el paquete data.table, llamado rleid . Usando eso, es solo:

 setDT(dataset)[, counter := seq_len(.N), by=rleid(input)] 

Vea ?rleid para más información sobre el uso y ejemplos. Gracias a @Henrik por la sugerencia de actualizar esta publicación.


rle es definitivamente la forma más conveniente de hacerlo (+1 @ Ananda). Pero uno podría hacerlo mejor (en términos de velocidad) en datos más grandes. Puede usar las funciones duplist y vecseq (no exportadas) de data.table siguiente manera:

 require(data.table) arun <- function(y) { w = data.table:::duplist(list(y)) w = c(diff(w), length(y)-tail(w,1L)+1L) data.table:::vecseq(rep(1L, length(w)), w, length(y)) } x <- c("a","b","b","a","a","c","a","a","a","a","b","c") arun(x) # [1] 1 1 2 1 2 1 1 2 3 4 1 1 

Benchmarking en big data:

 set.seed(1) x <- sample(letters, 1e6, TRUE) # rle solution ananda <- function(y) { sequence(rle(y)$lengths) } require(microbenchmark) microbenchmark(a1 <- arun(x), a2<-ananda(x), times=100) Unit: milliseconds expr min lq median uq max neval a1 <- arun(x) 123.2827 132.6777 163.3844 185.439 563.5825 100 a2 <- ananda(x) 1382.1752 1899.2517 2066.4185 2247.233 3764.0040 100 identical(a1, a2) # [1] TRUE 
    Intereting Posts