Agregar índice a ejecuciones contiguas de valores iguales

¿Hay una forma más rápida de hacer un índice de contador que utilizando un bucle? Dentro de ejecuciones contiguas de valores iguales, el índice debe ser el mismo. Encuentro que el bucle es muy lento, especialmente cuando los datos son muy grandes.

A modo de ilustración, aquí está la entrada y la salida deseada

x <- c(2, 3, 9, 2, 4, 4, 3, 4, 4, 5, 5, 5, 1) 

Contador resultante deseado:

 c(1, 2, 3, 4, 5, 5, 6, 7, 7, 8, 8, 8, 9) 

Tenga en cuenta que las ejecuciones no contiguas tienen índices diferentes . Por ejemplo, vea los índices deseados de los valores 2 y 4

Mi código ineficiente es este:

 group[1]<-1 counter<-1 for (i in 2:n){ if (x[i]==x[i-1]){ group[i]<-counter }else{ counter<-counter+1 group[1]<-counter} } 

Si tiene valores numéricos como este, puede usar diff y cumsum para sumr cambios en los valores

 x < - c(2,3,9,2,4,4,3,4,4,5,5,5,1) cumsum(c(1,diff(x)!=0)) # [1] 1 2 3 4 5 5 6 7 7 8 8 8 9 

Usando data.table , que tiene la función rleid() :

 require(data.table) # v1.9.5+ rleid(x) # [1] 1 2 3 4 5 5 6 7 7 8 8 8 9 

Esto funcionará con valores numéricos de caracteres:

 rep(1:length(rle(x)$values), times = rle(x)$lengths) #[1] 1 2 3 4 5 5 6 7 7 8 8 8 9 

También puede ser un poco más eficiente al llamar a rle solo una vez (aproximadamente 2 veces más rápido) y se puede hacer una mejora de velocidad muy leve usando rep.int lugar de rep :

 y < - rle(x) rep.int(1:length(y$values), times = y$lengths)