Unir o cruzar datos con left_join()

16/8/2025

Temas: procesamiento de datos limpieza de datos

El left join es una de las operaciones básicas del trabajo con datos, en el sentido de que realiza una operación sencilla que a la vez es muy útil. Sirve tanto para limpiar datos como para procesarlos y obtener nuevas relaciones entre ellos.

Un left join realiza una unión o combinación entre dos tablas de datos a partir de una variable en común o clave (key). En otras palabras, un left join toma dos tablas que tienen datos distintos, pero que comparten una variable o columna en común, y usa esta variable en común para unir las observaciones de ambas tablas.

Esquema de una unión entre tablas con left join

En el ejemplo anterior, tenemos dos tablas, ambas con tres variables distintas, pero en ambas tablas tenemos una variable que contiene información equivalente. En la vida real, esto podrían ser nombres de personas, nombres de países, identificadores únicos de personas o instituciones, fechas, etcétera. Esta variable compartida entre las tablas es la llave que usaremos para la unión.

Al realiazr la unión con left join obtenemos una nueva tabla que combina las observaciones de ambas, uniendo las filas de la primera tabla (x) con las filas de al segunda tabla (y) que se correspondan según la llave en común.

Esquema del resultado del left join

Ejemplo de una unión de tablas en R

Para unir dos tablas en R, usamos la función left_join() de {dplyr}.

library(dplyr)

Primero creemos una tabla de base con datos de ejemplo.

frutas_x <- tibble(fruta = c("pera", "manzana", "uva"),
                   color = c("verde", "roja", "morada"))
fruta color
pera verde
manzana roja
uva morada

En esa tabla tenemos tres observaciones que corresponden a animales, descritos en la primera columna, y una segunda columna con características de los mismos.

Ahora creemos una segunda tabla, que además de tener la misma columna que describe las frutas, agrega una nueva variable sobre las frutitas 🍐🍎🍇

frutas_y <- tibble(fruta = c("pera", "manzana", "uva"),
                   sabor = c("deliciosa", "buena", "ricolina"))
fruta sabor
pera deliciosa
manzana buena
uva ricolina

Dado que ambas tablas comparten la variable fruta, si hacemos un left join ambas tablas se cruzarán en base a esta variable, resultando en una tabla nueva:

frutas_2 <- left_join(frutas_x, frutas_y)
Joining with `by = join_by(fruta)`
fruta color sabor
pera verde deliciosa
manzana roja buena
uva morada ricolina

El resultado de la unión es una nueva tabla que tiene las tres variables únicas obtenidas del cruce de las dos tablas distintas. En este caso, el left join nos permite agregar información sobre una misma unidad de observación proveniente de distintas fuentes.

Otro ejemplo

Veamos un segundo ejemplo con más filas y más columnas, ésta vez sobre animalitos 🐈🐀🐕

animales_x <- tibble(animal = c("gato", "ratón", "perro", "pez"),
                     color = c("gris", "negro", "blanco", "azul"),
                     tamaño = c(34, 16, 50, 3))
animal color tamaño
gato gris 34
ratón negro 16
perro blanco 50
pez azul 3

La primera tabla contiene los nombres de animales (identificador único), sus colores y sus medidas. La segunda tabla también contiene nombres, pero agrega su cantidad de patas1 y sus edades.

animales_y <- tibble(animal = c("perro", "gato", "pez"),
                     patas = c(4, 3, 0),
                     edad = c(8, 3, 1))
animal patas edad
perro 4 8
gato 3 3
pez 0 1

Las dos tablas tienen distinta cantidad de observaciones, y además las observaciones clave (columna animal) que se usarán como llave de unión están desordenadas.

Cuando los data frames tienen distinta cantidad de filas, el orden en que hacemos la unión es importante: en un left join la primera tabla (o izquierda) es la tabla principal, a la cual se le agregan las columnas de una segunda tabla, en base a las coincidencias de la columna clave. Por lo tanto, si unimos o cruzamos las tablas poniendo primero la tabla más grande y después la más pequeña, obtendremos casos perdidos por las filas de la primera tabla que no obtuvieron coincidencias en la segunda.

animales_3 <- left_join(animales_x, animales_y)
Joining with `by = join_by(animal)`
animal color tamaño patas edad
gato gris 34 3 3
ratón negro 16 NA NA
perro blanco 50 4 8
pez azul 3 0 1

Como podemos ver, obtenemos celdas con NA en la observación ratón, debido a que en la segunda tabla (animales_y) no habían datos sobre este animalito. Una pena 😔

También sería una opción hacer el cruce al revés, poniendo primero la tabla animales_y (3 filas) y después animales_x (4 filas), con el objetivo de que las observaciones de la tabla animales_x complementen las observaciones de animales_y donde hayan coincidencias, y descartando los casos que no tienen en común:

animales_3 <- left_join(animales_y, animales_x)
Joining with `by = join_by(animal)`
animal patas edad color tamaño
perro 4 8 blanco 50
gato 3 3 gris 34
pez 0 1 azul 3

Ahora no tenemos datos perdidos, porque si bien animales_x tenía más observaciones que animales_y, animales_y contenía todas las observaciones de animales_x identificadas por la variable animal, lo que podemos confirmar comparando las diferencias entre ambas columnas con la función waldo::compare():

library(waldo)

compare(sort(animales_x$animal), 
        sort(animales_y$animal))
`old`: "gato" "perro" "pez" "ratón"
`new`: "gato" "perro" "pez"        

Caso licencias falsas

Un caso icónico de uso de left join fue el estudio realizado por la Contraloría General de la República de Chile, donde se cruzaron bases de datos que tenían en común la posibilidad de identificar funcionarios públicos:

