2010-08-04 8 views

risposta

154

rbind.fill dal pacchetto plyr potrebbe essere quello che stai cercando.

+1

'rbind.fill' e' bind_rows() 'abbassano silenziosamente i nomi dei giocatori. – MERose

+0

@MERose Hadley: "Sì, tutti i metodi di dplyr ignorano i nomi dei giocatori." – zx8754

39

È possibile utilizzare smartbind dal pacchetto gtools.

Esempio:

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

Ho provato 'smartbind' con due grandi frame di dati (in totale circa 3 * 10^6 righe) e l'ho interrotto dopo 10 minuti. – Joe

14

Si potrebbe anche solo tirare fuori i nomi delle colonne comuni.

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

Se le colonne in df1 è un sottoinsieme di quelle in DF2 (dai nomi delle colonne):

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

Forse ho letto male completamente la tua domanda, ma il "spero di mantenere le colonne che non corrispondono dopo il legame "mi fa pensare che stai cercando uno left join o right join simile a una query SQL. R ha la funzione merge che consente di specificare giunzioni a sinistra, a destra o interne simili a quelle di unione in SQL.

Esiste già una grande domanda e risposta su questo argomento qui: How to join (merge) data frames (inner, outer, left, right)?

6

ho scritto una funzione per fare questo perché mi piace il mio codice di dirmi se qualcosa non va. Questa funzione ti dirà esplicitamente quali nomi di colonne non corrispondono e se hai una mancata corrispondenza di tipo. Quindi farà del suo meglio per combinare comunque i data.frames. La limitazione è che puoi combinare solo due data.frames alla volta.

### 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/non ha ancora smartbind come lavorare con le date, probabilmente perché era as.vectoring. Quindi, ecco la mia soluzione ...

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 soluzione più recente è quella di utilizzare dplyr s' bind_rows funzione che presumo è più efficiente di smartbind.

15

Un'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 funzionano anche in data.table finché gli oggetti vengono convertiti data.table oggetti, così

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

funzionano anche in questa situazione . Questo può essere preferibile quando hai un paio di dati.tables e non vuoi costruire un elenco.

-2

aver capito la domanda come:

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

Sfortunatamente, la tua comprensione sembra sbagliata come si può vedere leggendo la risposta accettata. La domanda riguarda * binding di righe * due data.frames nel caso in cui non abbiano lo stesso set di colonne.Il tuo post si occupa di * column * binding usando 'cbind()'. Per favore, considera di rivedere il tuo post con una risposta univoca alla domanda o di eliminarlo. Grazie. – Uwe

2

Proprio per la documentazione.Si può provare la libreria Stack e la sua funzione Stack nella forma seguente:

Stack(df_1, df_2) 

Ho anche l'impressione che sia più veloce di altri metodi per grandi insiemi di dati.

2

La maggior parte delle risposte di base R risolve la situazione in cui solo un data.frame ha colonne aggiuntive o che il data.frame risultante avrebbe l'intersezione delle colonne. Dal momento che l'OP scrive spero di mantenere le colonne che non corrispondono dopo il binding, è probabile che una risposta utilizzando i metodi di base R per risolvere questo problema sia probabilmente utile.

Di seguito, presento due metodi di base R: Uno che altera i file di dati originali e uno che non lo fa. Inoltre, offro un metodo che generalizza il metodo non distruttivo a più di due data.frames.

In primo luogo, prendiamo alcuni dati di esempio.

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

Due data.frames, alterano originali
Per conservare tutte le colonne di entrambi data.frames in rbind (e consentire la funzione di lavorare senza un conseguente errore), è aggiungere colonne NA a ogni data.frame con i nomi mancanti appropriati compilati utilizzando setdiff.

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

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

Si noti che le prime due righe alterano il data.frames originale, df1 e DF2, aggiungendo il set completo di colonne per entrambi.


Due data.frames, non alterare gli originali
Per lasciare le data.frames originali intatti, primo ciclo attraverso i nomi che differiscono, restituisce un nome vettore di AN che sono concatenati in un elenco con il data.frame utilizzando c. Quindi, data.frame converte il risultato in un data.frame appropriato per lo 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))) 
) 

Molti data.frames, non alterare gli originali
nel caso che si dispone di più di due data.frames, si potrebbe fare quanto segue.

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

Forse un po 'più bello non vedere i nomi delle righe di data.frames originali? Quindi fai questo.

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