Divide un vector en trozos en R

Tengo que dividir un vector en n trozos de igual tamaño en R. No pude encontrar ninguna función base para hacer eso. Además, Google no me llevó a ninguna parte. Así que esto es lo que se me ocurrió, con suerte, ayuda a alguien en algún lugar.

x <- 1:10 n <- 3 chunk <- function(x,n) split(x, factor(sort(rank(x)%%n))) chunk(x,n) $`0` [1] 1 2 3 $`1` [1] 4 5 6 7 $`2` [1] 8 9 10 

Cualquier comentario, sugerencia o mejora es realmente bienvenido y apreciado.

Saludos, Sebastian

Una división de un trazador de líneas en trozos de tamaño 20:

 split(d, ceiling(seq_along(d)/20)) 

Más detalles: creo que todo lo que necesita es seq_along() , split() y ceiling() :

 > d <- rpois(73,5) > d [1] 3 1 11 4 1 2 3 2 4 10 10 2 7 4 6 6 2 1 1 2 3 8 3 10 7 4 [27] 3 4 4 1 1 7 2 4 6 0 5 7 4 6 8 4 7 12 4 6 8 4 2 7 6 5 [53] 4 5 4 5 5 8 7 7 7 6 2 4 3 3 8 11 6 6 1 8 4 > max <- 20 > x <- seq_along(d) > d1 <- split(d, ceiling(x/max)) > d1 $`1` [1] 3 1 11 4 1 2 3 2 4 10 10 2 7 4 6 6 2 1 1 2 $`2` [1] 3 8 3 10 7 4 3 4 4 1 1 7 2 4 6 0 5 7 4 6 $`3` [1] 8 4 7 12 4 6 8 4 2 7 6 5 4 5 4 5 5 8 7 7 $`4` [1] 7 6 2 4 3 3 8 11 6 6 1 8 4 
 chunk2 <- function(x,n) split(x, cut(seq_along(x), n, labels = FALSE)) 

Esto lo dividirá de manera diferente a lo que tienes, pero creo que sigue siendo una buena estructura de listas:

 chunk.2 <- function(x, n, force.number.of.groups = TRUE, len = length(x), groups = trunc(len/n), overflow = len%%n) { if(force.number.of.groups) { f1 <- as.character(sort(rep(1:n, groups))) f <- as.character(c(f1, rep(n, overflow))) } else { f1 <- as.character(sort(rep(1:groups, n))) f <- as.character(c(f1, rep("overflow", overflow))) } g <- split(x, f) if(force.number.of.groups) { g.names <- names(g) g.names.ordered <- as.character(sort(as.numeric(g.names))) } else { g.names <- names(g[-length(g)]) g.names.ordered <- as.character(sort(as.numeric(g.names))) g.names.ordered <- c(g.names.ordered, "overflow") } return(g[g.names.ordered]) } 

Lo cual le dará lo siguiente, dependiendo de cómo lo quiera formatear:

 > x <- 1:10; n <- 3 > chunk.2(x, n, force.number.of.groups = FALSE) $`1` [1] 1 2 3 $`2` [1] 4 5 6 $`3` [1] 7 8 9 $overflow [1] 10 > chunk.2(x, n, force.number.of.groups = TRUE) $`1` [1] 1 2 3 $`2` [1] 4 5 6 $`3` [1] 7 8 9 10 

Ejecutando un par de sincronizaciones usando estas configuraciones:

 set.seed(42) x <- rnorm(1:1e7) n <- 3 

Entonces tenemos los siguientes resultados:

 > system.time(chunk(x, n)) # your function user system elapsed 29.500 0.620 30.125 > system.time(chunk.2(x, n, force.number.of.groups = TRUE)) user system elapsed 5.360 0.300 5.663 

EDITAR: Cambiar de as.factor () a as.character () en mi función lo hizo dos veces más rápido.

 simplified version... n = 3 split(x, sort(x%%n)) 

Prueba la función cut_number , cut_number :

 library(ggplot2) x <- 1:10 n <- 3 cut_number(x, n) # labels = FALSE if you just want an integer result #> [1] [1,4] [1,4] [1,4] [1,4] (4,7] (4,7] (4,7] (7,10] (7,10] (7,10] #> Levels: [1,4] (4,7] (7,10] # if you want it split into a list: split(x, cut_number(x, n)) #> $`[1,4]` #> [1] 1 2 3 4 #> #> $`(4,7]` #> [1] 5 6 7 #> #> $`(7,10]` #> [1] 8 9 10 

Algunas variantes más a la stack …

 > x <- 1:10 > n <- 3 

Tenga en cuenta que no necesita usar la función de factor aquí, pero aún quiere sort el primer vector sería 1 2 3 10 :

 > chunk <- function(x, n) split(x, sort(rank(x) %% n)) > chunk(x,n) $`0` [1] 1 2 3 $`1` [1] 4 5 6 7 $`2` [1] 8 9 10 

O puede asignar índices de caracteres, vicio a los números en los tics de la izquierda de arriba:

 > my.chunk <- function(x, n) split(x, sort(rep(letters[1:n], each=n, len=length(x)))) > my.chunk(x, n) $a [1] 1 2 3 4 $b [1] 5 6 7 $c [1] 8 9 10 

