2013-04-15 11 views
11

Ho 3 frame di dati (righe: siti, colonne: nome di specie) di abbondanze di specie all'interno dei siti. I numeri di riga sono identici, ma i numeri delle colonne differiscono in quanto non tutte le specie si trovano in tutti e tre i frame di dati. Vorrei fonderli in un unico data frame con abbondanza di specie identiche riassunte. Per esempio:Combina data.frames riassumendo i valori di colonne identiche in R

data.frame1

 Sp1 Sp2 Sp3 Sp4 
site1 1 2 3 1 
site2 0 2 0 1 
site3 1 1 1 1 

data.frame2

 Sp1 Sp2 Sp4 
site1 0 1 2 
site2 1 2 0 
site3 1 1 1 

data.frame3

 Sp1 Sp2 Sp5 Sp6 
site1 0 1 1 1  
site2 1 1 1 5 
site3 2 0 0 0 

Quello che voglio avere è qualcosa di simile:

 Sp1 Sp2 Sp3 Sp4 Sp5 Sp6 
site1 1 4 3 3 1 1 
site2 2 5 0 1 1 5 
site3 4 2 1 2 0 0 

Credo che avrei dovuto lavorare con l'unione, ma finora i miei tentativi non sono riusciti a ottenere ciò che voglio.

Qualsiasi aiuto è apprezzato.

+0

Forse 'aggregato' meglio di 'unione'? –

risposta

18

userei plyr 's rbind.fill come questo:

pp <- cbind(names=c(rownames(df1), rownames(df2), rownames(df3)), 
         rbind.fill(list(df1, df2, df3))) 

# names Sp1 Sp2 Sp3 Sp4 Sp5 Sp6 
# 1 site1 1 2 3 1 NA NA 
# 2 site2 0 2 0 1 NA NA 
# 3 site3 1 1 1 1 NA NA 
# 4 site1 0 1 NA 2 NA NA 
# 5 site2 1 2 NA 0 NA NA 
# 6 site3 1 1 NA 1 NA NA 
# 7 site1 0 1 NA NA 1 1 
# 8 site2 1 1 NA NA 1 5 
# 9 site3 2 0 NA NA 0 0 

Poi, aggregato con plyr'sddply come segue:

ddply(pp, .(names), function(x) colSums(x[,-1], na.rm = TRUE)) 
# names Sp1 Sp2 Sp3 Sp4 Sp5 Sp6 
# 1 site1 1 4 3 3 1 1 
# 2 site2 2 5 0 1 1 5 
# 3 site3 4 2 1 2 0 0 
+3

Avevo in mente una soluzione e prometto che non era così elegante. +1 –

+0

ha funzionato perfettamente! sfortunatamente non posso votare :( – eugenego

+0

@eugenego È possibile contrassegnare il segno di spunta accanto alla soluzione che meglio risponde alla domanda. –

2

Un'alternativa alla risposta di Arun: Creare un 'modello' array con tutte le colonne necessarie

Rgames> bbar<-data.frame('one'=rep(0,3),'two'=rep(0,3),'three'=rep(0,3)) 
Rgames> bbar 
    one two three 
1 0 0 0 
2 0 0 0 
3 0 0 0 

Poi, dato a ciascuno dei vostri frame di dati come

Rgames> bar1<-data.frame('one'=c(1,2,3),'two'=c(4,5,6)) 
Rgames> bar1 
    one two 
1 1 4 
2 2 5 
3 3 6 

Crea un dataframe ampliato:

Rgames> newbar1<-bbar 
Rgames> for (jj in names(bar)) newbar1[[jj]]<-bar[[jj]] 
Rgames> newbar1 
    one two three 
1 1 4 0 
2 2 5 0 
3 3 6 0 

Poi riassumere tutte queste trame di dati estesi. Goffa ma semplice.

6

Un'altra alternativa è utilizzare melt/cast da reshape2. Ecco un esempio sofisticato:

df1 <- read.table(header=T, text=" 
    Sp1 Sp2 Sp3 Sp4 
    site1 1 2 3 1 
    site2 0 2 0 1 
    site3 1 1 1 1") 

df2 <- read.table(header=T, text=" 
     Sp1 Sp2 Sp4 
site1 0 1 2 
site2 1 2 0 
site3 1 1 1") 

df3 <- read.table(header=T, text=" 
     Sp1 Sp2 Sp5 Sp6 
site1 0 1 1 1  
site2 1 1 1 5 
site3 2 0 0 0") 

df1$site <- rownames(df1) 
df2$site <- rownames(df2) 
df3$site <- rownames(df3) 

DF <- rbind(melt(df1,id="site"),melt(df2,id="site"),melt(df3,id="site")) 
dcast(data=DF,formula=site ~ variable,fun.aggregate=sum) 

    site Sp1 Sp2 Sp3 Sp4 Sp5 Sp6 
1 site1 1 4 3 3 1 1 
2 site2 2 5 0 1 1 5 
3 site3 4 2 1 2 0 0 

Insomma, usiamo la designazione sito come una variabile aggiuntiva, e convertire ogni dataframe in formato lungo, poi le si unisce in un unico dataframe. Quest'ultimo contiene tutti i valori nel formato lungo. Con dcast creiamo il dataframe richiesto, i siti sono in righe (lato sinistro della formula), le variabili sono in colonne (lato destro della formula). La funzione somma viene utilizzata sulle variabili per le quali vengono prodotte più celle.

Ovviamente, il codice può essere esteso a casi più generali con cicli o * applica funzioni.

5

Aggiungendo alle opzioni disponibili, eccone altri due che si attaccano alla base R.

Prima opzione: larga aggregazione (specie di)

temp <- cbind(df1, df2, df3) 
temp 
#  Sp1 Sp2 Sp3 Sp4 Sp1 Sp2 Sp4 Sp1 Sp2 Sp5 Sp6 
# site1 1 2 3 1 0 1 2 0 1 1 1 
# site2 0 2 0 1 1 2 0 1 1 1 5 
# site3 1 1 1 1 1 1 1 2 0 0 0 
sapply(unique(colnames(temp)), 
     function(x) rowSums(temp[, colnames(temp) == x, drop = FALSE])) 
#  Sp1 Sp2 Sp3 Sp4 Sp5 Sp6 
# site1 1 4 3 3 1 1 
# site2 2 5 0 1 1 5 
# site3 4 2 1 2 0 0 

Seconda opzione: semi-larga per lungo a largo

Concettualmente, questo è simile a Maxim. Risposta di K: Ottieni i dati in un formato lungo e semplifica molto la manipolazione delle cose:

> temp1 <- t(cbind(df1, df2, df3)) 
> # You'll get a warning in the next step 
> # Safe to ignore though... 
> temp2 <- data.frame(var = rownames(temp), stack(data.frame(temp))) 
Warning message: 
In data.row.names(row.names, rowsi, i) : 
    some row.names duplicated: 5,6,7,8,9 --> row.names NOT used 
> xtabs(values ~ ind + var, temp2) 
     var 
ind  Sp1 Sp2 Sp3 Sp4 Sp5 Sp6 
    site1 1 4 3 3 1 1 
    site2 2 5 0 1 1 5 
    site3 4 2 1 2 0 0