2016-06-22 10 views
3

Ich frage mich, ob es eine Speicher effiziente Möglichkeit gibt, n data.tables (oder Datenrahmen) beizutreten. wenn ich die folgenden 4 data.tables Zum Beispiel haben:Effizient verbinden mehr als 2 data.tables

df1 = data.table(group = c(1L,2L,3L),value = rnorm(3),key = "group") 
df2 = data.table(group = c(2L,1L,3L),value2 = rnorm(3),key = "group") 
df3 = data.table(group = c(3L,2L,1L),value3 = rnorm(3),key = "group") 
df4 = data.table(group = c(1L,3L,2L),value4 = rnorm(3),key = "group") 

Ich konnte sie wie so zusammen:

merge(df1,merge(df2,merge(df3,df4))) 

aber das scheint nicht wie eine optimale Lösung. Ich könnte möglicherweise viele data.tables haben, die zusammengeführt werden müssen. Gibt es eine Möglichkeit, das oben Genannte zu verallgemeinern, ohne jede nachfolgende Zusammenführung in den Speicher zu kopieren? Gibt es einen bereits akzeptierten Weg außerhalb der data.table um dies zu tun?

+1

Eine Lösung ist, alle Datenrahmen in einer Liste zu setzen, verwenden Sie dann 'Reduce()' ihnen zu verschmelzen. Siehe http://stackoverflow.com/questions/8091303/simultously-merge-multiple-data-frames-in-a-list – ulfelder

+1

'Reduce (Funktion (x, y) x [y], Liste (df1, df2, df3 , df4)) scheint auf den von Ihnen bereitgestellten Daten ein wenig schneller zu sein, aber Sie müssten dies an größeren Eingängen testen, um zu sehen, wie es skaliert. – nrussell

+0

@ullinder Das ist nur semantischer Zucker. Die gleichen Zusammenführungsoperationen werden stattfinden. –

Antwort

5

Hier sind einige andere Optionen, die Sie je nach Ihren Daten haben können. Andere Optionen abgesehen von dem offensichtlichen Weg, eine Tonne Merges zu machen, meine ich: in einer Schleife, mit Reduce oder mit hadleys join_all/merge_all/wrap_em_all_up.

Das sind alles Methoden, die ich benutzt habe und die ich in meiner eigenen Arbeit schneller gefunden habe, aber ich beabsichtige nicht, einen allgemeinen Benchmarking-Fall zu versuchen. Zuerst einige Setup:

DFlist = list(df1,df2,df3,df4) 
bycols = key(DFlist[[1]]) 

Ich werde die Tabellen übernehmen werden alle durch die bycols verkeilt.

Stapel. Wenn die neuen Spalten aus jeder Tabelle irgendwie miteinander und erscheinen in den gleichen Positionen in jeder Tabelle verwandt sind, dann betrachten Sie einfach die Daten Stacking:

DFlong = rbindlist(DFlist, use.names = FALSE, idcol = TRUE) 

Wenn aus irgendeinem Grunde wollen Sie die Daten wirklich im Wide-Format können Sie dcast:

dcast(DFlong, 
    formula = sprintf("%s ~ .id", paste(bycols, collapse = "+")), 
    value.var = setdiff(names(DFlong), c(bycols, ".id")) 
) 

Data.table und R funktionieren am besten mit lang~~POS=TRUNC, though.

Kopiere Spalten. Wenn Sie wissen, dass die bycols nehmen alle die gleichen Werte in allen Tabellen, dann kopieren Sie einfach über:

DF = DFlist[[1]][, bycols, with=FALSE] 
for (k in seq_along(DFlist)){ 
    newcols = setdiff(names(DFlist[[k]]), bycols) 
    DF[, (newcols) := DFlist[[k]][, newcols, with=FALSE]] 
} 

Merge assign. Wenn einige Ebenen der bycols sein kann aus bestimmten Tabellen fehlt, wird dann eine Master-Tabelle mit allen Combos machen und eine Folge von Merge-Abtretungs tun:

DF = unique(rbindlist(lapply(DFlist, `[`, j = bycols, with = FALSE))) 
for (k in seq_along(DFlist)){ 
    newcols = setdiff(names(DFlist[[k]]), bycols) 
    DF[DFlist[[k]], (newcols) := mget(newcols)] 
} 
0

In dplyr:

Als Ihre Studien haben alle die Die gleichen Namen (und Sie haben die NAs ausgekratzt) können Sie einfach an die Zeilen binden und zusammenfassen.

library(dplyr) 

DF <- bind_rows(df1,df2,df3,df4) %>% 
    group_by(group) %>% 
    summarise_each(funs(na.omit)) 

Ansonsten gibt es die einfache, lokale Minima Lösung: zumindest obwohl in diesem Dialekt Codierung spart ein paar Schichten auf eigene Zwiebel rasieren.

DF <- 
    df1 %>% 
    full_join(df2) %>% 
    full_join(df3) %>% 
    full_join(df4) 

Da dplyr in C++ nicht läuft, sollte es schneller sein. Ich kann leider nicht mit der Effizienz der Speichernutzung sprechen.

(für ähnliche Situationen zu sehen: R: Updating a data frame with another data frame's dplyr sol'n)

+1

Wenn einige Spalten legale NAs haben, könnte der erste Ansatz seltsam werden. – Frank

+0

Ich teste, wie es auf NA reagiert und (un) zum Glück keine Probleme findet. 'df3 = data.table (Gruppe = c (3L, 2L), Wert3 = rnorm (2), Schlüssel =" Gruppe ")' –

+0

Mit NAs meine ich NAs :) Versuch 'df3 = data.table (group = c (NA, 2L, 1L), Wert3 = rnorm (3), Schlüssel = "Gruppe") 'oder mit' df3 = data.table (Gruppe = c (3L, 2L, 1L), Wert3 = rnorm (3), Schlüssel = "Gruppe") [2, Wert3: = NA] '. Beides führt zu einem Fehler bei der ersten Annäherung an meinen Computer. – Frank

Verwandte Themen