2012-07-27 12 views
22

tengo un hoja.de.datos df y quiero que cada fila de esta df se duplica lengthTime veces y que se añade una nueva columna que cuenta de 1 a lengthTime para cada fila de df .alternativa a expand.grid para data.frames

Lo sé, suena bastante complicado, pero lo que básicamente quiero es aplicar expand.grid a df. Aquí es una solución fea y tengo la sensación de que la mayoría de ser una solución más fácil (tal vez incluso una función de base-R?):

df <- data.frame(ID = rep(letters[1:3], each=3), 
       CatA = rep(1:3, times = 3), 
       CatB = letters[1:9]) 
lengthTime <- 3 
nrRow <- nrow(df) 
intDF <- df 
for (i in 1:(lengthTime - 1)) { 
    df <- rbind(df, intDF) 
} 
df$Time <- rep(1:lengthTime, each=nrRow) 

pensé que solo podía usar expand.grid(df, 1:lengthTime), pero eso no quiere trabajar. outer tampoco trajo ninguna suerte. Entonces, ¿alguien sabe una buena solución?

Respuesta

13

¿Por qué no simplemente algo como df[rep(1:nrow(df),times = 3),] para ampliar el marco de datos, y luego agregar la columna adicional como la anterior, con df$Time <- rep(1:lengthTime, each=nrRow)?

2

Esto funciona:

REP <- rep(1:nrow(df), 3) 
df2 <- data.frame(df[REP, ], Time = rep(1:3, each = 9)) 
rownames(df2) <- NULL 
df2 
+0

La mina realmente no es diferente a la de joran que me ha ganado por 40 segundos, pero lo dejo ya que es un poco más explícito. –

+0

Primero en llegar, primer servicio, así que acepté su respuesta ;-) Pero +1 para los dos. ¡Esa es una solución muy buena! –

36

Ha sido un tiempo desde que esta pregunta fue publicada, pero recientemente me encontré con él en busca de la cosa en el título, es decir, un expand.grid que funcione para tramas de datos. Las respuestas publicadas abordan pregunta más específica de la OP, por lo que en caso de que alguien está buscando una solución más general para tramas de datos, aquí hay un enfoque ligeramente más general:

expand.grid.df <- function(...) Reduce(function(...) merge(..., by=NULL), list(...)) 

# For the example in the OP 
expand.grid.df(df, data.frame(1:lengthTime)) 

# More generally 
df1 <- data.frame(A=1:3, B=11:13) 
df2 <- data.frame(C=51:52, D=c("Y", "N")) 
df3 <- data.frame(E=c("+", "-")) 
expand.grid.df(df1, df2, df3) 
+1

Hermosa solución. – Ariel

+1

Wow. Este es un gran trabajo. – jknowles

9

También se puede simplemente hacer una simple merge usando NULL como fusionar columna (lo que hará que merge hacer sencilla la replicación de datos combinatoria):

data.frame(time=1:lengthTime) %>% merge(iris, by=NULL) 

la tubería operador %>% proviene del paquete magrittr (dplyr también adjuntarlo automáticamente) y se acaba de usar para Impro ve legibilidad También puede sencillo hacer merge(iris, data.frame(...), by=NULL)

+0

Creo que es posible que desee mencionar dónde tomó '%>%' de a ... –

+0

@DavidArenburg gracias por la pista. –

1

Una solución data.table:

> library(data.table) 
> (df <- data.frame(ID = rep(letters[1:3], each=3), 
+     CatA = rep(1:3, times = 3), 
+     CatB = letters[1:9])) 
    ID CatA CatB 
1 a 1 a 
2 a 2 b 
3 a 3 c 
4 b 1 d 
5 b 2 e 
6 b 3 f 
7 c 1 g 
8 c 2 h 
9 c 3 i 
> (DT <- data.table(df)[, lapply(.SD, function(x) rep(x,3))][, Time:=rep(1:3, each=nrow(df0))]) 
    ID CatA CatB Time 
1: a 1 a 1 
2: a 2 b 1 
3: a 3 c 1 
4: b 1 d 1 
5: b 2 e 1 
6: b 3 f 1 
7: c 1 g 1 
8: c 2 h 1 
9: c 3 i 1 
10: a 1 a 2 
11: a 2 b 2 
12: a 3 c 2 
13: b 1 d 2 
14: b 2 e 2 
15: b 3 f 2 
16: c 1 g 2 
17: c 2 h 2 
18: c 3 i 2 
19: a 1 a 3 
20: a 2 b 3 
21: a 3 c 3 
22: b 1 d 3 
23: b 2 e 3 
24: b 3 f 3 
25: c 1 g 3 
26: c 2 h 3 
27: c 3 i 3 

Otra:

> library(data.table) 
> (df <- data.frame(ID = rep(letters[1:3], each=3), 
+     CatA = rep(1:3, times = 3), 
+     CatB = letters[1:9])) 
> DT <- data.table(df) 
> rbindlist(lapply(1:3, function(i) cbind(DT, Time=i))) 
    ID CatA CatB Time 
1: a 1 a 1 
2: a 2 b 1 
3: a 3 c 1 
4: b 1 d 1 
5: b 2 e 1 
6: b 3 f 1 
7: c 1 g 1 
8: c 2 h 1 
9: c 3 i 1 
10: a 1 a 2 
11: a 2 b 2 
12: a 3 c 2 
13: b 1 d 2 
14: b 2 e 2 
15: b 3 f 2 
16: c 1 g 2 
17: c 2 h 2 
18: c 3 i 2 
19: a 1 a 3 
20: a 2 b 3 
21: a 3 c 3 
22: b 1 d 3 
23: b 2 e 3 
24: b 3 f 3 
25: c 1 g 3 
26: c 2 h 3 
27: c 3 i 3 
5

Rápida actualización

En la actualidad existe también la función de cruce() en tidyr paquete que se puede usar en lugar de fusionar, es algo más rápido y devuelve un tbl_df/tibble.

data.frame(time=1:10) %>% merge(iris, by=NULL) 

data.frame(time=1:10) %>% tidyr::crossing(iris)