O puede usar nombres de palabras simples almacenados en un vector. Tenga en cuenta que el uso de sort para obtener valores consecutivos en x alfabetiza las tags:

 > my.other.chunk <- function(x, n) split(x, sort(rep(c("tom", "dick", "harry"), each=n, len=length(x)))) > my.other.chunk(x, n) $dick [1] 1 2 3 $harry [1] 4 5 6 $tom [1] 7 8 9 10 

Puede combinar la división / corte, como lo sugiere mdsummer, con quantile para crear grupos pares:

 split(x,cut(x,quantile(x,(0:n)/n), include.lowest=TRUE, labels=FALSE)) 

Esto le da el mismo resultado para su ejemplo, pero no para las variables asimétricas.

Aquí hay otra variante.

NOTA: con esta muestra está especificando el TAMAÑO DE CHUNK en el segundo parámetro

  1. todos los trozos son uniformes, excepto el último;
  2. el último será, en el peor de los casos, más pequeño, nunca más grande que el tamaño del fragmento.
 chunk <- function(x,n) { f <- sort(rep(1:(trunc(length(x)/n)+1),n))[1:length(x)] return(split(x,f)) } #Test n<-c(1,2,3,4,5,6,7,8,9,10,11) c<-chunk(n,5) q<-lapply(c, function(r) cat(r,sep=",",collapse="|") ) #output 1,2,3,4,5,|6,7,8,9,10,|11,| 

split(x,matrix(1:n,n,length(x))[1:length(x)])

quizás esto es más claro, pero la misma idea:
split(x,rep(1:n, ceiling(length(x)/n),length.out = length(x)))

si lo quieres ordenado, haz una especie de rodeo

Necesitaba la misma función y había leído las soluciones anteriores, sin embargo, también necesitaba tener el fragmento desequilibrado para estar al final, es decir, si tengo 10 elementos para dividirlos en vectores de 3 cada uno, entonces mi resultado debería tener vectores con 3, 3,4 elementos respectivamente. Así que utilicé lo siguiente (dejé el código sin optimizar para la legibilidad, de lo contrario no es necesario tener muchas variables):

 chunk <- function(x,n){ numOfVectors <- floor(length(x)/n) elementsPerVector <- c(rep(n,numOfVectors-1),n+length(x) %% n) elemDistPerVector <- rep(1:numOfVectors,elementsPerVector) split(x,factor(elemDistPerVector)) } set.seed(1) x <- rnorm(10) n <- 3 chunk(x,n) $`1` [1] -0.6264538 0.1836433 -0.8356286 $`2` [1] 1.5952808 0.3295078 -0.8204684 $`3` [1] 0.4874291 0.7383247 0.5757814 -0.3053884 

Función simple para dividir un vector simplemente usando índices: no hay necesidad de complicar demasiado esto

 vsplit <- function(v, n) { l = length(v) r = l/n return(lapply(1:n, function(i) { s = max(1, round(r*(i-1))+1) e = min(l, round(r*i)) return(v[s:e]) })) } 

Si no te gusta split() y no te gusta matrix() (con sus NA colgantes), hay esto:

 chunk <- function(x, n) (mapply(function(a, b) (x[a:b]), seq.int(from=1, to=length(x), by=n), pmin(seq.int(from=1, to=length(x), by=n)+(n-1), length(x)), SIMPLIFY=FALSE)) 

Al igual que split() , devuelve una lista, pero no pierde tiempo ni espacio con las tags, por lo que puede ser más eficaz.

Gracias a @Sebastian por esta función

 chunk <- function(x,y){ split(x, factor(sort(rank(row.names(x))%%y))) } 

Si no te gusta la split() y no te importa que las NAs rellenen tu cola corta:

 chunk <- function(x, n) { if((length(x)%%n)==0) {return(matrix(x, nrow=n))} else {return(matrix(append(x, rep(NA, n-(length(x)%%n))), nrow=n))} } 

Las columnas de la matriz devuelta ([, 1: ncol]) son los droides que está buscando.

Necesito una función que tome el argumento de un data.table (entre comillas) y otro argumento que sea el límite superior sobre el número de filas en los subconjuntos de ese data.table original. Esta función produce cualquier cantidad de datos. Tablas que el límite superior permite:

 library(data.table) split_dt <- function(x,y) { for(i in seq(from=1,to=nrow(get(x)),by=y)) {df_ <<- get(x)[i:(i + y)]; assign(paste0("df_",i),df_,inherits=TRUE)} rm(df_,inherits=TRUE) } 

Esta función me da una serie de tablas de datos llamadas df_ [número] con la fila inicial de la tabla de datos original en el nombre. La última tabla de datos puede ser corta y estar llena de NA, por lo que debe subconjuntarla a los datos que queden. Este tipo de función es útil porque ciertos progtwigs GIS tienen límites sobre cuántos pines de dirección puede importar, por ejemplo. Por lo tanto, no es recomendable dividir los datos en tablas en trozos más pequeños, pero puede que no se pueda evitar.

Lo siento si esta respuesta llega tan tarde, pero tal vez puede ser útil para otra persona. En realidad, hay una solución muy útil para este problema, explicada al final de? Split.

 > testVector <- c(1:10) #I want to divide it into 5 parts > VectorList <- split(testVector, 1:5) > VectorList $`1` [1] 1 6 $`2` [1] 2 7 $`3` [1] 3 8 $`4` [1] 4 9 $`5` [1] 5 10