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 hacer un estilo de base de datos, es decir, estilo sql, une ? Es decir, cómo obtengo:
- Una combinación interna de
df1
ydf2
:
devuelve solo las filas en las que la tabla izquierda tiene claves coincidentes en la tabla derecha. - Una combinación externa de
df1
ydf2
:
devuelve todas las filas de ambas tablas, registros de unión de la izquierda que tienen claves coincidentes en la tabla de la derecha. - Una combinación externa izquierda (o simplemente combinación izquierda) de
df1
ydf2
Devuelve todas las filas de la tabla izquierda, y cualquier fila con teclas coincidentes de la tabla derecha. - Una combinación externa derecha de
df1
ydf2
Devuelve todas las filas de la tabla derecha, y cualquier fila con teclas coincidentes de la tabla izquierda.
Crédito adicional:
¿Cómo puedo hacer una declaración de selección de estilo SQL?
Respuestas:
Al usar la
merge
función y sus parámetros opcionales:Unión interna:
merge(df1, df2)
funcionará para estos ejemplos porque R une automáticamente los marcos por nombres de variables comunes, pero lo más probable es que desee especificarmerge(df1, df2, by = "CustomerId")
para asegurarse de que coincida solo en los campos que desea. También puede usar losparámetrosby.x
yby.y
si 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)
Derecho exterior:
merge(x = df1, y = df2, by = "CustomerId", all.y = TRUE)
Cruz de unión:
merge(x = df1, y = df2, by = NULL)
Al igual que con la combinación interna, es probable que desee pasar explícitamente "CustomerId" a R como la variable coincidente.Creo que casi siempre es mejor indicar explícitamente los identificadores en los que desea fusionarse; 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 combinar en varias columnas, dando
by
un vector, por ejemplo,by = c("CustomerId", "OrderId")
.Si los nombres de columna para fusionar no son los mismos, puede especificar, por ejemplo,
by.x = "CustomerId_in_df1", by.y = "CustomerId_in_df2"
dóndeCustomerId_in_df1
está el nombre de la columna en el primer marco de datos yCustomerId_in_df2
es el nombre de la columna en el segundo marco de datos. (Estos también pueden ser vectores si necesita fusionarse en varias columnas).fuente
data.table
paquete: es un conjunto completamente nuevo de sintaxis de combinación, pero es radicalmente más rápido que cualquier cosa de la que estamos hablando aquí.merge(x=df1,y=df2, by.x=c("x_col1","x_col2"), by.y=c("y_col1","y_col2"))
data.table
ahora, la misma función solo que más rápido.Recomendaría consultar el paquete sqldf de Gabor Grothendieck , que le permite expresar estas operaciones en SQL.
Creo que la sintaxis de SQL es más simple y más natural que su equivalente R (pero esto puede reflejar mi sesgo RDBMS).
Consulte sqldf GitHub de Gabor para obtener más información sobre combinaciones.
fuente
Existe el enfoque data.table para una unión interna, que es muy eficiente en cuanto a tiempo y memoria (y necesario para algunos data.frames más grandes):
merge
también funciona en data.tables (ya que es genérico y llamamerge.data.table
)data.table documentado en stackoverflow:
Cómo hacer una operación de combinación data.table
Traducción de uniones SQL en claves foráneas a R sintaxis data.table
Alternativas eficientes para combinar 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 es la
join
función que se encuentra en el paquete plyrLas opciones para
type
:inner
,left
,right
,full
.De
?join
: A diferenciamerge
, [join
] conserva el orden de x sin importar qué tipo de combinación se use.fuente
plyr::join
. Microbenchmarking indica que se realiza aproximadamente 3 veces más rápido quemerge
.data.table
es mucho más rápido que ambos. También hay un gran soporte en SO, no veo a muchos escritores de paquetes respondiendo preguntas aquí tan a menudo como eldata.table
escritor o los contribuyentes.data.table
sintaxis para fusionar una lista de marcos de datos ?nomatch = 0L
en ese caso.También puedes hacer combinaciones usando el increíble paquete dplyr de Hadley Wickham .
Mutación de combinaciones: agregue columnas a df1 utilizando coincidencias en df2
Filtrado de combinaciones: filtrar filas en df1, no modificar columnas
fuente
CustomerId
a numérico? No veo ninguna mención en la documentación (para ambosplyr
ydplyr
) sobre este tipo de restricción. ¿Funcionaría incorrectamente su código si la columna de combinación fuera delcharacter
tipo (especialmente interesadoplyr
)? ¿Me estoy perdiendo de algo?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 hacer una unión interna es merge ():
se puede crear una unión interna completa (todos los registros de ambas tablas) con la palabra clave "all":
una unión externa izquierda de df1 y df2:
una unión externa derecha de df1 y df2:
puedes voltearlos, abofetearlos y frotarlos para obtener las otras dos uniones externas que preguntaste :)
Método de subíndice
Una combinación externa izquierda con df1 a la izquierda usando un método de subíndice sería:
La otra combinación de combinaciones externas se puede crear mezclando el ejemplo de subíndice de combinación externa izquierda. (Sí, sé que es el equivalente a decir "Lo dejaré como un ejercicio para el lector ...")
fuente
Nuevo en 2014:
Especialmente si también está interesado en la manipulación de datos en general (incluida la clasificación, filtrado, subconjunto, resumen, etc.), definitivamente debe echar un vistazo
dplyr
, que viene con una variedad de funciones, todas diseñadas para facilitar su trabajo específicamente con marcos de datos y ciertos otros tipos de bases de datos. Incluso ofrece una interfaz SQL bastante elaborada, e incluso una función para convertir (la mayoría) del código SQL directamente en R.Las cuatro funciones relacionadas con la unión en el paquete dplyr son (entre comillas):
inner_join(x, y, by = NULL, copy = FALSE, ...)
: devuelve todas las filas de x donde hay valores coincidentes en y, y todas las columnas de x e yleft_join(x, y, by = NULL, copy = FALSE, ...)
: devuelve todas las filas de x, y todas las columnas de x e ysemi_join(x, y, by = NULL, copy = FALSE, ...)
: devuelve todas las filas de x donde hay valores coincidentes en y, manteniendo solo columnas de x.anti_join(x, y, by = NULL, copy = FALSE, ...)
: devuelve todas las filas de x donde no hay valores coincidentes en y, manteniendo solo columnas de xTodo está aquí con gran detalle.
La selección de columnas se puede hacer por
select(df,"column")
. Si eso no es lo suficientemente SQL para usted, entonces está lasql()
función, en la que puede ingresar el código SQL tal cual, y realizará la operación que especificó tal como estaba escribiendo en R todo el tiempo (para obtener más información, consulte a la viñeta dplyr / bases de datos ). Por ejemplo, si se aplica correctamente,sql("SELECT * FROM hflights")
seleccionará todas las columnas de la tabla dplyr "hflights" (un "tbl").fuente
Actualización sobre métodos data.table para unir conjuntos de datos. Vea los ejemplos a continuación para cada tipo de unión. Hay dos métodos, uno desde el
[.data.table
momento en que se pasa la segunda tabla de datos como el primer argumento para el subconjunto, otra forma es usar lamerge
función que despacha al método rápido de tabla de datos.Por debajo de las pruebas de referencia base R, sqldf, dplyr y data.table.
Las pruebas de referencia prueban conjuntos de datos no codificados / no indexados. El punto de referencia se realiza en conjuntos de datos de filas de 50M-1, hay valores comunes de 50M-2 en la columna de unión, por lo que cada escenario (interno, izquierdo, derecho, completo) se puede probar y la unión aún no es trivial de realizar. Es un tipo de unión que también enfatiza los algoritmos de unión. Sincronizaciones son con fecha de
sqldf:0.4.11
,dplyr:0.7.8
,data.table:1.12.0
.Tenga en cuenta que hay otros tipos de combinaciones que puede realizar usando
data.table
:- actualizar en combinación - si desea buscar valores de otra tabla a su tabla principal
- agregar en combinación - si desea agregar en clave que está uniendo, no tiene para materializar todos se unen resultados
- la superposición de unirse a - si desea combinar por cadenas
- rodando unirse a - si quieres fusión para poder coincidir con los valores de precedente / siguiente filas haciendo rodar hacia delante o hacia atrás
- no equi unen - si su la condición de unión no es igual
Código para reproducir:
fuente
on =
también?on
argmerge.data.table
existe elsort = TRUE
argumento predeterminado , que agrega una clave durante la fusión y la deja allí en el resultado? Esto es algo a tener en cuenta, especialmente si está tratando de evitar configurar las teclas.data.table
, ¿qué quieres decir? Puede ser más específico, por favor.dplyr desde 0.4 implementó todas esas uniones incluidas
outer_join
, pero valió la pena señalar que durante las primeras versiones anteriores a 0.4 solía no ofrecerouter_join
, y como resultado había un montón de código de usuario de solución alternativa muy malo flotando durante bastante tiempo después (todavía puede encontrar dicho código en SO, respuestas de Kaggle, github de ese período. Por lo tanto, esta respuesta todavía tiene un propósito útil).Destacados de lanzamiento relacionados con Join :
v0.5 (6/2016)
v0.4.0 (1/2015)
v0.3 (10/2014)
v0.2 (5/2014)
v0.1.3 (4/2014)
Soluciones para los comentarios de hadley en ese tema:
fuente
dplyr
sintaxis, el cambio delazyeval
arlang
backends rompió un montón de código para mí, que me volvía a aprender másdata.table
, y ahora sobre todo utilizardata.table
.)plyr
/dplyr
/data.table
/ tidyverse depende en gran medida de qué año comenzamos, y de qué estado (embrionario) estaban los paquetes en ese entonces, a diferencia de ahora ...Al unir dos marcos de datos con ~ 1 millón de filas cada uno, uno con 2 columnas y el otro con ~ 20, sorprendentemente he encontrado
merge(..., all.x = TRUE, all.y = TRUE)
que es más rápido entoncesdplyr::full_join()
. Esto es con dplyr v0.4La fusión tarda ~ 17 segundos, full_join tarda ~ 65 segundos.
Sin embargo, algo de comida, ya que generalmente prefiero dplyr para tareas de manipulación.
fuente
Para el caso de una unión izquierda con una
0..*:0..1
cardinalidad o una unión derecha con una0..1:0..*
cardinalidad, es posible asignar en el lugar las columnas unilaterales de la unión (la0..1
tabla) directamente sobre la unión (la0..*
tabla), y así evitar la creación de Una tabla de datos completamente nueva. Esto requiere hacer coincidir las columnas clave del participante en el ensamblador e indexar + ordenar las filas del ensamblador en consecuencia para la asignación.Si la clave es una sola columna, entonces podemos usar una sola llamada a
match()
para hacer la coincidencia. Este es el caso que cubriré en esta respuesta.Aquí hay un ejemplo basado en el OP, excepto que agregué una fila adicional
df2
con una identificación de 7 para probar el caso de una clave que no coincide en la combinación. Esto sedf1
deja efectivamente unirsedf2
:En lo anterior codifiqué la suposición de que la columna clave es la primera columna de ambas tablas de entrada. Yo diría que, en general, esto no es una suposición irrazonable, ya que, si tiene un data.frame con una columna clave, sería extraño si no se hubiera configurado como la primera columna del data.frame desde El principio. Y siempre puede reordenar las columnas para que sea así. Una consecuencia ventajosa de esta suposición es que el nombre de la columna clave no tiene que estar codificado, aunque supongo que solo está reemplazando una suposición por otra. La concisión es otra ventaja de la indexación de enteros, así como la velocidad. En los puntos de referencia a continuación, cambiaré la implementación para usar la indexación de nombre de cadena para que coincida con las implementaciones de la competencia.
Creo que esta es una solución particularmente apropiada si tiene varias tablas que desea unir en una sola tabla grande. La reconstrucción repetida de la tabla completa para cada fusión sería innecesaria e ineficiente.
Por otro lado, si necesita que el participante permanezca inalterado a través de esta operación por cualquier razón, entonces esta solución no se puede usar, ya que modifica al participante directamente. Aunque en ese caso, simplemente podría hacer una copia y realizar las asignaciones en el lugar en la copia.
Como nota al margen, analicé brevemente las posibles soluciones de coincidencia para las claves de varias columnas. Desafortunadamente, las únicas soluciones coincidentes que encontré fueron:
match(interaction(df1$a,df1$b),interaction(df2$a,df2$b))
, o la misma idea conpaste()
.outer(df1$a,df2$a,`==`) & outer(df1$b,df2$b,`==`)
.merge()
y funciones de fusión basadas en paquetes equivalentes, que siempre asignan una nueva tabla para devolver el resultado combinado, y por lo tanto no son adecuadas para una solución basada en asignación en el lugar.Por ejemplo, vea Hacer coincidir varias columnas en diferentes marcos de datos y obtener otra columna como resultado , hacer coincidir dos columnas con otras dos columnas , Hacer coincidir en varias columnas y el engaño de esta pregunta donde originalmente se me ocurrió la solución in situ, Combinar dos tramas de datos con diferente número de filas de R .
Benchmarking
Decidí hacer mi propia evaluación comparativa para ver cómo el enfoque de asignación en el lugar se compara con las otras soluciones que se han ofrecido en esta pregunta.
Código de prueba:
Aquí hay un punto de referencia del ejemplo basado en el OP que demostré anteriormente:
Aquí comparo datos de entrada aleatorios, probando diferentes escalas y diferentes patrones de superposición de teclas entre las dos tablas de entrada. Este punto de referencia todavía está restringido al caso de una clave entera de una sola columna. Además, para garantizar que la solución en el lugar funcione para las uniones izquierda y derecha de las mismas tablas, todos los datos de prueba aleatorios usan
0..1:0..1
cardinalidad. Esto se implementa mediante el muestreo sin reemplazo de la columna clave del primer data.frame al generar la columna clave del segundo data.frame.Escribí un código para crear diagramas de log-log de los resultados anteriores. Genere un gráfico separado para cada porcentaje de superposición. Está un poco desordenado, pero me gusta tener todos los tipos de soluciones y tipos de unión representados en la misma trama.
Usé la interpolación de spline para mostrar una curva suave para cada combinación de solución / tipo de unión, dibujada con símbolos pch individuales. El tipo de unión es capturado por el símbolo pch, usando un punto para los corchetes angulares internos, izquierdo y derecho para izquierda y derecha, y un diamante para completo. El tipo de solución es capturado por el color como se muestra en la leyenda.
Aquí hay un segundo punto de referencia a gran escala que es más resistente, con respecto al número y los tipos de columnas clave, así como a la cardinalidad. Para este punto de referencia utilizo tres columnas clave: un carácter, un número entero y uno lógico, sin restricciones de cardinalidad (es decir,
0..*:0..*
). (En general, no es aconsejable definir columnas clave con valores dobles o complejos debido a complicaciones de comparación de punto flotante, y básicamente nadie usa el tipo sin formato, mucho menos para columnas clave, por lo que no he incluido esos tipos en la clave Además, por el bien de la información, inicialmente intenté usar cuatro columnas clave al incluir una columna de clave POSIXct, pero el tipo POSIXct no funcionó bien con lasqldf.indexed
solución por alguna razón, posiblemente debido a anomalías de comparación de punto flotante, así que eliminado)Las parcelas resultantes, utilizando el mismo código de trazado dado anteriormente:
fuente
merge
función podemos seleccionar la variable de la tabla izquierda o la tabla derecha, de la misma manera que todos estamos familiarizados con la instrucción select en SQL (EX: Seleccione a. * ... o Seleccione b. * De .....)Tenemos que agregar código adicional que se subconjunto de la tabla recién unida.
SQL: -
select a.* from df1 a inner join df2 b on a.CustomerId=b.CustomerId
R: -
merge(df1, df2, by.x = "CustomerId", by.y = "CustomerId")[,names(df1)]
Mismo camino
SQL: -
select b.* from df1 a inner join df2 b on a.CustomerId=b.CustomerId
R: -
merge(df1, df2, by.x = "CustomerId", by.y = "CustomerId")[,names(df2)]
fuente
Para una unión interna en todas las columnas, también puede usar
fintersect
desde data.table -package ointersect
desde dplyr -package como una alternativamerge
sin especificar lasby
-columnas. esto dará las filas que son iguales entre dos marcos de datos:Datos de ejemplo:
fuente
Actualizar unirse. Otra combinación importante de estilo SQL es una " combinación de actualización " donde las columnas de una tabla se actualizan (o crean) utilizando otra tabla.
Modificando las tablas de ejemplo del OP ...
Supongamos que queremos agregar el estado del cliente
cust
a la tabla de comprassales
, ignorando la columna del año. Con la base R, podemos identificar filas coincidentes y luego copiar valores sobre:Como se puede ver aquí,
match
selecciona la primera fila coincidente de la tabla de clientes.Actualización de unirse con múltiples columnas. El enfoque anterior funciona bien cuando nos unimos en una sola columna y estamos satisfechos con la primera coincidencia. Supongamos que queremos que el año de medición en la tabla del cliente coincida con el año de venta.
Como respuesta @ de bgoldst menciona,
match
coninteraction
podría ser una opción para este caso. Más directamente, uno podría usar data.table:Actualización continua unirse. Alternativamente, podemos querer tomar el último estado en el que se encontró al cliente:
Los tres ejemplos anteriores se centran en crear / agregar una nueva columna. Consulte las preguntas frecuentes relacionadas con R para ver un ejemplo de actualización / modificación de una columna existente.
fuente