1539 Stimmen

Zusammenführen von Datenrahmen (innen, außen, links, rechts)

Gegeben sind zwei Datenrahmen:

df1 = data.frame(CustomerId = c(1:6), Product = c(rep("Toaster", 3), rep("Radio", 3)))
df2 = data.frame(CustomerId = c(2, 4, 6), State = c(rep("Alabama", 2), rep("Ohio", 1)))

df1
#  CustomerId Product
#           1 Toaster
#           2 Toaster
#           3 Toaster
#           4   Radio
#           5   Radio
#           6   Radio

df2
#  CustomerId   State
#           2 Alabama
#           4 Alabama
#           6    Ohio

Wie kann ich den Datenbankstil, d.h., sql-stil, joins ? Das heißt, wie bekomme ich:

  • Eine innere Verknüpfung de df1 y df2 :
    Gibt nur die Zeilen zurück, in denen die linke Tabelle übereinstimmende Schlüssel in der rechten Tabelle hat.
  • Eine äußere Verbindung de df1 y df2 :
    Gibt alle Zeilen aus beiden Tabellen zurück, verbindet Datensätze aus der linken Tabelle, die übereinstimmende Schlüssel in der rechten Tabelle haben.
  • A Left Outer Join (oder einfach Left Join) de df1 y df2
    Gibt alle Zeilen aus der linken Tabelle und alle Zeilen mit übereinstimmenden Schlüsseln aus der rechten Tabelle zurück.
  • A rechte äußere Verbindung de df1 y df2
    Gibt alle Zeilen aus der rechten Tabelle und alle Zeilen mit übereinstimmenden Schlüsseln aus der linken Tabelle zurück.

Extra Kredit:

Wie kann ich eine SQL-ähnliche Select-Anweisung ausführen?

2 Stimmen

Der Spickzettel "Data Transformation with dplyr", der von RStudio erstellt und gepflegt wird, enthält auch schöne Infografiken darüber, wie Joins in dplyr funktionieren rstudio.com/resources/cheatsheets

5 Stimmen

Wenn Sie stattdessen hierher gekommen sind, um etwas über die Zusammenlegung von Pandas Dataframes, diese Ressource kann gefunden werden aquí .

1 Stimmen

Für @isomorphismes Link ist hier eine aktuelle archivierte Version: web.archive.org/web/20190312112515/http://stat545.com/…

1652voto

Matt Parker Punkte 25875

Durch die Verwendung des merge Funktion und ihre optionalen Parameter:

Innere Verbindung: merge(df1, df2) funktioniert für diese Beispiele, weil R die Frames automatisch durch gemeinsame Variablennamen verbindet, aber Sie würden wahrscheinlich angeben wollen merge(df1, df2, by = "CustomerId") um sicherzustellen, dass Sie nur die gewünschten Felder abgleichen. Sie können auch die by.x y by.y Parameter, wenn die übereinstimmenden Variablen in den verschiedenen Datenrahmen unterschiedliche Namen haben.

Äußere Verbindung: merge(x = df1, y = df2, by = "CustomerId", all = TRUE)

Links außen: merge(x = df1, y = df2, by = "CustomerId", all.x = TRUE)

Rechts außen: merge(x = df1, y = df2, by = "CustomerId", all.y = TRUE)

Kreuzverbindung: merge(x = df1, y = df2, by = NULL)

Genau wie bei der inneren Verknüpfung möchten Sie wahrscheinlich "CustomerId" explizit als übereinstimmende Variable an R übergeben. Ich denke, es ist fast immer am besten, die Bezeichner, die Sie zusammenführen wollen, explizit anzugeben; das ist sicherer, wenn sich die eingegebenen data.frames unerwartet ändern, und später leichter zu lesen.

Sie können auf mehrere Spalten zusammenführen, indem Sie by einen Vektor, z.B., by = c("CustomerId", "OrderId") .

