Eliminar / colapsar valores duplicados consecutivos en secuencia

Tengo el siguiente dataframe :

aaabccdeaabbbeedd 

El resultado requerido debe ser

 abcdeabed 

Significa que no hay dos filas consecutivas que tengan el mismo valor. Cómo se puede hacer sin usar el bucle

Como mi conjunto de datos es bastante grande, la ejecución de bucles requiere mucho tiempo.

La estructura del dataframe es como la siguiente

 a 1 a 2 a 3 b 2 c 4 c 1 d 3 e 9 a 4 a 8 b 10 b 199 e 2 e 5 d 4 d 10 

Resultado:

 a 1 b 2 c 4 d 3 e 9 a 4 b 10 e 2 d 4 

Debería eliminar toda la fila.

Una manera fácil es usar rle :

Aquí está su muestra de datos:

 x <- scan(what = character(), text = "aaabccdeaabbbeedd") # Read 17 items 

rle devuelve una list con dos valores: la longitud de ejecución (" lengths ") y el valor que se repite para esa ejecución (" values ").

 rle(x)$values # [1] "a" "b" "c" "d" "e" "a" "b" "e" "d" 

Actualización: para un data.frame

Si está trabajando con un data.frame , intente algo como lo siguiente:

 ## Sample data mydf <- data.frame( V1 = c("a", "a", "a", "b", "c", "c", "d", "e", "a", "a", "b", "b", "e", "e", "d", "d"), V2 = c(1, 2, 3, 2, 4, 1, 3, 9, 4, 8, 10, 199, 2, 5, 4, 10) ) ## Use rle, as before X <- rle(mydf$V1) ## Identify the rows you want to keep Y <- cumsum(c(1, X$lengths[-length(X$lengths)])) Y # [1] 1 4 5 7 8 9 11 13 15 mydf[Y, ] # V1 V2 # 1 a 1 # 4 b 2 # 5 c 4 # 7 d 3 # 8 e 9 # 9 a 4 # 11 b 10 # 13 e 2 # 15 d 4 

Actualización 2

El paquete "data.table" tiene una función rleid que te permite hacer esto con bastante facilidad. Usando mydf desde arriba, intente:

 library(data.table) as.data.table(mydf)[, .SD[1], by = rleid(V1)] # rleid V2 # 1: 1 1 # 2: 2 2 # 3: 3 4 # 4: 4 3 # 5: 5 9 # 6: 6 4 # 7: 7 10 # 8: 8 2 # 9: 9 4 

Con la base R, me gustan los algoritmos graciosos:

 x <- c("a", "a", "a", "b", "c", "c", "d", "e", "a", "a", "b", "b", "b", "e", "e", "d", "d") x[x!=c(x[-1], FALSE)] #[1] "a" "b" "c" "d" "e" "a" "b" "e" "d" 
 library(dplyr) x <- c("a", "a", "a", "b", "c", "c", "d", "e", "a", "a", "b", "b", "b", "e", "e", "d", "d") x[x!=lag(x, default=1)] #[1] "a" "b" "c" "d" "e" "a" "b" "e" "d" 

EDITAR : para data.frame

  mydf <- data.frame( V1 = c("a", "a", "a", "b", "c", "c", "d", "e", "a", "a", "b", "b", "e", "e", "d", "d"), V2 = c(1, 2, 3, 2, 4, 1, 3, 9, 4, 8, 10, 199, 2, 5, 4, 10), stringsAsFactors=FALSE) 

La solución dplyr es un trazador de líneas:

 mydf %>% filter(V1!= lag(V1, default="1")) # V1 V2 #1 a 1 #2 b 2 #3 c 4 #4 d 3 #5 e 9 #6 a 4 #7 b 10 #8 e 2 #9 d 4 

publicar scriptum

lead(x,1) sugerido por @Carl Witthoft itera en orden inverso.

 leadit<-function(x) x!=lead(x, default="what") rows <- leadit(mydf[ ,1]) mydf[rows, ] # V1 V2 #3 a 3 #4 b 2 #6 c 1 #7 d 3 #8 e 9 #10 a 8 #12 b 199 #14 e 5 #16 d 10 

Por mucho que me gusta, … errr, amor , aquí hay un tiroteo:

EDITAR: No puedo averiguar exactamente qué dplyr con dplyr así que utilicé dplyr::lead . Estoy en OSX, R3.1.2 y último dplyr de CRAN.

 xlet<-sample(letters,1e5,rep=T) rleit<-function(x) rle(x)$values lagit<-function(x) x[x!=lead(x, default=1)] tailit<-function(x) x[x!=c(tail(x,-1), tail(x,1))] microbenchmark(rleit(xlet),lagit(xlet),tailit(xlet),times=20) Unit: milliseconds expr min lq median uq max neval rleit(xlet) 27.43996 30.02569 30.20385 30.92817 37.10657 20 lagit(xlet) 12.44794 15.00687 15.14051 15.80254 46.66940 20 tailit(xlet) 12.48968 14.66588 14.78383 15.32276 55.59840 20