2010-08-04 61 views

回答

154

rbind.fill從包裝plyr可能是你在找什麼。

+1

'rbind.fill'和'bind_rows()'都默默地放棄了rownames。 – MERose 2017-12-05 16:40:30

+0

@Merose Hadley:「是的,所有的dplyr方法都會忽略rownames。」 – zx8754 2017-12-07 09:11:05

39

您可以使用gtools包中的smartbind

例子:

library(gtools) 
df1 <- data.frame(a = c(1:5), b = c(6:10)) 
df2 <- data.frame(a = c(11:15), b = c(16:20), c = LETTERS[1:5]) 
smartbind(df1, df2) 
# result 
    a b c 
1.1 1 6 <NA> 
1.2 2 7 <NA> 
1.3 3 8 <NA> 
1.4 4 9 <NA> 
1.5 5 10 <NA> 
2.1 11 16 A 
2.2 12 17 B 
2.3 13 18 C 
2.4 14 19 D 
2.5 15 20 E 
+0

我試着用兩個大數據幀(總共大約3 * 10^6行)'smartbind'並在10分鐘後中止。 – Joe 2017-05-11 11:39:02

14

你也可以只退出共同列名。

> cols <- intersect(colnames(df1), colnames(df2)) 
> rbind(df1[,cols], df2[,cols]) 
24

如果DF1列是那些在DF2一個子集(按列名):

df3 <- rbind(df1, df2[, names(df1)]) 
1

也許我完全誤解了你的問題,但「我希望能保留列綁定後不匹配「使我認爲您正在尋找類似於SQL查詢的left joinright join。 R的merge函數允許您指定左連接,右連接或內連接,類似於SQL中的連接表。

已經有關於這一主題在這裏一個很大的問題和答案:How to join (merge) data frames (inner, outer, left, right)?

6

我寫了一個功能,因爲我喜歡我的代碼,告訴我什麼是錯的做到這一點。此函數將明確告訴您哪些列名稱不匹配,以及是否有類型不匹配。然後,它會盡最大努力組合數據框架。限制是您一次只能組合兩個數據幀。

### combines data frames (like rbind) but by matching column names 
# columns without matches in the other data frame are still combined 
# but with NA in the rows corresponding to the data frame without 
# the variable 
# A warning is issued if there is a type mismatch between columns of 
# the same name and an attempt is made to combine the columns 
combineByName <- function(A,B) { 
    a.names <- names(A) 
    b.names <- names(B) 
    all.names <- union(a.names,b.names) 
    print(paste("Number of columns:",length(all.names))) 
    a.type <- NULL 
    for (i in 1:ncol(A)) { 
     a.type[i] <- typeof(A[,i]) 
    } 
    b.type <- NULL 
    for (i in 1:ncol(B)) { 
     b.type[i] <- typeof(B[,i]) 
    } 
    a_b.names <- names(A)[!names(A)%in%names(B)] 
    b_a.names <- names(B)[!names(B)%in%names(A)] 
    if (length(a_b.names)>0 | length(b_a.names)>0){ 
     print("Columns in data frame A but not in data frame B:") 
     print(a_b.names) 
     print("Columns in data frame B but not in data frame A:") 
     print(b_a.names) 
    } else if(a.names==b.names & a.type==b.type){ 
     C <- rbind(A,B) 
     return(C) 
    } 
    C <- list() 
    for(i in 1:length(all.names)) { 
     l.a <- all.names[i]%in%a.names 
     pos.a <- match(all.names[i],a.names) 
     typ.a <- a.type[pos.a] 
     l.b <- all.names[i]%in%b.names 
     pos.b <- match(all.names[i],b.names) 
     typ.b <- b.type[pos.b] 
     if(l.a & l.b) { 
      if(typ.a==typ.b) { 
       vec <- c(A[,pos.a],B[,pos.b]) 
      } else { 
       warning(c("Type mismatch in variable named: ",all.names[i],"\n")) 
       vec <- try(c(A[,pos.a],B[,pos.b])) 
      } 
     } else if (l.a) { 
      vec <- c(A[,pos.a],rep(NA,nrow(B))) 
     } else { 
      vec <- c(rep(NA,nrow(A)),B[,pos.b]) 
     } 
     C[[i]] <- vec 
    } 
    names(C) <- all.names 
    C <- as.data.frame(C) 
    return(C) 
} 
-1
rbind.ordered=function(x,y){ 

    diffCol = setdiff(colnames(x),colnames(y)) 
    if (length(diffCol)>0){ 
    cols=colnames(y) 
    for (i in 1:length(diffCol)) y=cbind(y,NA) 
    colnames(y)=c(cols,diffCol) 
    } 

    diffCol = setdiff(colnames(y),colnames(x)) 
    if (length(diffCol)>0){ 
    cols=colnames(x) 
    for (i in 1:length(diffCol)) x=cbind(x,NA) 
    colnames(x)=c(cols,diffCol) 
    } 
    return(rbind(x, y[, colnames(x)])) 
} 
1

