2012-06-20 14 views
49

Chcę powtórzyć wiersze obiektu data.frame, każdy o wartości N. Wynik powinien być nowy data.frame (z nrow(new.df) == nrow(old.df) * N) zachowując typy danych kolumn.Powtórz wiersze obiektu data.frame

przykład dla 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 

Tak, każdy wiersz jest powtarzane 2 razy i postacie pozostają znaki, czynniki pozostają czynniki, Liczby pozostają numeryczne ...

Moja pierwsza próba zastosowania używany : apply(old.df, 2, function(co) rep(co, each = N)), ale ten zmienia swoje wartości do znaków i uzyskać:

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

Możliwe wtórnika [powtórzyć data.frame N razy] (http://stackoverflow.com/questions/8753531/repeat-data-frame-n-times) –

Odpowiedz

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

Możesz użyć 'n.czasów <- c (2,4); df [rep (seq_len (nrow (df)), n.times),] 'jeśli chcesz zmienić liczbę powtórzeń każdego wiersza. –

4

Jeśli można powtórzyć całość, czy podzbiorem najpierw powtórzyć, wtedy this similar question może być pomocne. Po raz kolejny:

library(mefa) 
rep(mtcars,10) 

lub po prostu

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

Aha! Kolejna genialna funkcja R ukryta głęboko w specjalnym pakiecie specjalistycznym o zupełnie niezwiązanej nazwie. Kocham ten język! – smci

4

Funkcja rep.row wydaje się czasem zrobić list do kolumn, co prowadzi do złych hijinks pamięci. Pisałem następujących składników, które wydaje się działać dobrze:

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

Dodając do tego, co @dardisco wspomniano o mefa::rep.data.frame(), jest bardzo elastyczny.

Można powtórzyć każdy wiersz N razy:

rep(df, each=N) 

lub powtórzyć cały dataframe razy N (myślę: jak przy recyklingu Vectorized argumentu)

rep(df, times=N) 

Two kciuki za mefa! Nigdy dotąd o tym nie słyszałem i musiałem napisać ręczny kod, żeby to zrobić.

0

Innym sposobem, aby to zrobić by najpierw uzyskać indeksy wierszy, dołączyć dodatkowe kopie df, a następnie zamówienie indeksów:

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

Chociaż inne rozwiązania może być krótszy, metoda ta może być bardziej korzystne w pewnych sytuacjach.

3

Dla odniesienia i dodanie do odpowiedzi powołując mefA, to może warto spojrzeć na realizację mefa::rep.data.frame() w przypadku, gdy nie chcą zawierać cały pakiet:

> 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

Moje rozwiązanie podobne jak mefa:::rep.data.frame , ale szybciej się trochę i dba o nazwach rzędu:

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 
} 

Porównaj rozwiązania:

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 
3

Czyste dplyr, pobraną z here

library(dplyr) 
df <- data_frame(x = 1:2, y = c("a", "b")) 
df %>% slice(rep(1:n(), each = 2))