2010-08-04 19 views

Trả lời

154

rbind.fill từ gói plyr có thể là những gì bạn đang tìm kiếm.

+1

'rbind.fill' và' bind_rows() 'cả hai đều giảm âm thầm. – MERose

+0

@MERose Hadley: "Có, tất cả các phương pháp dplyr đều bỏ qua các tên gọi." – zx8754

39

Bạn có thể sử dụng smartbind từ gói gtools.

Ví dụ:

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

Tôi đã thử 'smartbind' với hai khung dữ liệu lớn (tổng cộng khoảng 3 * 10^6 hàng) và hủy bỏ sau 10 phút. – Joe

14

Bạn cũng có thể chỉ cần kéo ra khỏi các tên cột chung.

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

Nếu các cột trong df1 là một tập hợp con của những người trong df2 (bởi tên cột):

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

Có lẽ tôi hoàn toàn hiểu sai câu hỏi của bạn, nhưng "Tôi hy vọng có thể giữ lại các cột mà không phù hợp sau khi ràng buộc "làm cho tôi nghĩ rằng bạn đang tìm kiếm một left join hoặc right join tương tự như một truy vấn SQL. R có chức năng merge cho phép bạn chỉ định các kết nối bên trái, phải hoặc bên trong tương tự như nối các bảng trong SQL.

Hiện đã là một câu hỏi lớn và trả lời về chủ đề này ở đây: How to join (merge) data frames (inner, outer, left, right)?

6

Tôi đã viết một chức năng để làm điều này vì tôi thích mã của tôi để cho tôi biết nếu có điều gì là sai. Hàm này sẽ cho bạn biết rõ ràng tên cột nào không khớp và nếu bạn có loại không phù hợp. Sau đó, nó sẽ làm tốt nhất của nó để kết hợp data.frames anyway. Giới hạn là bạn chỉ có thể kết hợp hai data.frames tại một thời điểm.

### 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/didnt smartbind như làm việc với Ngày, có lẽ vì nó được as.vectoring. Vì vậy, đây là giải pháp của tôi ...

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

Một giải pháp gần đây hơn là sử dụng dplyr 's bind_rows chức năng mà tôi giả định là hiệu quả hơn smartbind.

15

Một thay thế với 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 cũng sẽ làm việc trong data.table miễn là các đối tượng được chuyển đổi thành data.table đối tượng, vì vậy

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

cũng sẽ làm việc trong tình huống này . Điều này có thể thích hợp hơn khi bạn có một vài data.tables và không muốn xây dựng một danh sách.

-2

Tôi hiểu câu hỏi như:

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

Thật không may, sự hiểu biết của bạn có vẻ sai khi có thể được nhìn thấy bằng cách đọc câu trả lời được chấp nhận. Câu hỏi đặt ra là * liên kết hàng * hai dữ liệu.frames trong trường hợp chúng không có cùng một tập hợp các cột.Bài đăng của bạn thỏa thuận với * cột * ràng buộc bằng cách sử dụng 'cbind()'. Xin vui lòng, xem xét để sửa đổi bài viết của bạn với một câu trả lời duy nhất cho câu hỏi hoặc xóa nó. Cảm ơn bạn. – Uwe

2

Chỉ cần cho các tài liệu hướng dẫn.Bạn có thể thử các Stack thư viện và chức năng của nó Stack theo hình thức sau:

Stack(df_1, df_2) 

Tôi cũng có ấn tượng rằng nó là nhanh hơn so với các phương pháp khác cho các tập dữ liệu lớn.

2

Hầu hết các câu trả lời cơ sở R giải quyết tình huống chỉ có một data.frame có các cột bổ sung hoặc data.frame kết quả sẽ có giao điểm của các cột. Kể từ khi OP viết Tôi hy vọng sẽ giữ lại các cột không khớp sau khi liên kết, một câu trả lời bằng cách sử dụng các phương thức R cơ bản để giải quyết vấn đề này có lẽ đáng để đăng.

Dưới đây, tôi trình bày hai phương pháp cơ sở R: Một phương pháp thay đổi dữ liệu ban đầu.frames và một cái không thay đổi. Ngoài ra, tôi cung cấp một phương thức tổng quát phương thức không phá hủy cho hơn hai data.frames.

Trước tiên, hãy lấy một số dữ liệu mẫu.

# 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]) 

Hai data.frames, thay đổi bản gốc
Để giữ lại tất cả các cột từ cả hai data.frames trong một rbind (và cho phép các chức năng để làm việc mà không dẫn đến một lỗi), bạn thêm cột NA vào mỗi data.frame với tên thiếu thích hợp được điền bằng cách sử dụng setdiff.

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

Bây giờ, 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 

Lưu ý rằng hai dòng đầu tiên thay đổi data.frames gốc, df1 và df2, thêm các tập hợp đầy đủ các cột cho cả hai.


Hai data.frames, không làm thay đổi bản gốc
Để thoát khỏi data.frames gốc còn nguyên vẹn, vòng đầu tiên thông qua những cái tên mà khác nhau, trả lại một vector được đặt tên của NA đó được nối vào một danh sách với data.frame sử dụng c. Sau đó, data.frame chuyển đổi kết quả thành một dữ liệu thích hợp.bảng cho rbind.

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))) 
) 

Nhiều data.frames, không làm thay đổi bản gốc
Trong trường hợp mà bạn có nhiều hơn hai data.frames, bạn có thể làm những điều sau đây.

# 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))))) 

Có thể đẹp hơn một chút để không thấy tên hàng của dữ liệu gốc.frames? Sau đó làm điều này.

do.call(rbind, 
     c(lapply(mydflist, 
       function(x) data.frame(c(x, sapply(setdiff(allNms, names(x)), 
                function(y) NA)))), 
      make.row.names=FALSE)) 
Các vấn đề liên quan