detectar intervalos de las secuencias de enteros consecuentes

Tengo dos vectores de entero. Me gustaría identificar los intervalos de secuencias enteras consecutivas presentadas en el segundo vector condicionado por el primer vector (este vector puede verse como un factor, por lo que el segundo vector se puede clasificar en varios grupos).

Aquí presento un maniquí para mi problema.

Los datos, en un grupo (definido por el primer vector) del segundo vector, los números enteros monótonamente aumentan.

my.data <- data.frame( V1=c(rep(1, 10), rep(2, 9), rep(3,11)), V2=c(seq(2,5), seq(7,11), 13, seq(4, 9), seq(11,13), seq(1, 6), seq(101, 105)) ) 

Lo que quiero:

  • salida el comienzo y el final del intervalo
  • aquí, grupo en la primera columna, el número entero inicial en el segundo, el número entero final en el tercero.

Resultados previstos:

 1, 2, 5 \n 1, 7, 11 \n 1, 13, 13 \n 2, 4, 9 \n 2, 11, 13 \n 3, 1, 6 \n 3, 101, 105 \n 

Aquí hay una respuesta breve usando agregado ….

 runs <- cumsum( c(0, diff(my.data$V2) > 1) ) aggregate(V2 ~ runs + V1, my.data, range)[,-1] V1 V2.1 V2.2 1 1 2 5 2 1 7 11 3 1 13 13 4 2 4 9 5 2 11 13 6 3 1 6 7 3 101 105 

Hace un tiempo, escribí una variante de rle() que seqle() porque permite buscar secuencias enteras en lugar de repeticiones. Entonces, puedes hacer:

 Rgames: seqle(my.data[my.data$V1==1,2]) #repeat for my.data$V1 equal to 2 and 3 $lengths [1] 4 5 1 $values [1] 2 7 13 

(por ejemplo). Se necesitaría un poco de manipulación para obtener estos resultados en la forma tabular que desea, pero pensé que lo mencionaría. Por cierto, aquí está el código de seqle . Si establece incr=0 obtendrá el resultado base.

 function(x,incr=1){ if(!is.numeric(x)) x <- as.numeric(x) n <- length(x) y <- x[-1L] != x[-n] + incr i <- c(which(y|is.na(y)),n) list( lengths = diff(c(0L,i)), values = x[head(c(0L,i)+1L,-1L)]) } 

EDITAR: hay una excelente actualización de esto, proporcionada por flodel, en Cómo verificar si un vector contiene n números consecutivos . Señaló que esta versión tiene los problemas habituales de error de coma flotante cuando se trabaja con dobles, y proporciona una solución también.

Aquí hay un ejemplo:

 library(plyr) ddply(my.data, .(V1), function(x) data.frame(do.call("rbind", tapply(x$V2, cumsum(c(T, diff(x$V2)!=1)), function(y) c(min(y), max(y)))))) 

tal vez, demasiado complicado, pero lo que es importante es la cumsum(c(T, diff(x$V2)!=1)) .

 > ddply(my.data, .(V1), + function(x) data.frame(do.call("rbind", tapply(x$V2, cumsum(c(T, diff(x$V2)!=1)), + function(y) c(min(y), max(y)))))) V1 X1 X2 1 1 2 5 2 1 7 11 3 1 13 13 4 2 4 9 5 2 11 13 6 3 1 6 7 3 101 105 

Aquí hay una solución usando ddply del paquete plyr . La idea básica es ver cuándo diff(x) no es 1, para encontrar los puntos de cambio.

 ddply( my.data, .(V1), summarise, lower = { cut_points <- which(diff(V2) != 1) V2[c(1, cut_points + 1)] }, upper = { cut_points <- which(diff(V2) != 1) V2[c(cut_points, length(V2))] } ) 
 my.data$run <- ave(my.data$V2, my.data$V1, FUN=function(x) c(1, diff(x))) strstp <- by(my.data, list(my.data$V1), FUN=function(x) list( starts=c( head(x$V2,1), x$V2[x$run != 1]), stops=c(x$V2[which(x$run != 1)-1], tail(x$V2, 1)))) > strstp : 1 $starts [1] 2 7 13 $stops [1] 5 11 13 ------------------------------------------------------------- : 2 $starts [1] 4 11 $stops [1] 9 13 ------------------------------------------------------------- : 3 $starts [1] 1 101 $stops [1] 6 105