Se trata de un estudio a partir del cruce de información de las salidas del país registradas por la Policía de Investigaciones (PDI), la base de funcionarios públicos y las licencias médicas que se otorgaron entre el 2023 y 2024. (Fuente: Bío Bío)

La hipótesis sería que una persona que sale del país durante su licencia médica sería probablemente una persona que consiguió una licencia falsa para tomarse vacaciones 🏖️☀️

Simulemos lo que podría haber hecho la Contraloría para detectar estos casos. Asumimos que contaron con (al menos) tres bases de datos: una de funcionarios públicos, una de licencias médicas, y otra de viajes al extranjero, las tres teniendo en común el RUN (código de identificación único de ciudadanos chilenos) para poder cruzar las personas.

options(scipen = 9999)

funcionarios <- tibble(run = c(10000001, 10000002, 10000003),
                       nombre = c("maría", "pepito", "juanito"),
                       ministerio = c("defensa", "economía", "hacienda"))
run nombre ministerio
10000001 maría defensa
10000002 pepito economía
10000003 juanito hacienda

Tenemos identificados tres funcionarios públicos de distintos servicios.

Luego tenemos una base de datos con licencias médicas de trabajadores que pueden o no ser funcionarios públicos. Con la base de los RUN de funcionarios públicos podemos identificar si las licencias corresponden a funcionarios públicos y no a trabajadores del sector privado.

licencias <- tibble(run = c(10000001, 10000002, 10000003, 10000004),
                    licencia = c(FALSE, FALSE, TRUE, TRUE),
                    licencia_inicio = c(NA, "2024-04-10", "2024-02-04", "2010-09-18"),
                    licencia_fin = c(NA, "2024-04-13", "2024-02-18", "2030-12-31"))
run licencia licencia_inicio licencia_fin
10000001 FALSE NA NA
10000002 FALSE 2024-04-10 2024-04-13
10000003 TRUE 2024-02-04 2024-02-18
10000004 TRUE 2010-09-18 2030-12-31

Lo importante de esta tabla es que tenemos una fecha de inicio y una fecha de fin de la licencia médica.

Finalmente tenemos la información de salidas del país de distintas personas, que pueden o no ser funcionarios públicos, y que pueden o no haber estado con licencia médica 🤔

viajes <- tibble(run = c(10000005, 10000001, 10000002, 10000003, 10000008),
                 viaje_destino = c("Bolivia", "Perú", "Argentina", "Italia", "España"),
                 viaje_fecha = c("2021-01-06", "2021-02-15", "2023-06-23", "2024-02-09", "2025-08-17")
)
run viaje_destino viaje_fecha
10000005 Bolivia 2021-01-06
10000001 Perú 2021-02-15
10000002 Argentina 2023-06-23
10000003 Italia 2024-02-09
10000008 España 2025-08-17

Ahora que tenemos datos simulados, usaremos {dplyr} para trabajar con los datos y encontrar respuestas.

Si necesitas aprender lo básico del manejo de datos con R, revisa este tutorial básico de {dplyr}!

Lo primero sería filtrar las licencias médicas para que solamente correspondan con funcionarios públicos (también podría hacerse con left_join() pero creo que es más pertinente un filtro)

licencias_f <- licencias |> 
  # sólo funcionarios públicos
  filter(run %in% funcionarios$run)

Luego, cruzamos los datos de licencias de funcionarios públicos con el registro de salidas del país:

# cruzar con viajes
cruce <- licencias_f |> 
  left_join(viajes, join_by(run))

Finalmente revisamos si los viajes fueron durante el tiempo de licencia médica, y si los viajes fueron fuera del país. Podemos hacer esto con un filtro, o preferentemente creando una columna nueva (irregular) que indique si se cumple o no la evaluación.

# revisar si viajaron fuera del país durante licencia
resultado <- cruce |>
  # crear una nueva variable
  mutate(irregular = 
           licencia == TRUE & # personas on licencia
           viaje_destino != "Chile" & # viajes fuera de Chile
           between(viaje_fecha, 
                   licencia_inicio, licencia_fin) # viaje durante el tiempo de licencia
  ) |> 
  select(-viaje_destino)
run licencia licencia_inicio licencia_fin viaje_fecha irregular
10000001 FALSE NA NA 2021-02-15 FALSE
10000002 FALSE 2024-04-10 2024-04-13 2023-06-23 FALSE
10000003 TRUE 2024-02-04 2024-02-18 2024-02-09 TRUE

⚠️ Detectamos un caso de funcionario público que viajó fuera del país durante su licencia médica! La última columna marca TRUE si se trata de un caso irregular.

Conclusión

Podemos usar left_join() para completar los datos sobre nuestra unidad de análisis si la información viene diseminada en distintas tablas o archivos. Pero también podemos utilizarla para complementar datos desde distintas fuentes, aumentando la información que tenemos sobre las observaciones que estemos estudiando, o bien, para realizar cruces de información que nos entreguen coincidencias relevantes.

¿Necesitas aprender R para análisis de datos desde cero? Inscríbete a mi curso!

¿Necesitas aprender R para análisis de datos desde cero? Inscríbete a mi curso!


  1. el gatito lamentablemente sufrió un accidente y perdió una patita trasera 😿 ↩︎

Fecha de publicación:
August 16, 2025
Extensión:
8 minute read, 1548 words
Categorías:
tutoriales
Tags:
procesamiento de datos limpieza de datos
Ver también:
Echa un vistazo preliminar a tus datos con {visdat}
Crea planillas de Excel con formato personalizado desde R con {openxlsx}
Validación básica de datos con R