2014-03-24 178 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