Wenn die Spaltennamen, die zusammengeführt werden sollen, nicht identisch sind, können Sie z. B. angeben, by.x = "CustomerId_in_df1", by.y = "CustomerId_in_df2" donde CustomerId_in_df1 ist der Name der Spalte im ersten Datenrahmen und CustomerId_in_df2 ist der Name der Spalte im zweiten Datenrahmen. (Dies können auch Vektoren sein, wenn Sie mehrere Spalten zusammenführen müssen).

3 Stimmen

@MattParker Ich habe mit sqldf-Paket für eine ganze Reihe von komplexen Abfragen gegen dataframes, wirklich brauchte es, um eine Selbst-Cross-Join (dh data.frame Cross-Joining selbst) Ich frage mich, wie es von einer Performance-Perspektive vergleicht....???

10 Stimmen

@ADP Ich habe sqldf nie wirklich benutzt, daher bin ich mir über die Geschwindigkeit nicht sicher. Wenn Leistung für Sie ein wichtiges Thema ist, sollten Sie sich auch mit dem data.table Paket - das ist eine ganz neue Join-Syntax, aber sie ist wesentlich schneller als alles, worüber wir hier sprechen.

6 Stimmen

Mit mehr Klarheit und Erklärung..... mkmanu.wordpress.com/2016/04/08/

257voto

medriscoll Punkte 25767

Ich würde empfehlen, sich die Das Paket sqldf von Gabor Grothendieck die es Ihnen ermöglicht, diese Operationen in SQL auszudrücken.

library(sqldf)

