2014-03-24 217 views
4

我试图按行名合并多个数据帧。按行名合并多个数据帧

我知道怎么有两个做:

x = data.frame(a = c(1,2,3), row.names = letters[1:3]) 
y = data.frame(b = c(1,2,3), row.names = letters[1:3]) 
merge(x,y, by = "row.names") 

但是当我尝试使用reshape包的merge_all()我发现了一个错误。

z = data.frame(c = c(1,2,3), row.names = letters[1:3]) 
l = list(x,y,z) 
merge_all(l, by = "row.names") 

Error in -ncol(df) : invalid argument to unary operator 

这样做的最佳方法是什么?

+0

把行名称中一个列,然后使用'Reduce':http://stackoverflow.com/q/8091303/817778 – eddi

+4

eg '减少(merge,lapply(l,function(x)data.frame(x,rn = row.names(x))))' – eddi

+0

@eddi这很棒,非常优雅。你可以添加为答案? –

回答

8

合并由row.names做奇怪的事情 - 它创建了一个名为Row.names列,这使得后续的合并努力。

为了避免这个问题,你可以改为创建一个带有行名称的列(无论如何,这通常是一个更好的主意 - 行名非常有限,难以操作)。这样做有作为OP给出的数据(而不是最优化的方式,来处理矩形数据我建议去了解data.table而不是更优化和更容易的方法)的一种方法:

Reduce(merge, lapply(l, function(x) data.frame(x, rn = row.names(x)))) 
+0

我想这是'data.table'的等价物? 'reduce(merge,lapply(l,data.table,keep.rownames = TRUE,key =“rn”))' – A5C1D2H2I1M1N2O1R2T1

+0

然后删除rn列:'transform(merge,lapply(l,function .frame(x,rn = row.names(x)))),row.names = rn,rn = NULL)' – hagai

1

可能存在使用do.call或* apply更快的版本,但这部作品在您的情况:

x = data.frame(X = c(1,2,3), row.names = letters[1:3]) 
y = data.frame(Y = c(1,2,3), row.names = letters[1:3]) 
z = data.frame(Z = c(1,2,3), row.names = letters[1:3]) 

merge.all <- function(x, ..., by = "row.names") { 
    L <- list(...) 
    for (i in seq_along(L)) { 
    x <- merge(x, L[[i]], by = by) 
    rownames(x) <- x$Row.names 
    x$Row.names <- NULL 
    } 
    return(x) 
} 

merge.all(x,y,z) 

重要的可能是在函数中定义的所有参数(如bymerge.all要转发到merge,因为整个...参数用于要合并的对象列表中。

+0

我也喜欢@eddi的第二条评论(见问题)。 – setempler

0

作为替代Reducemerge

如果你把所有的数据帧到一个列表中,您就可以使用grepcbind获得与所需的行名称的数据帧。

## set up the data 
> x <- data.frame(x1 = c(2,4,6), row.names = letters[1:3]) 
> y <- data.frame(x2 = c(3,6,9), row.names = letters[1:3]) 
> z <- data.frame(x3 = c(1,2,3), row.names = letters[1:3]) 
> a <- data.frame(x4 = c(4,6,8), row.names = letters[4:6]) 
> lst <- list(a, x, y, z) 

## combine all the data frames with row names = letters[1:3] 
> gg <- grep(paste(letters[1:3], collapse = ""), 
      sapply(lapply(lst, rownames), paste, collapse = "")) 
> do.call(cbind, lst[gg]) 
## x1 x2 x3 
## a 2 3 1 
## b 4 6 2 
## c 6 9 3