Cómo unir (fusionar) marcos de datos (interior, exterior, izquierda, derecha)

Resuelto Dan Goldstein asked hace 54 años • 14 respuestas

Dados dos marcos de datos:

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

¿Cómo puedo unir el estilo de la base de datos, es decir, el estilo SQL ? Es decir, ¿cómo consigo:

  • Una combinación interna de df1y df2:
    Devuelve solo las filas en las que la tabla de la izquierda tiene claves coincidentes en la tabla de la derecha.
  • Una combinación externa de df1y df2:
    devuelve todas las filas de ambas tablas, une los registros de la izquierda que tienen claves coincidentes en la tabla de la derecha.
  • Una combinación externa izquierda (o simplemente una combinación izquierda) de df1y df2
    Devuelve todas las filas de la tabla de la izquierda y cualquier fila con claves coincidentes de la tabla de la derecha.
  • Una combinación externa derecha de df1y df2
    Devuelve todas las filas de la tabla derecha y cualquier fila con claves coincidentes de la tabla izquierda.

Crédito adicional:

¿Cómo puedo hacer una declaración de selección de estilo SQL?

Dan Goldstein avatar Jan 01 '70 08:01 Dan Goldstein
Aceptado

Usando la mergefunción y sus parámetros opcionales:

Unión interna: merge(df1, df2) funcionará para estos ejemplos porque R une automáticamente los marcos mediante nombres de variables comunes, pero lo más probable es que desee especificarlomerge(df1, df2, by = "CustomerId")para asegurarse de que coincida solo en los campos que desea. También puede utilizar losby.xyby.ysi las variables coincidentes tienen nombres diferentes en los diferentes marcos de datos.

Unión externa: merge(x = df1, y = df2, by = "CustomerId", all = TRUE)

Exterior izquierdo: merge(x = df1, y = df2, by = "CustomerId", all.x = TRUE)

Exterior derecho: merge(x = df1, y = df2, by = "CustomerId", all.y = TRUE)

Unión cruzada: merge(x = df1, y = df2, by = NULL)

Al igual que con la combinación interna, probablemente desee pasar explícitamente "CustomerId" a R como variable coincidente. Creo que casi siempre es mejor indicar explícitamente los identificadores que desea fusionar; Es más seguro si los marcos de datos de entrada cambian inesperadamente y son más fáciles de leer más adelante.

Puede fusionar varias columnas proporcionando byun vector, por ejemplo, by = c("CustomerId", "OrderId").

Si los nombres de las columnas a fusionar no son los mismos, puede especificar, por ejemplo, by.x = "CustomerId_in_df1", by.y = "CustomerId_in_df2"dónde CustomerId_in_df1está el nombre de la columna en el primer marco de datos y dónde CustomerId_in_df2está el nombre de la columna en el segundo marco de datos. (Estos también pueden ser vectores si necesita fusionar varias columnas).

Matt Parker avatar Aug 19 '2009 15:08 Matt Parker

Recomendaría consultar el paquete sqldf de Gabor Grothendieck , que le permite expresar estas operaciones en SQL.

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)")

Considero que la sintaxis de SQL es más simple y natural que su equivalente en R (pero esto puede reflejar mi preferencia por RDBMS).

Consulte sqldf GitHub de Gabor para obtener más información sobre las uniones.

medriscoll avatar Aug 20 '2009 17:08 medriscoll

También puedes hacer uniones usando el increíble paquete dplyr de Hadley Wickham .

library(dplyr)

#make sure that CustomerId cols are both the same type
#they aren’t in the provided data (one is integer and one is double)
df1$CustomerId <- as.double(df1$CustomerId)

Uniones mutantes: agregue columnas a df1 usando coincidencias en 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)

Filtrado de uniones: filtre filas en df1, no modifique columnas

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

#drop all observations in df1 that match in df2.
anti_join(df1, df2)
Andrew Barr avatar Feb 06 '2014 21:02 Andrew Barr

Existe el enfoque data.table para una unión interna, que es muy eficiente en tiempo y memoria (y necesario para algunos marcos de datos más grandes):

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

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

mergetambién funciona en data.tables (ya que es genérico y llama merge.data.table)

merge(dt1, dt2)

data.table documentado en stackoverflow:
Cómo hacer una operación de fusión de data.table
Traducir uniones SQL en claves externas a la sintaxis de R data.table
Alternativas eficientes para fusionar para data.frames más grandes R
Cómo hacer una unión externa izquierda básica con data.table en R?

Otra opción más es la joinfunción que se encuentra en el paquete plyr . [Nota de 2022: plyr ya está retirado y ha sido reemplazado por dplyr . Las operaciones de unión en dplyr se describen en esta respuesta .]

library(plyr)

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

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

Opciones para type: inner, left, right, full.

De ?join: A diferencia de merge, [ join] conserva el orden de x sin importar qué tipo de combinación se utilice.

Etienne Low-Décarie avatar Mar 11 '2012 06:03 Etienne Low-Décarie

Hay algunos buenos ejemplos de cómo hacer esto en R Wiki . Robaré un par aquí:

Método de fusión

Dado que sus claves tienen el mismo nombre, la forma corta de realizar una unión interna es fusionar():

merge(df1, df2)

Se puede crear una combinación interna completa (todos los registros de ambas tablas) con la palabra clave "todos":

merge(df1, df2, all=TRUE)

una unión exterior izquierda de df1 y df2:

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

una unión exterior derecha de df1 y df2:

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

puedes darles la vuelta, darles una bofetada y frotarlas para obtener las otras dos uniones exteriores sobre las que preguntaste :)

Método de subíndice

Una unión externa izquierda con df1 a la izquierda usando un método de subíndice sería:

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

La otra combinación de uniones externas se puede crear mezclando el ejemplo del subíndice de unión externa izquierda. (sí, sé que eso equivale a decir "lo dejaré como ejercicio para el lector...")

JD Long avatar Aug 19 '2009 15:08 JD Long