## inner join
df3 <- sqldf("SELECT CustomerId, Product, State 
              FROM df1
              JOIN df2 USING(CustomerID)")

## left join (substitute 'right' for right join)
df4 <- sqldf("SELECT CustomerId, Product, State 
              FROM df1
              LEFT JOIN df2 USING(CustomerID)")

Ich finde die SQL-Syntax einfacher und natürlicher als ihr R-Äquivalent (aber das mag nur meine RDBMS-Vorurteile widerspiegeln).

Ver Gabors sqldf GitHub für weitere Informationen über Verbindungen.

254voto

Andrew Barr Punkte 3389

Sie können auch Verbindungen herstellen, indem Sie Hadley Wickhams großartiges dplyr Paket.

library(dplyr)

#make sure that CustomerId cols are both type numeric
#they ARE not using the provided code in question and dplyr will complain
df1$CustomerId <- as.numeric(df1$CustomerId)
df2$CustomerId <- as.numeric(df2$CustomerId)

Mutating Joins: Hinzufügen von Spalten zu df1 anhand von Übereinstimmungen in df2

#inner
inner_join(df1, df2)

#left outer
left_join(df1, df2)

#right outer
right_join(df1, df2)

#alternate right outer
left_join(df2, df1)

#full join
full_join(df1, df2)

Filtern von Joins: Zeilen in df1 herausfiltern, Spalten nicht ändern

semi_join(df1, df2) #keep only observations in df1 that match in df2.
anti_join(df1, df2) #drops all observations in df1 that match in df2.

20 Stimmen

Warum müssen Sie konvertieren? CustomerId zu numerisch? Ich finde in der Dokumentation keinen Hinweis darauf (sowohl für plyr y dplyr ) über diese Art von Einschränkung. Würde Ihr Code nicht korrekt funktionieren, wenn die Merge-Spalte von character Typ (besonders interessiert an plyr )? Übersehe ich etwas?

0 Stimmen

Könnte man semi_join(df1, df2, df3, df4) verwenden, um nur die Beobachtungen in df1 zu behalten, die mit den restlichen Spalten übereinstimmen?

0 Stimmen

@GhoseBishwajit In der Annahme, dass Sie den Rest der Datenrahmen anstelle von Spalten meinen, könnten Sie rbind auf df2, df3 und df4 verwenden, wenn sie dieselbe Struktur haben, z. B. semi_join(df1, rbind(df2, df3, df4))

239voto

Etienne Low-Décarie Punkte 12463

Es gibt die Daten.Tabelle Ansatz für eine innere Verknüpfung, der sehr zeit- und speichereffizient ist (und für einige größere data.frames notwendig):

library(data.table)

dt1 <- data.table(df1, key = "CustomerId") 
dt2 <- data.table(df2, key = "CustomerId")

joined.dt1.dt.2 <- dt1[dt2]

merge funktioniert auch bei data.tables (da es generisch ist und die merge.data.table )

merge(dt1, dt2)

data.table auf Stackoverflow dokumentiert:
Wie führt man eine data.table-Zusammenführung durch?
Übersetzen von SQL-Joins auf Fremdschlüsseln in die Syntax von R data.table
Effiziente Alternativen zum Zusammenführen für größere Datenrahmen R
Wie macht man einen einfachen Left Outer Join mit data.table in R?

Eine weitere Möglichkeit ist die join Funktion, die in der plyr Paket

library(plyr)

join(df1, df2,
     type = "inner")

#   CustomerId Product   State
# 1          2 Toaster Alabama
# 2          4   Radio Alabama
# 3          6   Radio    Ohio

Optionen für type : inner , left , right , full .

Von ?join : Im Gegensatz zu merge , [ join ] behält die Reihenfolge von x bei, unabhängig davon, welche Verknüpfungsart verwendet wird.

11 Stimmen

+1 für die Erwähnung plyr::join . Microbenchmarking zeigt, dass es etwa 3 mal schneller ist als merge .

25 Stimmen

Allerdings, data.table ist viel schneller als beide. Es gibt auch eine großartige Unterstützung in SO, ich sehe nicht viele Paketschreiber, die hier so oft Fragen beantworten wie die data.table Verfasser oder Mitwirkende.

7 Stimmen

Bitte beachten Sie: dt1[dt2] ist eine rechte äußere Verknüpfung (keine "reine" innere Verknüpfung) so dass ALLE Zeilen aus dt2 Teil des Ergebnisses sind, auch wenn es keine passende Zeile in dt1 gibt. Auswirkungen: Ihr Ergebnis enthält potenziell unerwünschte Zeilen wenn Sie Schlüsselwerte in dt2 haben, die nicht mit den Schlüsselwerten von dt1 übereinstimmen.

111voto

JD Long Punkte 57096

Es gibt einige gute Beispiele für diese Vorgehensweise auf der R Wiki . Ich werde hier ein paar klauen:

Zusammenführungsmethode

Da Ihre Schlüssel gleich benannt sind, ist der kürzeste Weg, eine innere Verknüpfung durchzuführen, merge():

merge(df1, df2)

eine vollständige innere Verknüpfung (alle Datensätze aus beiden Tabellen) kann mit dem Schlüsselwort "all" erstellt werden:

merge(df1, df2, all=TRUE)

eine linke äußere Verknüpfung von df1 und df2:

merge(df1, df2, all.x=TRUE)

eine rechte äußere Verknüpfung von df1 und df2:

merge(df1, df2, all.y=TRUE)

du kannst sie umdrehen, schlagen und reiben, um die anderen beiden äußeren Verbindungen zu erhalten, nach denen du gefragt hast :)

Subscript-Methode

Eine linke äußere Verknüpfung mit df1 auf der linken Seite unter Verwendung einer tiefgestellten Methode wäre wie folgt:

df1[,"State"]<-df2[df1[ ,"Product"], "State"]

Die andere Kombination äußerer Verknüpfungen kann erstellt werden, indem man das Beispiel für die linke äußere Verknüpfung umschreibt. (ja, ich weiß, das ist das Äquivalent zu "Ich überlasse es dem Leser als Übung...")

0 Stimmen

Sollte sein: "Hau drauf, dreh es um, reib es ab", aber es ist ein guter Versuch ;-)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X