2010-08-04 3 views

ответ

154

rbind.fill из пакета plyr может быть то, что вы ищете.

+1

'rbind.fill' и' bind_rows() 'оба молчат падают имена ростов. – MERose

+0

@MERose Hadley: «Да, все методы dplyr игнорируют имена ростов». – zx8754

39

Вы можете использовать smartbind от gtools.

Пример:

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

Я попробовал «smartbind» с двумя большими кадрами данных (всего примерно 3 * 10^6 строк) и прервал его через 10 минут. – Joe

14

Вы также можете просто вытащить общие имена столбцов.

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

Если столбцы в df1 является подмножеством тех, кто в df2 (по именам столбцов):

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

Может быть, я совершенно неправильно ваш вопрос, но «я надеюсь сохранить столбцы которые не совпадают после привязки «заставляет меня думать, что вы ищете left join или right join, похожие на SQL-запрос. R имеет функцию merge, которая позволяет указывать левые, правые или внутренние соединения, похожие на объединение таблиц в SQL.

Существует уже большой вопрос и ответ на эту тему здесь: How to join (merge) data frames (inner, outer, left, right)?

6

Я написал функцию, чтобы сделать это, потому что мне нравится мой код, чтобы сказать мне, если что-то не так. Эта функция явно укажет вам, какие имена столбцов не совпадают, и если у вас есть несоответствие типа. Тогда он сделает все возможное, чтобы объединить data.frames в любом случае. Ограничение состоит в том, что вы можете комбинировать только два кадра данных за один раз.

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

Более недавнее решение использовать dplyr «s bind_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, если они не имеют одинакового набора столбцов.Ваш пост имеет дело с привязкой * column * с использованием 'cbind()'. Пожалуйста, подумайте о том, чтобы пересмотреть свой пост с уникальным ответом на вопрос или удалить его. Спасибо. – Uwe

2

Только для документации.Вы можете попробовать Stack библиотеку и ее функции Stack в следующем виде:

Stack(df_1, df_2) 

У меня есть также впечатление, что это быстрее, чем другие методы для больших наборов данных.

2

Основная часть базы R отвечает на ситуацию, когда только один data.frame имеет дополнительные столбцы или что результирующий data.frame будет иметь пересечение столбцов. Поскольку OP пишет , я надеюсь сохранить столбцы, которые не совпадают после привязки, ответ с использованием базовых методов R для решения этой проблемы, вероятно, стоит опубликовать.

Ниже я представляю два базовых метода R: один, который изменяет исходные кадры data.frames, и тот, который этого не делает. Кроме того, я предлагаю метод, который обобщает неразрушающий метод на более чем два data.frames.

Прежде всего, давайте возьмем некоторые данные образца.

# 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 нетронутыми, первый цикл по именам, которые отличаются, возвращать названный вектор ВПЛ, которые объединяются в список с data.frame с использованием c. Затем data.frame преобразует результат в соответствующий файл data.frame для 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))) 
) 

Многие 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))))) 

Может быть, немного лучше не видеть имена строк исходных данных.фреймы? Тогда сделайте это.

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

 Смежные вопросы

  • Нет связанных вопросов^_^