2013-02-25 70 views
10

我有一個包含數據幀作爲其在R.單元的明細表如何合併R中列表的所有元素?

實施例:

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) 

是否有可能合併MYLIST的所有元件一起,而無需使用一個循環?

我期望用於本實施例中的輸出是:

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

在這個例子中的列表僅具有三個要素;不過,我正在尋找一種可以處理任意數量元素的解決方案。

回答

16

您可以使用Reduce,一個班輪解決方案:

Reduce(merge,mylist) 

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

快速和骯髒的例子:

merge(merge(df1, df2),df3) 

編輯 - 非常類似的問題在這裏:Simultaneously merge multiple data.frames in a list

解決方案:

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

聲明 - 所有我從@Charles改變答案是使merge(..., all=F)而不是T - 這種方式可以提供您想要的輸出。

+0

感謝@alexwhan。我應該更具體。我需要一個包含任意數量元素的列表的解決方案。我的輸入列表可能每次都有不同數量的元素,而不是本例中的三個元素。 – user2109248 2013-02-26 00:07:09

+0

是的,這就是我想知道的 – alexwhan 2013-02-26 00:11:23

3

只是爲了表明它可以做的另一種方式......

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 

人們可以很容易地適應刪除缺失值的行,或者也許只是隨後用complete.cases刪除。

爲了表明速度更快,我們將構建一個更大的數據集; 100個變量和25個名字。

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

好吧,我很少會陷入低谷。不是說我不應該得到它,但評論會很好。我認爲這很漂亮,並且在數據變大時比'Reduce'更快,如編輯中所示。 – Aaron 2013-02-26 13:59:16

+0

爲基準+1!減少真的很慢! – agstudy 2013-07-12 13:28:05