2016-05-03 7 views
8

Ich habe zwei data.tables mit vielen Feldern.R data.table beitreten: SQL "Select *" gleich Syntax in verbundenen Tabellen?

Ich möchte die beiden Tabellen verbinden, einige berechnete Felder hinzufügen und alle anderen Felder aus der ersten, zweiten oder beiden Tabellen (ähnlich SQL select a+b AS sum, DT1.*, DT2.* FROM...) anhängen, ohne alle Feldnamen einzugeben.

Wie kann ich dies (in Bezug auf einfachste Syntax und beste Leistung) tun?

Vereinfachtes Beispiel Daten:

library(data.table) 
DT1 = data.table(x=c("c", "a", "b", "a", "b"), a=1:5) 
DT2 = data.table(x=c("d", "c", "b"), b=6:8) 

Jetzt möchte ich die Tabellen verknüpfen und ein berechnetes Feld hinzufügen:

DT1[DT2, .(sum=a + b, <<< how to say DT1.*, DT2.* here? >>>), on="x"] 

-Update 4. Mai 2016: durch Benutzer Inspired jangorecki Ich habe eine Feature-Anfrage dafür gefunden:

Should be able to refer to i's .SD during a join

+0

Ich bin nicht sicher, das ganz ist, was Sie brauchen, aber einen Blick auf die .SDcols Argument in Datentabelle. Kann hilfreich sein. – giraffehere

+0

@giraffehere Ich denke .SDcols verlangt von mir, jeden Feldnamen anzugeben, was ich vermeiden möchte. Ich versuche, eine Lösung mit .SD zu finden, aber das funktioniert nicht (Syntaxfehler und keine Möglichkeit, zwischen DT1 und DT2 zu unterscheiden) –

+1

Vielleicht zeigen Sie Ihre gewünschte Ausgabe auch? Deine Frage ist etwas verwirrend für mich. –

Antwort

7

Dies sollte genau Ihre Bedürfnisse beantworten.
Es nutzt sehr leistungsfähige R-Funktion namens Computing auf die Sprache (oder Meta-Programmierung) gut im offiziellen R Language Definition Handbuch beschrieben. Dies ist ein außergewöhnliches Merkmal der R-Sprache und sollte IMO nicht vergessen werden.

library(data.table) 
DT1 = data.table(x=c("c", "a", "b", "a", "b"), a=1:5) 
DT2 = data.table(x=c("d", "c", "b"), b=6:8) 

jj = as.call(c(
    list(as.name(".")), 
    list(sum = quote(a+b)), 
    lapply(unique(c(names(DT1), names(DT2))), as.name) 
)) 
print(jj) 
#.(sum = a + b, x, a, b) 
DT1[DT2, eval(jj), on="x"] 
# sum x a b 
#1: NA d NA 6 
#2: 8 c 1 7 
#3: 11 b 3 8 
#4: 13 b 5 8 
+0

Meta-Programmierung, unglaublich gute Antwort! –

+3

Neben dem pädagogischen Wert, kein Fan der zusätzlichen Komplikationen hier. @RYoda, wenn Sie OK '' Namen (DT *) 'eingeben, dann könnte auch tun:' DT1 [DT2, c (Liste (Summe = a + b), Mget (Union (Namen (DT1), Namen (DT2)))), on = 'x'] '. Es gibt momentan keine Unterstützung für "i.SD", aber es gibt einen FR darüber. – eddi

+2

wert, zu beachten, dass 'x.col' und' i.col' beide in 1.9.7 funktionieren, so 'as.name' kann Namen Namen mit Präfixen füllen, die volle Kontrolle über die verwendeten Spalten geben – jangorecki

5

Ich bin mir meiner Antwort auf den zweiten Teil Ihrer Frage sicherer, also werde ich das zuerst beantworten. Wenn Sie nur wollen DT1 sagen * oder DT2 *, wollen aber die zusätzliche Spalte neu = a + b, würde ich es auf diese Weise tun:...

DT1[DT2,new:=a+b,on="x"] 

Für den ersten Teil, in dem Sie DT1 benötigen * . und DT2 *, die einzige Antwort, die ich denken kann, ist:

DT1[DT2, on="x"][,new := a+b] 

es könnte jedoch effizienteren Code, dies zu erreichen.

+0

Ihr erstes Code-Snippet ist perfekt für DT1. *. Ich denke, DT2. * Funktioniert nicht so, weil ': =' die Spalte zu DT1 hinzufügt. Bezüglich des zweiten Codeausschnitts: Funktioniert perfekt für DT1. * UND DT2. *, Aber ich habe in meiner Frage nicht explizit erwähnt, dass ich es vermeiden möchte, eine neue Spalte als Verweis hinzuzufügen (ich habe deshalb in der Frage nur eine berechnete Spalte gezeigt) Ich möchte die Datentabellen nicht mit temporären Feldern "polieren". Ich werde meine Frage klären. –

+0

** Korrektur: ** Ich habe gerade herausgefunden, dass ': =' in der zweiten oder höheren verwendet '[...] 'Kette fügt das Feld NICHT zur ursprünglichen Datentabelle hinzu, also genau, was ich wollte! –

+1

Ich habe mich entschieden, meine Frage auf den Hauptteil zu konzentrieren (alle Spalten aus beiden Tabellen) und die Variationen entfernt (alle Spalten aus nur einer Tabelle). Ihr Code-Snippet 2 ist die richtige Lösung. –

0

Sie können nur die Spalten in DT2 halten, die Sie benötigen:

DT1 = data.table(x=c("c", "a", "b", "a", "b"), a=1:5, d=rnorm(5)) 
DT2 = data.table(x=c("d", "c", "b"), b=6:8, c=letters[3]) 

DT3 <- DT1[DT2[,.(x,b), on="x"][, sum := a+b]