Repite las filas de un data.frame
dataframe rows (9)
Agregando a lo que @dardisco mencionó sobre mefa::rep.data.frame()
, es muy flexible.
Puedes repetir cada fila N veces :
rep(df, each=N)
o repita todo el dataframe N veces (piense: como cuando recicla un argumento vectorizado)
rep(df, times=N)
¡Dos pulgares arriba para mefa
! Nunca había oído hablar de él hasta ahora y tuve que escribir el código manual para hacer esto.
Quiero repetir las filas de un data.frame, cada N
veces. El resultado debe ser un nuevo data.frame
(con nrow(new.df) == nrow(old.df) * N
) manteniendo los tipos de datos de las columnas.
Ejemplo para N = 2:
A B C
A B C 1 j i 100
1 j i 100 --> 2 j i 100
2 K P 101 3 K P 101
4 K P 101
Entonces, cada fila se repite 2 veces y los caracteres se mantienen, los factores siguen siendo factores, los números siguen siendo numéricos, ...
Mi primer intento utilizado apply: apply(old.df, 2, function(co) rep(co, each = N))
, pero este transforma mis valores en caracteres y obtengo:
A B C
[1,] "j" "i" "100"
[2,] "j" "i" "100"
[3,] "K" "P" "101"
[4,] "K" "P" "101"
La función rep.row parece a veces hacer listas para columnas, lo que conduce a hijinks de mala memoria. He escrito lo siguiente que parece funcionar bien:
library(plyr)
rep.row <- function(r, n){
colwise(function(x) rep(x, n))(r)
}
Mi solución es similar a mefa:::rep.data.frame
, pero un poco más rápido y se preocupa por los nombres de las filas:
rep.data.frame <- function(x, times) {
rnames <- attr(x, "row.names")
x <- lapply(x, rep.int, times = times)
class(x) <- "data.frame"
if (!is.numeric(rnames))
attr(x, "row.names") <- make.unique(rep.int(rnames, times))
else
attr(x, "row.names") <- .set_row_names(length(rnames) * times)
x
}
Compare soluciones:
library(Lahman)
library(microbenchmark)
microbenchmark(
mefa:::rep.data.frame(Batting, 10),
rep.data.frame(Batting, 10),
Batting[rep.int(seq_len(nrow(Batting)), 10), ],
times = 10
)
#> Unit: milliseconds
#> expr min lq mean median uq max neval cld
#> mefa:::rep.data.frame(Batting, 10) 127.77786 135.3480 198.0240 148.1749 278.1066 356.3210 10 a
#> rep.data.frame(Batting, 10) 79.70335 82.8165 134.0974 87.2587 191.1713 307.4567 10 a
#> Batting[rep.int(seq_len(nrow(Batting)), 10), ] 895.73750 922.7059 981.8891 956.3463 1018.2411 1127.3927 10 b
Otra forma de hacer esto sería obtener primero los índices de fila, anexar copias adicionales de la df, y luego ordenar por los índices:
df$index = 1:nrow(df)
df = rbind(df,df)
df = df[order(df$index),][,-ncol(df)]
Aunque las otras soluciones pueden ser más cortas, este método puede ser más ventajoso en ciertas situaciones.
Para referencia y agregar respuestas que citan mefa, vale la pena echar un vistazo a la implementación de mefa::rep.data.frame()
en caso de que no desee incluir todo el paquete:
> data <- data.frame(a=letters[1:3], b=letters[4:6])
> data
a b
1 a d
2 b e
3 c f
> as.data.frame(lapply(data, rep, 2))
a b
1 a d
2 b e
3 c f
4 a d
5 b e
6 c f
Si puede repetir todo o subconjunto primero y luego repetirlo, esta pregunta similar puede ser útil. Una vez más:
library(mefa)
rep(mtcars,10)
o simplemente
mefa:::rep.data.frame(mtcars)
Una solución dplyr
limpia, tomada de here
library(dplyr)
df <- data_frame(x = 1:2, y = c("a", "b"))
df %>% slice(rep(1:n(), each = 2))
intente usar, por ejemplo
N=2
rep(1:4, each = N)
como un índice
df <- data.frame(a=1:2, b=letters[1:2])
df[rep(seq_len(nrow(df)), each=2),]