2012-01-06 43 views
39

Tôi có khung dữ liệu sauLặp lại data.frame N lần

data.frame(a = c(1,2,3),b = c(1,2,3)) 
    a b 
1 1 1 
2 2 2 
3 3 3 

và tôi muốn biến nó thành

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 

hoặc lặp lại nó N lần. Có một chức năng dễ dàng để làm điều này trong R? Cảm ơn!

Trả lời

66

Bạn có thể sử dụng replicate(), sau đó rbind kết quả lại với nhau. Các rownames được tự động thay đổi để chạy từ 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)) 

Một cách truyền thống hơn là sử dụng lập chỉ mục, nhưng ở đây làm thay đổi rowname không phải là khá nên gọn gàng (nhưng thông tin mới hơn):

d[rep(seq_len(nrow(d)), n), ] 
+4

Hãy coi chừng khung dữ liệu hàng không. seq_len có lẽ là một lựa chọn tốt hơn – hadley

+1

Cảm ơn, tôi đã mơ hồ về điều đó (tôi luôn nghĩ rằng đó là seq_along và không nỗ lực). Tôi đánh giá cao những người đứng đầu. – mdsumner

3
d <- data.frame(a = c(1,2,3),b = c(1,2,3)) 
r <- Reduce(rbind, list(d)[rep(1L, times=3L)]) 
+2

Chăm sóc để xây dựng những gì bạn vừa làm và làm thế nào nó so sánh với câu trả lời của mdsumner? Có lẽ dán vào một số kết quả? –

16

Đối data.frame đối tượng, giải pháp này là nhiều nhanh hơn so với @ mdsummer's và @ wojciech-sobala's.

d[rep(seq_len(nrow(d)), n), ] 

Đối data.table đối tượng, @ mdsummer là nhanh hơn so với việc áp dụng trên sau khi chuyển đổi để data.frame một chút. Đối với lớn n này có thể lật. microbenchmark.

Full mã:

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)) 
2

Chỉ cần sử dụng chỉ mục đơn giản với chức năng lặp lại.

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 
8

Gói dplyr chứa các chức năng bind_rows() trực tiếp kết hợp tất cả các khung dữ liệu trong một danh sách, như vậy mà không có nhu cầu sử dụng do.call() cùng với rbind():

df <- data.frame(a = c(1, 2, 3), b = c(1, 2, 3)) 
library(dplyr) 
bind_rows(replicate(3, df, simplify = FALSE)) 

Đối với một số lượng lớn các repetions bind_rows() cũng nhanh hơn nhiều so với 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 
+0

Tôi đoán 'slice (rep (row_number(), 3))' là tốt hơn, theo điểm chuẩn của Max. Oh, chỉ cần nhìn thấy băng ghế dự bị của bạn ... cá nhân, tôi nghĩ rằng mở rộng quy mô của DF phần nào sẽ là đúng hướng, chứ không phải là số lượng các bảng, nhưng tôi không biết. – Frank

+1

Đẹp nhất! Khi tôi chuẩn nó, 'slice (df, rep (row_number(), 3))' hóa ra là chậm hơn một chút so với 'bind_rows (replicate (...))' (1.9 so với 2.1 ms). Trong mọi trường hợp, tôi nghĩ hữu ích khi có một giải pháp 'dplyr' là tốt ... – Stibu

+1

@Frank Bạn có lẽ đúng. Tôi đã không kiểm tra những gì xảy ra cho các khung dữ liệu lớn, vì tôi chỉ sử dụng khung được cung cấp trong câu hỏi. – Stibu

Các vấn đề liên quan