2012-06-20 41 views
49

Tôi muốn lặp lại các hàng của một data.frame, mỗi N lần. Kết quả phải là một data.frame mới (với nrow(new.df) == nrow(old.df) * N) giữ các kiểu dữ liệu của các cột.Lặp lại các hàng của một data.frame

Ví dụ cho 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 

Vì vậy, mỗi hàng được lặp lại 2 lần và các nhân vật vẫn còn nhân vật, các yếu tố duy trì yếu tố, numerics vẫn numerics, ...

nỗ lực đầu tiên của tôi sử dụng áp dụng : apply(old.df, 2, function(co) rep(co, each = N)), nhưng điều này biến đổi các giá trị của tôi để các nhân vật và tôi nhận được:

 A B C  
[1,] "j" "i" "100" 
[2,] "j" "i" "100" 
[3,] "K" "P" "101" 
[4,] "K" "P" "101" 
+0

trùng lặp có thể xảy ra của [Lặp lại data.frame N lần] (http://stackoverflow.com/questions/8753531/repeat-data-frame-n-times) –

Trả lời

84
df <- data.frame(a=1:2, b=letters[1:2]) 
df[rep(seq_len(nrow(df)), each=2),] 
+12

Bạn có thể sử dụng 'n.times <- c (2,4); df [rep (seq_len (nrow (df)), n.times),] 'nếu bạn muốn thay đổi số lần lặp lại mỗi dòng. –

4

Nếu bạn có thể lặp lại toàn bộ sự việc, hoặc tập hợp con nó đầu tiên sau đó lặp lại rằng, sau đó this similar question có thể hữu ích. Một lần nữa:

library(mefa) 
rep(mtcars,10) 

hoặc đơn giản là

mefa:::rep.data.frame(mtcars) 
+6

Aha! Một chức năng R rực rỡ khác ẩn sâu bên trong một gói chuyên gia obcure với một cái tên hoàn toàn không liên quan. Tôi yêu ngôn ngữ này! – smci

4

chức năng Các rep.row dường như đôi khi làm cho danh sách cho các cột, dẫn đến hijinks trí nhớ kém. Tôi đã viết những điều sau đây có vẻ hoạt động tốt:

library(plyr) 
rep.row <- function(r, n){ 
    colwise(function(x) rep(x, n))(r) 
} 
3

Thêm vào những gì @dardisco đề cập về mefa::rep.data.frame(), nó rất linh hoạt.

Bạn có thể lặp lại mỗi dòng N lần:

rep(df, each=N) 

hoặc lặp lại toàn bộ dataframe lần N (nghĩ: giống như khi bạn tái chế một đối số vectorized)

rep(df, times=N) 

Hai thích hợp cho mefa! Tôi chưa bao giờ nghe nói về nó cho đến bây giờ và tôi đã phải viết mã thủ công để làm điều này.

0

Một cách khác để làm sẽ này đầu tiên có được chỉ số liên tiếp, gắn thêm các bản sao của df, và sau đó theo thứ tự của các chỉ số:

df$index = 1:nrow(df) 
df = rbind(df,df) 
df = df[order(df$index),][,-ncol(df)] 

Mặc dù các giải pháp khác có thể ngắn hơn, phương pháp này có thể có nhiều thuận lợi trong các tình huống nhất định.

3

Để tham khảo và thêm vào câu trả lời với lý do mefa, nó có thể đáng để có một cái nhìn về việc thực hiện mefa::rep.data.frame() trong trường hợp bạn không muốn bao gồm toàn bộ gói:

> 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 
1

Giải pháp của tôi tương tự như mefa:::rep.data.frame , nhưng một chút nhanh hơn và quan tâm đến tên hàng:

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 
} 

Hãy so sánh các giải pháp:

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 
.210
3

Một dplyr giải pháp làm sạch, lấy từ here

library(dplyr) 
df <- data_frame(x = 1:2, y = c("a", "b")) 
df %>% slice(rep(1:n(), each = 2)) 
Các vấn đề liên quan