2010-08-04 25 views

Respuesta

154

rbind.fill del paquete plyr podría ser lo que buscas.

+1

'rbind.fill' y' bind_rows() 'ambos colocan rownames en forma silenciosa. – MERose

+0

@MOSE Hadley: "Sí, todos los métodos dplyr ignoran nombres de fila". – zx8754

39

Puede usar smartbind del paquete gtools.

Ejemplo:

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

I tratado 'smartbind' con dos tramas de datos de gran tamaño (en total aproximadamente 3 * 10^6 filas) y abortada después de 10 minutos. – Joe

14

También puede simplemente sacar los nombres de las columnas comunes.

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

Si las columnas de gl1 es un subconjunto de los de gl2 (por nombres de columna):

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

Tal vez leí mal por completo su pregunta, pero el "yo soy la esperanza de retener las columnas que no coinciden después del enlace "me hace pensar que estás buscando left join o right join similar a una consulta SQL. R tiene la función merge que le permite especificar uniones izquierdas, derechas o internas similares a unir tablas en SQL.

Ya existe una gran pregunta y respuesta en este tema aquí: How to join (merge) data frames (inner, outer, left, right)?

6

escribí una función para hacer esto porque me gusta mi código para decirme si algo está mal. Esta función le indicará explícitamente qué nombres de columna no coinciden y si tiene un tipo no coincidente. Luego hará todo lo posible para combinar los data.frames de todos modos. La limitación es que solo puede combinar dos data.frames a la vez.

### 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/aún no ha smartbind como trabajar con fechas, probablemente debido a que se as.vectoring. Así que aquí está mi solución ...

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

Una solución más reciente es el uso de dplyr 's bind_rows función que yo supongo que es más eficiente que smartbind.

15

Una alternativa con 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 también funcionará en data.table siempre que los objetos se convierten a data.table objetos, por lo

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

también trabajar en esta situación . Esto puede ser preferible cuando tiene un par de data.tables y no quiere construir una lista.

-2

entiendo la pregunta:

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

Desafortunadamente, su comprensión parece incorrecta, como se puede ver al leer la respuesta aceptada. La pregunta es sobre * enlace de fila * dos marcos de datos en caso de que no tengan el mismo conjunto de columnas.Tu publicación trata sobre el enlace * column * usando 'cbind()'. Considere revisar su publicación con una respuesta única a la pregunta o eliminarla. Gracias. – Uwe

2

Sólo por la documentación.Puede probar el Stack biblioteca y su función Stack de la siguiente forma:

Stack(df_1, df_2) 

también tengo la impresión de que es más rápido que otros métodos para grandes conjuntos de datos.

2

La mayoría de las respuestas de la base R abordan la situación donde solo un data.frame tiene columnas adicionales o que el data.frame resultante tendría la intersección de las columnas. Dado que el OP escribe espero conservar las columnas que no coinciden después del enlace, probablemente valga la pena publicar una respuesta utilizando los métodos de base R para abordar este problema.

A continuación, presento dos métodos de base R: uno que altera los data.frames originales y otro que no. Además, ofrezco un método que generaliza el método no destructivo a más de dos data.frames.

Primero, veamos algunos datos de muestra.

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

Dos data.frames, alteran originales
el fin de conservar todas las columnas de ambos data.frames en un rbind (y permitir que la función de trabajar sin que se produzca un error), se agregue columnas NA a cada data.frame con los nombres faltantes correspondientes completados usando setdiff.

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

Ahora, 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 

Tenga en cuenta que las dos primeras líneas alteran la data.frames original, DF1 y DF2, añadiendo el conjunto de columnas a ambos.


Dos data.frames, no alteran originales
Para dejar los originales intactos data.frames primer bucle, a través de los nombres que se diferencian, devuelve un vector con nombre de AN que se concatenan en una lista con el data.frame usando c. Luego, data.frame convierte el resultado en un data.frame apropiado para el 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))) 
) 

Muchos data.frames, no alteran originales
en el caso de que usted tiene más de dos data.frames, se puede hacer lo siguiente.

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

Tal vez un poco mejor no ver los nombres de las filas de data.frames originales? Entonces haz esto.

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