Replica ogni riga di data.frame e specifica il numero di repliche per ogni riga

df <- data.frame(var1=c('a', 'b', 'c'), var2=c('d', 'e', 'f'), freq=1:3) 

Qual è il modo più semplice per espandere le prime due colonne di data.frame in alto, in modo che ogni riga appaia il numero di volte specificato nella colonna “freq”?

In altre parole, vai da questo:

 df var1 var2 freq 1 ad 1 2 be 2 3 cf 3 

A questa:

 df.expanded var1 var2 1 ad 2 be 3 be 4 cf 5 cf 6 cf 

    Ecco una soluzione:

     df.expanded < - df[rep(row.names(df), df$freq), 1:2] 

    Risultato:

      var1 var2 1 ad 2 be 2.1 be 3 cf 3.1 cf 3.2 cf 

    Usa expandRows() dal pacchetto splitstackshape :

     library(splitstackshape) expandRows(df, "freq") 

    La syntax semplice, molto veloce, funziona su data.frame o data.table .

    Risultato:

      var1 var2 1 ad 2 be 2.1 be 3 cf 3.1 cf 3.2 cf 

    vecchia domanda, nuovo verbo in tidyverse:

     library(tidyr) # version >= 0.8.0 df < - data.frame(var1=c('a', 'b', 'c'), var2=c('d', 'e', 'f'), freq=1:3) df %>% uncount(freq) var1 var2 1 ad 2 be 2.1 be 3 cf 3.1 cf 3.2 cf 

    La soluzione di @ neilfws funziona alla grande per data.frame s, ma non per data.table s poiché mancano della proprietà row.names . Questo approccio funziona per entrambi:

     df.expanded < - df[rep(seq(nrow(df)), df$freq), 1:2] 

    Il codice per data.table è un tad cleaner:

     # convert to data.table by reference setDT(df) df.expanded < - df[rep(seq(.N), freq), !"freq"] 

    Nel caso in cui dovessi fare questa operazione su data.frames molto grandi, ti consiglio di convertirlo in un file data.table e di usare quanto segue, che dovrebbe funzionare molto più velocemente:

     library(data.table) dt < - data.table(df) dt.expanded <- dt[ ,list(freq=rep(1,freq)),by=c("var1","var2")] dt.expanded[ ,freq := NULL] dt.expanded 

    Scopri quanto è più veloce questa soluzione:

     df < - data.frame(var1=1:2e3, var2=1:2e3, freq=1:2e3) system.time(df.exp <- df[rep(row.names(df), df$freq), 1:2]) ## user system elapsed ## 4.57 0.00 4.56 dt <- data.table(df) system.time(dt.expanded <- dt[ ,list(freq=rep(1,freq)),by=c("var1","var2")]) ## user system elapsed ## 0.05 0.01 0.06