2013-02-25 102 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