2015-12-14 30 views
5

Desidero aggiungere un frame di dati a un altro (quello principale). Il problema è che solo il sottoinsieme delle loro colonne è comune. Inoltre, l'ordine delle loro colonne potrebbe essere diverso.Aggiunge un frame di dati a un frame di dati master se alcune colonne sono comuni

Maestro dataframe:

a b c 
r1 1 2 -2 
r2 2 4 -4 
r3 3 6 -6 
r4 4 8 -8 

Nuovo dataframe:

 d a c 
r1 -120 10 -20 
r2 -140 20 -40 

Risultato atteso:

a b c 
r1 1 2 -2 
r2 2 4 -4 
r3 3 6 -6 
r4 4 8 -8 
r5 10 NaN -20 
r6 20 NaN -40 

è il sei un modo intelligente per farlo? This è una domanda simile ma l'impostazione è diversa.

risposta

6

Controllare la funzione bind_rows nel pacchetto dplyr. Per impostazione predefinita, farà alcune cose carine, come riempire colonne esistenti in uno data.frame ma non nell'altro con NA s invece di fallire. Ecco un esempio:

# Use the dplyr package for binding rows and for selecting columns 
library(dplyr) 

# Generate some example data 
a <- data.frame(a = rnorm(10), b = rnorm(10)) 
b <- data.frame(a = rnorm(5), c = rnorm(5)) 

# Stack data frames 
bind_rows(a, b) 

Source: local data frame [15 x 3] 

      a   b   c 
1 2.2891895 0.1940835   NA 
2 0.7620825 -0.2441634   NA 
3 1.8289665 1.5280338   NA 
4 -0.9851729 -0.7187585   NA 
5 1.5829853 1.6609695   NA 
6 0.9231296 1.8052112   NA 
7 -0.58-0.6928449   NA 
8 0.2033514 -0.6673596   NA 
9 -0.8576628 0.5163021   NA 
10 0.6296633 -1.2445280   NA 
11 2.1693068   NA -0.2556584 
12 -0.1048966   NA -0.3132198 
13 0.2673514   NA -1.1181995 
14 1.0937759   NA -2.5750115 
15 -0.8147180   NA -1.5525338 

per risolvere il problema nella sua interrogazione, si desidera selezionare per le colonne nel tuo padrone data.frame prima. Se è il master e contiene i dati che si desidera aggiungere, è possibile utilizzare la funzione select da dplyr per ottenere prima le colonne necessarie.

# Select all columns in b with the same names as in master data, a 
# Use select_() instead of select() to do standard evaluation. 
b <- select_(b, names(a)) 

# Combine 
bind_rows(a, b) 

Source: local data frame [15 x 2] 

      a   b 
1 2.2891895 0.1940835 
2 0.7620825 -0.2441634 
3 1.8289665 1.5280338 
4 -0.9851729 -0.7187585 
5 1.5829853 1.6609695 
6 0.9231296 1.8052112 
7 -0.58-0.6928449 
8 0.2033514 -0.6673596 
9 -0.8576628 0.5163021 
10 0.6296633 -1.2445280 
11 2.1693068   NA 
12 -0.1048966   NA 
13 0.2673514   NA 
14 1.0937759   NA 
15 -0.8147180   NA 
2

provare questo:

library(plyr) # thanks to comment @ialm 
df <- data.frame(a=1:4,b=seq(2,8,2),c=seq(-2,-8,-2)) 
new <- data.frame(d=c(-120,-140),a=c(10,20),c=c(-20,40)) 

# we use %in% to pull the columns that are the same in the master 
# then we use rbind.fill to put in this dataframe below the master 
# filling any missing data with NA values 
res <- rbind.fill(df,new[,colnames(new) %in% colnames(df)]) 

> res 
    a b c 
1 1 2 -2 
2 2 4 -4 
3 3 6 -6 
4 4 8 -8 
5 10 NA -20 
6 20 NA 40 
1

un'altra opzione sta usando rbind.fill dal pacchetto plyr

portare i vostri dati di esempio

toread <- " 
a b c 
1 2 -2 
2 4 -4 
3 6 -6 
4 8 -8" 
master <- read.table(textConnection(toread), header = TRUE) 
toread <- " 
d a c 
-120 10 -20 
-140 20 -40" 
to.append <- read.table(textConnection(toread), header = TRUE) 

dati legano

library(plyr) 
rbind.fill(master, to.append) 
+1

Se si utilizza 'dplyr', perché non usare solo' bind_rows() '? – ialm

+1

@ialm Con una lettura più attenta, questa risposta * non * usa alcuna funzione 'dplyr' (carica solo il pacchetto). Vale la pena notare che il caricamento di 'plyr' * dopo * il caricamento di' dplyr' maschererà 'dplyr :: sumarize' e' dplyr :: mutate' con le versioni 'plyr' e non è raccomandato. – Gregor

+1

@Gregor Sì, lo vedo ora. E per i motivi evidenziati nel tuo commento, viene emesso un avviso se carichi 'plyr' dopo' dplyr', e credo che Hadley consiglia di caricare 'plyr' prima di' dplyr' se hai mai bisogno di usare entrambi i pacchetti. – ialm

2

Le soluzioni basate su dplyr - e plyr qui pubblicate sono molto naturali per questa attività utilizzando bind_rows e rbind.fill, sebbene sia possibile anche come one-liner in base R. In pratica vorrei scorrere i nomi dei primi frame di dati, afferrando la colonna corrispondente del secondo frame di dati se è lì o altrimenti restituendo tutti i valori NaN.

rbind(A, sapply(names(A), function(x) if (x %in% names(B)) B[,x] else rep(NaN, nrow(B)))) 
#  a b c 
# r1 1 2 -2 
# r2 2 4 -4 
# r3 3 6 -6 
# r4 4 8 -8 
# 5 10 NaN -20 
# 6 20 NaN -40 
Problemi correlati