4

It's easy to repeat a data.frame once,

mt2 <- rbind(mtcars, mtcars)

But what's an R-like way to do this generally? If I want 10 copies of mtcars together I could

mt10 <- mtcars
for (i in 2:10) mt10 <- rbind(mt10, mtcars)

which is plenty concise, but seems not in the spirit of R. Is there a better way to do this, or a clever trick using vector recycling?

Gregor Thomas
  • 136,190
  • 20
  • 167
  • 294

4 Answers4

8

Here's a very simple method:

mtcars[rep(1:nrow(mtcars),2),]

or using better "grammar":

mtcars[rep(seq_len(nrow(mtcars)),2),]

As GSee notes below, one difference here is that rbind will replicate the row names exactly, while using indexing will force unique row names by appending digits. Off the top of my head, I think the only fix would be to set the row names (again using rep) after the fact.

joran
  • 169,992
  • 32
  • 429
  • 468
  • Although that gives different rownames, so `identical(rbind(mtcars, mtcars), mtcars[rep(1:nrow(mtcars),2),])` is FALSE – GSee Nov 07 '12 at 17:51
  • I was disappointed that `rep(mtcars, 10)` didn't work, but of course this is the way to go about it with `rep`. – Gregor Thomas Nov 07 '12 at 17:52
6

@joran's answer is very elegant and you should use it if duplicating the rownames isn't required. However, this way will also duplicate the rownames:

do.call(rbind, replicate(10, mtcars[1:10, ], simplify=FALSE))

Matthew Plourde
  • 43,932
  • 7
  • 96
  • 113
3

If you can tolerate another package:

require(mefa)
rep(mtcars,10)
  • works after all!

It appears a little faster:

system.time(mtcars[rep(1:nrow(mtcars),1e5),])
system.time(mtcars[rep(seq_len(nrow(mtcars)),1e5),])
system.time(rep(mtcars,1e5))

Gives:

 user  system elapsed 
 17.41    0.19   17.89
 17.11    0.31   17.91
 6.79    0.70    7.67

Caveats: 1) rep will not reproduce the row names; this is a separate step. 2) mefa::rep(mtcars,10) doesn't work as: Error: 'rep' is not an exported object from 'namespace:mefa'. Also mefa:::rep(mtcars,10) gives object 'rep' not found. Not sure why this is...

dardisco
  • 5,086
  • 2
  • 39
  • 54
  • 2
    Because what `mefa` provides is a `rep` method for data.frames, so `mefa:::rep.data.frame(mtcars, 10)` works. – Gregor Thomas Nov 11 '12 at 03:29
  • 2
    Also, looking at `mefa:::rep.data.frame`, it's a one-liner so no need to load the package. `rep.data.frame <- function(x, ...) as.data.frame(lapply(x, rep, ...))` – Gregor Thomas Nov 11 '12 at 18:35
1

dplyr-based solution (from here)

library(dplyr)
mtcars %>% slice(rep(1:n(), 2))  # 2 copies of data frame
David Rubinger
  • 3,580
  • 1
  • 20
  • 29