gtools/smartbind不喜歡使用日期,可能是因爲它是as.vectoring。因此,這裏是我的解決方案...

sbind = function(x, y, fill=NA) { 
    sbind.fill = function(d, cols){ 
     for(c in cols) 
      d[[c]] = fill 
     d 
    } 

    x = sbind.fill(x, setdiff(names(y),names(x))) 
    y = sbind.fill(y, setdiff(names(x),names(y))) 

    rbind(x, y) 
} 
75

最近的一個解決方案是使用dplyrbind_rows功能,我認爲比smartbind更有效。

15

data.table一種替代:

library(data.table) 
df1 = data.frame(a = c(1:5), b = c(6:10)) 
df2 = data.frame(a = c(11:15), b = c(16:20), c = LETTERS[1:5]) 
rbindlist(list(df1, df2), fill = TRUE) 

rbind也將在data.table工作,只要該對象轉換爲data.table對象,所以

rbind(setDT(df1), setDT(df2), fill=TRUE) 

也將在這種情況下,工作。當你有幾個data.tables並且不想構造一個列表時,這可能會更好。

-2

我明白的問題爲:

a = data.frame(
    x = c(1,2,3), 
    y = c(5,2,3) 
) 
b = data.frame(
    u = c(6,2,3), 
    v = c(19,13,12) 
) 
dd=cbind(a, b) 


str(dd) 

'data.frame': 3 obs. of 4 variables: 
$ x: num 1 2 3 
$ y: num 5 2 3 
$ u: num 6 2 3 
$ v: num 19 13 12 
+1

不幸的是,通過閱讀接受的答案可以看出您的理解錯誤。問題是關於*行綁定*兩個data.frames,以防它們沒有相同的一組列。您的文章使用'cbind()'處理* column *綁定。請考慮修改您的帖子,並將其刪除。謝謝。 – Uwe 2017-08-07 04:57:16

2

只是爲了文檔。您可以嘗試Stack庫及其下面的表格功能Stack

Stack(df_1, df_2) 

我也有印象,它比其他方法大數據集的速度更快。

2

大多數基準R答案解決了只有一個數據幀具有附加列或結果數據幀具有列交集的情況。由於OP寫道我希望保留綁定後不匹配的列,使用基本R方法解決此問題的答案可能值得發佈。

下面我介紹兩種基本的R方法:一種改變原始數據幀,另一種不改變原始數據幀。另外,我提供了一種將非破壞性方法推廣到兩個以上數據框架的方法。

首先,我們來看一些示例數據。

# sample data, variable c is in df1, variable d is in df2 
df1 = data.frame(a=1:5, b=6:10, d=month.name[1:5]) 
df2 = data.frame(a=6:10, b=16:20, c = letters[8:12]) 

兩個data.frames,改變原件
爲了留住來自data.frames所有列在rbind(並允許功能,而不會產生錯誤的工作),你將NA列添加到每個data.frame中,並使用setdiff填寫相應的缺失名稱。

# fill in non-overlapping columns with NAs 
df1[setdiff(names(df2), names(df1))] <- NA 
df2[setdiff(names(df1), names(df2))] <- NA 

現在,rbind -em

rbind(df1, df2) 
    a b  d c 
1 1 6 January <NA> 
2 2 7 February <NA> 
3 3 8 March <NA> 
4 4 9 April <NA> 
5 5 10  May <NA> 
6 6 16  <NA> h 
7 7 17  <NA> i 
8 8 18  <NA> j 
9 9 19  <NA> k 
10 10 20  <NA> l 

注意,前兩行改變原始data.frames,DF1和DF2,加上全套到兩列的。


兩個data.frames,不改變原件
要離開了原來的data.frames通過不同的名字不變,第一次循環,返回連接成一個列表的NAS命名矢量data.frame使用c。然後,data.frame將結果轉換爲適合rbind的data.frame。

rbind(
    data.frame(c(df1, sapply(setdiff(names(df2), names(df1)), function(x) NA))), 
    data.frame(c(df2, sapply(setdiff(names(df1), names(df2)), function(x) NA))) 
) 

許多data.frames,不改變原件
在你有兩個以上的data.frames的情況下,你可以做到以下幾點。

# put data.frames into list (dfs named df1, df2, df3, etc) 
mydflist <- mget(ls(pattern="df\\d+") 
# get all variable names 
allNms <- unique(unlist(lapply(mydflist, names))) 

# put em all together 
do.call(rbind, 
     lapply(mydflist, 
       function(x) data.frame(c(x, sapply(setdiff(allNms, names(x)), 
                function(y) NA))))) 

也許有點更好,看不到原始data.frames的行名?然後做這個。

do.call(rbind, 
     c(lapply(mydflist, 
       function(x) data.frame(c(x, sapply(setdiff(allNms, names(x)), 
                function(y) NA)))), 
      make.row.names=FALSE)) 
相關問題