2013-02-25 23 views
10

Ho una lista contenente i frame di dati come i suoi elementi a R.Come unire tutti gli elementi della lista in R?

Esempio:

df1 <- data.frame("names"=c("John","Sam","Dave"),"age"=c(21,22,25)) 
df2 <- data.frame("names"=c("John","Sam"),"score"=c(22,25)) 
df3 <- data.frame("names"=c("John","Sam","Dave"),"country"=c("US","SA","NZ")) 
mylist <- list(df1,df2,df3) 

E 'possibile unire tutti gli elementi della mylist insieme senza l'utilizzo di un ciclo?

mia uscita desiderato per questo esempio è:

names age score country 
1 John 21 22  US 
2 Sam 22 25  SA 

La lista in questo esempio ha solo tre elementi; tuttavia, sto cercando una soluzione in grado di gestire un numero arbitrario di elementi.

risposta

16

È possibile utilizzare Reduce, una soluzione di linea:

Reduce(merge,mylist) 

    names age score country 
1 John 21 22  US 
2 Sam 22 25  SA 
7

rapido e sporco esempio:

merge(merge(df1, df2),df3) 

EDIT - domanda molto simile qui: Simultaneously merge multiple data.frames in a list

soluzione:

merged.data.frame = Reduce(function(...) merge(..., all=F), my.list) 

Disclaimer - Tutto quello che ho cambiato da @Charles la risposta era fare merge(..., all=F) anziché T - in questo modo fornisce l'output desiderato.

+0

Grazie @alexwhan. Avrei dovuto essere più specifico Ho bisogno di una soluzione per una lista con un numero arbitrario di elementi. La mia lista di input può avere un numero diverso di elementi ogni volta invece dei tre in questo esempio. – user2109248

+0

Sì, questo è quello che mi chiedevo – alexwhan

3

solo per dimostrare che si poteva fare in un altro modo ...

mymerge <- function(mylist) { 
    names(mylist) <- sapply(mylist, function(x) names(x)[2]) 
    ns <- unique(unlist(lapply(mylist, function(x) levels(x$names)))) 
    as.data.frame(c(list(names=ns), lapply(mylist, function(x) 
         {x[match(ns, x$names),2]}))) 
} 

> mymerge(mylist) 
    names age score country 
1 Dave 25 NA  NZ 
2 John 21 22  US 
3 Sam 22 25  SA 

si potrebbe facilmente adattarsi a rimuovere le righe con valori mancanti, o forse basta rimuovere in seguito con complete.cases.

Per dimostrare che è più veloce, creeremo un set di dati più grande; 100 variabili e 25 nomi.

set.seed(5) 
vs <- paste0("V", 1:100) 
mylist <- lapply(vs, function(v) { 
    x <- data.frame(names=LETTERS[1:25], round(runif(25, 0,100))) 
    names(x)[2] <- v 
    x 
}) 

> microbenchmark(Reduce(merge, mylist), myf(mylist)) 
Unit: milliseconds 
        expr  min  lq median  uq  max 
1   myf(mylist) 12.81371 13.19746 13.36571 14.40093 33.90468 
2 Reduce(merge, mylist) 199.23714 206.28608 207.30247 208.44939 226.05980 
+0

Beh, raramente ho downvoted. Non che a volte non me lo meriti, ma un commento sarebbe carino. Ho pensato che fosse piuttosto fluido, e sarà più veloce di 'Riduci 'quando i dati si ingrandiscono, come mostrato nella modifica. – Aaron

+0

+1 per il benchmark! Ridurre è veramente lento! – agstudy

Problemi correlati