mtcars - Repita data.frame N veces
r data frame mtcars (5)
EDIT: actualizado a una mejor respuesta R moderna.
Puede usar replicate()
y luego rbind
el resultado. Los nombres de fila se modifican automáticamente para ejecutarse desde 1: nrows.
d <- data.frame(a = c(1,2,3),b = c(1,2,3))
n <- 3
do.call("rbind", replicate(n, d, simplify = FALSE))
Una forma más tradicional es usar indexación, pero aquí la alteración del nombre de fila no es tan clara (pero más informativa):
d[rep(seq_len(nrow(d)), n), ]
Aquí hay mejoras en los anteriores, los dos primeros usan programación funcional purrr
, purrr idiomático:
purrr::map_df(seq_len(3), ~d)
y menos purrr idiomático (resultado idéntico, aunque más incómodo):
purrr::map_df(seq_len(3), function(x) d)
y finalmente a través de la indexación en lugar de la lista aplicar usando dplyr
:
d %>% slice(rep(row_number(), 3))
Tengo el siguiente marco de datos
data.frame(a = c(1,2,3),b = c(1,2,3))
a b
1 1 1
2 2 2
3 3 3
y quiero convertirlo en
a b
1 1 1
2 2 2
3 3 3
4 1 1
5 2 2
6 3 3
7 1 1
8 2 2
9 3 3
o repítelo N veces. ¿Hay una función fácil de hacer esto en R? ¡Gracias!
El paquete dplyr
contiene la función bind_rows()
que combina directamente todos los marcos de datos en una lista, de modo que no hay necesidad de usar do.call()
junto con rbind()
:
df <- data.frame(a = c(1, 2, 3), b = c(1, 2, 3))
library(dplyr)
bind_rows(replicate(3, df, simplify = FALSE))
Para una gran cantidad de repeticiones bind_rows()
también es mucho más rápido que rbind()
:
library(microbenchmark)
microbenchmark(rbind = do.call("rbind", replicate(1000, df, simplify = FALSE)),
bind_rows = bind_rows(replicate(1000, df, simplify = FALSE)),
times = 20)
## Unit: milliseconds
## expr min lq mean median uq max neval cld
## rbind 31.796100 33.017077 35.436753 34.32861 36.773017 43.556112 20 b
## bind_rows 1.765956 1.818087 1.881697 1.86207 1.898839 2.321621 20 a
Para objetos data.frame
, esta solución es varias veces más rápida que @ mdsummer y @ wojciech-sobala.
d[rep(seq_len(nrow(d)), n), ]
Para objetos data.table
, @ mdsummer es un poco más rápido que aplicar lo anterior después de convertir a data.frame
. Para n grande, esto podría voltearse. .
Código completo:
Repeat1 <- function(d, n) {
return(do.call("rbind", replicate(n, d, simplify = FALSE)))
}
Repeat2 <- function(d, n) {
return(Reduce(rbind, list(d)[rep(1L, times=n)]))
}
Repeat3 <- function(d, n) {
if ("data.table" %in% class(d)) return(d[rep(seq_len(nrow(d)), n)])
return(d[rep(seq_len(nrow(d)), n), ])
}
Repeat3.dt.convert <- function(d, n) {
if ("data.table" %in% class(d)) d <- as.data.frame(d)
return(d[rep(seq_len(nrow(d)), n), ])
}
# Try with data.frames
mtcars1 <- Repeat1(mtcars, 3)
mtcars2 <- Repeat2(mtcars, 3)
mtcars3 <- Repeat3(mtcars, 3)
library(RUnit)
checkEquals(mtcars1, mtcars2)
# Only difference is row.names having ".k" suffix instead of "k" from 1 & 2
checkEquals(mtcars1, mtcars3)
# Works with data.tables too
mtcars.dt <- data.table(mtcars)
mtcars.dt1 <- Repeat1(mtcars.dt, 3)
mtcars.dt2 <- Repeat2(mtcars.dt, 3)
mtcars.dt3 <- Repeat3(mtcars.dt, 3)
# No row.names mismatch since data.tables don''t have row.names
checkEquals(mtcars.dt1, mtcars.dt2)
checkEquals(mtcars.dt1, mtcars.dt3)
# Time test
library(microbenchmark)
res <- microbenchmark(Repeat1(mtcars, 10),
Repeat2(mtcars, 10),
Repeat3(mtcars, 10),
Repeat1(mtcars.dt, 10),
Repeat2(mtcars.dt, 10),
Repeat3(mtcars.dt, 10),
Repeat3.dt.convert(mtcars.dt, 10))
print(res)
library(ggplot2)
ggsave("~/gdrive/repeat_microbenchmark.png", autoplot(res))
Simplemente use indexación simple con función de repetición.
mydata<-data.frame(a = c(1,2,3),b = c(1,2,3)) #creating your data frame
n<-10 #defining no. of time you want repetition of the rows of your dataframe
mydata<-mydata[rep(rownames(mydata),n),] #use rep function while doing indexing
rownames(mydata)<-1:NROW(mydata) #rename rows just to get cleaner look of data
d <- data.frame(a = c(1,2,3),b = c(1,2,3))
r <- Reduce(rbind, list(d)[rep(1L, times=3L)])