Incrementar en 1 por cada cambio en la columna

Digamos que tengo el siguiente dataframe

set.seed(123) df 0.5)*1) 

var1 podría tener cualquier tipo / número de niveles, no específicamente 0 y 1s

Me gustaría crear un var2 que se incremente en 1 cada vez que var1 cambie sin usar un for loop

El resultado esperado en este caso es:

 data.frame(var1=(runif(10)>0.5)*1, var2=c(1, 2, 3, 4, 4, 5, 6, 6, 6, 7)) var1 var2 0 1 1 2 0 3 1 4 1 4 0 5 1 6 1 6 1 6 0 7 

Otra opción para el dataframe podría ser:

 df <- data.frame(var1=c("a", "a", "1", "0", "b", "b", "b", "c", "1", "1")) 

en este caso, el resultado debería ser:

 var1 var2 a 1 a 1 1 2 0 3 b 4 b 4 b 4 c 5 1 6 1 6 

Basándose en la respuesta del Sr. Flick:

 df$var2 < - cumsum(c(0,as.numeric(diff(df$var1))!=0)) 

Pero si no quiere usar diff , puede usar:

 df$var2 < - c(0,cumsum(as.numeric(with(df,var1[1:(length(var1)-1)] != var1[2:length(var1)])))) 

Comienza en 0, no en 1, pero estoy seguro de que verá cómo cambiarlo si lo desea.

¿Qué hay de usar diff() y cumsum() . Por ejemplo

 df$var2 < - cumsum(c(1,diff(df$var1)!=0)) 

Estos parecen una encoding de longitud de ejecución (rle)

 x = c("a", "a", "1", "0", "b", "b", "b", "c", "1", "1") r = rle(x) 

con

 > rle(x) Run Length Encoding lengths: int [1:6] 2 1 1 3 1 2 values : chr [1:6] "a" "1" "0" "b" "c" "1" 

Esto dice que el primer valor (“a”) ocurrió 2 veces seguidas, luego “1” ocurrió una vez, etc. Lo que busca es crear una secuencia a lo largo de las ‘longitudes’, y replicar cada elemento de la secuencia la cantidad de veces que ocurre el elemento, por lo

 > rep(seq_along(r$lengths), r$lengths) [1] 1 1 2 3 4 4 4 5 6 6 

Las otras respuestas son semi-engañosas, ya que dependen de que la columna sea un factor (); fallan cuando la columna es en realidad un personaje ().

 > diff(x) Error in r[i1] - r[-length(r):-(length(r) - lag + 1L)] : non-numeric argument to binary operator 

Una solución sería mapear los caracteres a enteros, a lo largo de las líneas de

 > diff(match(x, x)) [1] 0 2 1 1 0 0 3 -5 0 

Hmm, pero una vez dicho eso, descubro que no funcionan los factores.

 > f = factor(x) > rle(f) Error in rle(factor(x)) : 'x' must be a vector of an atomic type > rle(as.vector(f)) Run Length Encoding lengths: int [1:6] 2 1 1 3 1 2 values : chr [1:6] "a" "1" "0" "b" "c" "1" 

Aquí hay otra solución con base R usando inverse.rle() :

 df < - data.frame(var1=c("a", "a", "1", "0", "b", "b", "b", "c", "1", "1")) r <- rle(as.character(df$var1)) r$values <- seq_along(r$values) df$var2 <- inverse.rle(r) 

Version corta:

 df$var2 < - with(rle(as.character(df$var1)), rep(seq_along(values), lengths)) 

Aquí hay una solución con data.table :

 library("data.table") dt < - data.table(var1=c("a", "a", "1", "0", "b", "b", "b", "c", "1", "1")) dt[, var2:=rleid(var1)]