11.5 Cruces de tablas

Con la función merge pueden hacerse cruces de tablas. Para ilustrar los distintos tipos de cruce, crearemos unos datos pequeños de ejemplo:

clientes <- data.frame(id = 1:3, nombre = c("Carlos", "Sara", "Raquel"))
ventas <- data.frame(fecha = c(1, 1, 1, 2, 2, 3, 3, 3, 4), 
                     id = c(1,2,3,2,3, 1, 2, 3, 3), 
                     total = 100 * runif(9))

Para cruzarlas por defecto, se usa la función merge:

merge(clientes, ventas)
##   id nombre fecha    total
## 1  1 Carlos     1 75.04759
## 2  1 Carlos     3 41.64581
## 3  2   Sara     3 78.36645
## 4  2   Sara     2 90.88009
## 5  2   Sara     1 24.15553
## 6  3 Raquel     2 95.34162
## 7  3 Raquel     1 61.04433
## 8  3 Raquel     3 81.18654
## 9  3 Raquel     4 98.56591

Esta función crea una nueva tabla juntando filas de otras dos. El resultado es el mismo que la consulta de SQL

select * 
from clientes a, ventas b
where a.id = b.id

merge junta las filas que tienen el mismo valor en los campos de cruce. Por defecto, los campos de cruce son aquellos que se llaman igual en ambas tablas. Esto es a la vez cómodo (evita tener que especificarlas explícitamente) y peligroso. En el ejercicio siguiente se te pide que investigues cómo modificar este funcionamiento por defecto de merge.

¿Y si las variables de cruce no se llaman igual? ¿Y si no quieres cruzar por todas ellas?

merge también permite realizar left joins. Nótese la diferencia entre las dos tablas creadas por merge en el ejemplo siguiente.

ventas.2 <- ventas[ventas$fecha == 2,]
merge(clientes, ventas.2)
##   id nombre fecha    total
## 1  2   Sara     2 90.88009
## 2  3 Raquel     2 95.34162
merge(clientes, ventas.2, all.x = T)
##   id nombre fecha    total
## 1  1 Carlos    NA       NA
## 2  2   Sara     2 90.88009
## 3  3 Raquel     2 95.34162

La consulta de SQL equivalente a la última expresión es

select * 
from clientes a left join ventas.2 b
on a.id = b.id

Para el ejercicio siguiente vamos a crear una tabla simulada,

n <- 10000
n.clientes <- 1000

contracts <- data.frame(
  customer  = sample(n.clientes, n, replace = T),
  contract  = sample(n, n),
  amount    = 1000 * exp(runif(n))
)

que contiene clientes, contratos y el importe de cada contrato.

Calcula el porcentaje que cada contrato de un cliente supone dentro de su facturación total. P.e., si un cliente tiene dos contratos de 200 y 800 euros, a la primera fila le asociaremos un 20% y, a la segunda, 80%. Una manera de hacerlo consiste en:

  • Crear una tabla que agregue el total de los importes por cliente
  • Cruzar esta nueva tabla con la original (por cliente)
  • Dividir el importe original por el total y multiplicarlo por 100.

merge es la función por defecto para cruzar tablas en R. Sin embargo, existe una colección de funciones (left_join, inner_join, etc.) en el paquete dplyr que pueden resultar más familiares a quienes tengan experiencia con SQL29.


  1. Puede consultarse un tutorial de estas funciones aquí