cs0815
cs0815

Reputation: 17388

repeat dataframe n times whilst adding column

This is my reproducible code:

df <- data.frame(x = c(1, 2), y = c(3, 4))

df1 <- df %>% mutate(z = 1)
df2 <- df %>% mutate(z = 2)
df3 <- df %>% mutate(z = 3)

df <- rbind(df1, df2, df3)

df

I repeat the original data frame df 3 times, whilst adding one column where the number in the column indicated the repetition. In my use case, I have to do this more than 3 times. I could use a loop but is there a neater way? I guess i cannot use expand.grid.

Upvotes: 2

Views: 457

Answers (5)

ebeneditos
ebeneditos

Reputation: 2612

You can also do it with a merge:

dfz <- data.frame(z = 1:3)

merge(df, dfz)

#   x y z
# 1 1 3 1
# 2 2 4 1
# 3 1 3 2
# 4 2 4 2
# 5 1 3 3
# 6 2 4 3

Upvotes: 5

acylam
acylam

Reputation: 18661

We can also do a cross join with sqldf. This creates a Cartesian Product of df and the reps tables:

library(sqldf)
reps <- data.frame(z = 1:3)

sqldf("select * from df, reps order by z")

or simply with map_dfr from purrr:

library(purrr)

map_dfr(1:3, ~cbind(df, z = .))

Output:

  x y z
1 1 3 1
2 2 4 1
3 1 3 2
4 2 4 2
5 1 3 3
6 2 4 3

Upvotes: 3

Gregor Thomas
Gregor Thomas

Reputation: 145745

A few other ways not covered yet:

# setup
df = data.frame(x = c(1, 2), y = c(3, 4))
n = 3

# simple row indexing, add column manually
result = df[rep(1:nrow(df), 3), ]
result$id = rep(1:n, each = nrow(df))

# cross join in base
merge(df, data.frame(id = 1:n), by = NULL)

# cross join in tidyr
tidyr::crossing(df, data.frame(id = 1:n))

# dplyr version of the row-index method above
slice(df, rep(1:n(), n)) %>% mutate(id = rep(1:n, each = nrow(df)))

Inspiration drawn heavily from an old question of mine, How can I repeat a data frame?. Basically the same question but without the id column requirement.

Upvotes: 1

markus
markus

Reputation: 26333

Yet another option using base R

n <- 3
do.call(rbind, 
        Map(`[<-`, replicate(n = n, 
                             expr = df, 
                             simplify = FALSE), 
            "z", 
            value = seq_len(n)))
#  x y z
#1 1 3 1
#2 2 4 1
#3 1 3 2
#4 2 4 2
#5 1 3 3
#6 2 4 3

Upvotes: 1

akrun
akrun

Reputation: 886938

We can create a list column and unnest

library(tidyverse)
df %>%
   mutate(z = list(1:3)) %>%
   unnest %>%
   arrange(z)
#  x y z
#1 1 3 1
#2 2 4 1
#3 1 3 2
#4 2 4 2
#5 1 3 3
#6 2 4 3

Upvotes: 3

Related Questions