122 votes

Répéter les lignes d'un data.frame

Je veux répéter les lignes d'un data.frame, chaque N fois. Le résultat devrait être un nouveau data.frame (avec nrow(new.df) == nrow(old.df) * N ) en conservant les types de données des colonnes.

Exemple pour 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

Ainsi, chaque ligne est répétée 2 fois et les caractères restent les caractères, les facteurs restent les facteurs, les chiffres restent les chiffres, ...

Ma première tentative d'utilisation de l'application : apply(old.df, 2, function(co) rep(co, each = N)) Mais celui-ci transforme mes valeurs en caractères et j'obtiens :

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

7voto

Fabio Gabriel Points 61

A titre de référence et pour compléter les réponses citant mefa, il peut être intéressant de jeter un coup d'œil sur l'implémentation de mefa::rep.data.frame() au cas où vous ne souhaiteriez pas inclure l'ensemble du paquet :

> 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

5voto

jebyrnes Points 1970

La fonction rep.row semble parfois créer des listes pour les colonnes, ce qui entraîne des problèmes de mémoire. J'ai écrit ce qui suit et qui semble bien fonctionner :

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

3voto

Artem Klevtsov Points 1049

Ma solution est similaire à mefa:::rep.data.frame mais un peu plus rapide et qui se soucie des noms de lignes :

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
}

Comparer les solutions :

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

1voto

Essayez d'utiliser par exemple

N=2
rep(1:4, each = N) 

en tant qu'index

0voto

crazjo Points 385

Une autre façon de procéder serait d'obtenir d'abord les indices des lignes, d'ajouter des copies supplémentaires de la base de données, puis de classer les données en fonction des indices :

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

Bien que les autres solutions soient plus courtes, cette méthode peut être plus avantageuse dans certaines situations.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X