Apunte 4 — Uniendo bases de datos

Analítica de Personas · Semestre otoño 2026 · Semana 2 · Prof. René Gempp

1. ¿Por qué unir tablas?

En people analytics, los datos casi nunca vienen en una sola tabla. El HRIS tiene una tabla de empleados, otra de evaluaciones de desempeño, otra de entrevistas de salida, otra de encuestas. Para responder preguntas de negocio, necesitas combinar estas tablas usando una columna en común (una clave).

En nuestro caso de InnovaCo:

innovaco_empleados.csv (1.200 filas, todos los empleados)
→ Columna clave: id_empleado

innovaco_salidas.csv (326 filas, solo los que se fueron)
→ Columna clave: id_empleado

Queremos: una tabla con todos los empleados + la información de salida para los que se fueron.

Las funciones de unión (joins) de dplyr resuelven exactamente este problema. La idea es simple: "buscar coincidencias" entre dos tablas por una columna compartida.

2. left_join(): el join que más usarás

left_join() toma todas las filas de la tabla izquierda y les agrega columnas de la tabla derecha donde coincida la clave. Si no hay coincidencia, rellena con NA.

# Sintaxis básica
datos <- tabla_izquierda |>
  left_join(tabla_derecha, by = "columna_clave")

# Ejemplo concreto de InnovaCo
datos <- innovaco |>
  left_join(salidas, by = "id_empleado")

¿Qué pasa paso a paso?

innovaco (izquierda, 1.200 filas)
id_empleadoedad...
INN-000130...
INN-000235...
INN-000342...
INN-000425...
───▶
──✗
──✗
───▶
salidas (derecha, 326 filas)
id_empleadotipo_salida
INN-0001Voluntaria
INN-0004Voluntaria
▼ Resultado
Resultado (1.200 filas — se conservan todas las de la izquierda)
id_empleadoedad...tipo_salida
INN-000130...Voluntaria
INN-000235...NA
INN-000342...NA
INN-000425...Voluntaria

INN-0002 e INN-0003 no se fueron, así que no están en salidas. left_join() los mantiene y rellena con NA las columnas nuevas.

¿Por qué "left"? Porque preserva todas las filas de la tabla de la izquierda (la primera que nombras). Es la operación más común en people analytics: "quiero mi tabla completa de empleados, enriquecida con datos de otra fuente".

3. Claves de unión: el argumento by

Caso simple: misma columna en ambas tablas

# Cuando la clave se llama igual en ambas tablas
datos <- innovaco |>
  left_join(salidas, by = "id_empleado")

Caso con nombres distintos

# Si en una tabla la clave se llama "id" y en otra "id_empleado"
datos <- tabla_a |>
  left_join(tabla_b, by = c("id_empleado" = "id"))
# Izquierda = derecha

Clave compuesta (más de una columna)

# Cuando necesitas cruzar por dos columnas a la vez
# Ejemplo: encuesta por empleado Y por período
datos <- empleados |>
  left_join(encuestas, by = c("id_empleado", "periodo"))
¿Qué pasa si no pones by? R intentará unir por todas las columnas que tengan el mismo nombre en ambas tablas. Esto puede producir resultados inesperados si hay columnas con nombres coincidentes que no son la clave. Siempre especifica by explícitamente.

4. Los otros tipos de join

left_join() es el que usarás el 90% del tiempo, pero existen otros cuatro tipos. La diferencia es qué filas conservan cuando no hay coincidencia:

FunciónConservaUso típico en RRHH
left_join(A, B) Todas las filas de A. Si no hay match en B, rellena con NA. Enriquecer la tabla de empleados con datos de otra fuente
right_join(A, B) Todas las filas de B. Si no hay match en A, rellena con NA. Rara vez. Es un left_join con las tablas al revés.
inner_join(A, B) Solo filas que existen en ambas tablas. Cuando solo quieres empleados que se fueron Y tienen entrevista de salida
full_join(A, B) Todas las filas de ambas tablas. NA donde no hay match. Combinar dos fuentes donde ninguna es "la completa"
anti_join(A, B) Filas de A que NO están en B. ¿Quiénes se fueron y NO tuvieron entrevista de salida?
# inner_join: solo empleados que se fueron (326 filas)
solo_salidas <- innovaco |>
  inner_join(salidas, by = "id_empleado")

nrow(solo_salidas)  # 326

# anti_join: empleados que NO se fueron (874 filas)
activos <- innovaco |>
  anti_join(salidas, by = "id_empleado")

nrow(activos)       # 874
Regla práctica para elegir ¿Quieres conservar a todos los empleados, incluso si no tienen datos en la otra tabla? → left_join(). ¿Quieres solo los que tienen datos en ambas? → inner_join(). ¿Quieres saber quién NO está en la otra tabla? → anti_join().

5. Verificar el resultado de un join

Siempre verifica después de un join. Los tres chequeos esenciales:

# 1. ¿Cuántas filas tiene el resultado?
nrow(datos)  # Debería ser 1200 con left_join

# 2. ¿Hay duplicados? (filas más que las esperadas)
datos |>
  count(id_empleado) |>
  filter(n > 1)  # Si hay filas aquí, algo salió mal

# 3. ¿Los NA están donde esperamos?
datos |>
  count(rotacion, tipo_salida)
# Los que NO se fueron deberían tener NA en tipo_salida
Peligro: filas duplicadas después del join Si después de un left_join() tienes más filas de las que empezaste, es porque la tabla derecha tiene duplicados en la clave. Por ejemplo, si un empleado tiene 3 registros de encuesta, el join creará 3 filas para ese empleado. Verifica siempre con nrow().

6. bind_rows(): apilar tablas

A veces no necesitas cruzar tablas por una clave, sino simplemente apilar una debajo de otra (cuando tienen las mismas columnas). Esto es bind_rows():

# Ejemplo: juntar datos de dos oficinas
datos_stgo <- read_csv("oficina_santiago.csv")
datos_valpo <- read_csv("oficina_valparaiso.csv")

todos <- bind_rows(datos_stgo, datos_valpo)
# Si una tabla tiene una columna que la otra no tiene,
# bind_rows() rellena con NA. No da error.

left_join()

Agrega columnas de otra tabla, cruzando por una clave.

A |> left_join(B, by = "id")
# A tiene 5 cols → resultado 8 cols

bind_rows()

Agrega filas de otra tabla (misma estructura).

bind_rows(A, B)
# A tiene 100 filas, B tiene 50
# → resultado 150 filas

7. Resumen: ¿qué función necesito?

Quiero...FunciónEjemplo
Agregar columnas de otra tabla, conservando todos los empleadosleft_join()Empleados + datos de salida
Solo filas que existen en ambas tablasinner_join()Solo empleados que se fueron Y tienen encuesta
Filas de A que NO están en Banti_join()Empleados activos (sin salida registrada)
Apilar tablas con la misma estructurabind_rows()Datos de varias oficinas en una sola tabla

8. Errores frecuentes

ErrorCausaSolución
Error: `by` must be supplied No especificaste la columna de unión Agrega by = "id_empleado"
El resultado tiene más filas de las esperadas La tabla derecha tiene duplicados en la clave Verifica con tabla_b |> count(clave) |> filter(n > 1)
NA en columnas que no deberían tenerlos La clave no coincide (diferencias de mayúsculas, espacios, formato) Compara las claves: setdiff(tabla_a$id, tabla_b$id)
Columnas duplicadas con sufijo .x y .y Ambas tablas tienen una columna con el mismo nombre (que no es la clave) Renombra antes del join, o usa suffix = c("_emp", "_sal")