R
Tutorial R: joins en r para combinación y relaciones de tablas
Aprende a usar inner, outer, semi y anti joins en R con dplyr para combinar y filtrar tablas eficientemente en análisis de datos.
Aprende R y certifícateInner y outer joins en dplyr
Cuando trabajamos con datos en R, es común necesitar combinar información de diferentes tablas o dataframes. El paquete dplyr nos ofrece funciones específicas para realizar estas operaciones de forma sencilla y eficiente, permitiéndonos relacionar datos a través de columnas comunes.
Los joins o uniones son operaciones que nos permiten conectar tablas basándonos en valores coincidentes en columnas específicas. Estas operaciones son fundamentales cuando trabajamos con datos que están distribuidos en múltiples tablas, como suele ocurrir en bases de datos relacionales.
Inner join: intersección de datos
El inner join es la operación más básica y devuelve únicamente las filas que tienen coincidencias en ambas tablas. Usando la función inner_join()
de dplyr, podemos combinar dos dataframes incluyendo solo los registros que existen en ambas tablas.
Veamos un ejemplo sencillo con dos dataframes:
# Cargamos la librería dplyr
library(dplyr)
# Creamos dos dataframes de ejemplo
clientes <- tibble(
id_cliente = c(1, 2, 3, 4, 5),
nombre = c("Ana", "Benito", "Carmen", "David", "Elena"),
ciudad = c("Madrid", "Barcelona", "Sevilla", "Valencia", "Bilbao")
)
pedidos <- tibble(
id_pedido = c(101, 102, 103, 104, 105),
id_cliente = c(1, 3, 3, 6, 7),
producto = c("Laptop", "Móvil", "Tablet", "Monitor", "Teclado"),
precio = c(850, 300, 200, 150, 25)
)
# Realizamos un inner join
clientes_con_pedidos <- inner_join(clientes, pedidos, by = "id_cliente")
# Visualizamos el resultado
clientes_con_pedidos
El resultado mostrará solo los clientes que han realizado pedidos (ids 1 y 3), excluyendo a los clientes sin pedidos y los pedidos de clientes que no están en nuestra tabla de clientes:
# A tibble: 3 × 6
id_cliente nombre ciudad id_pedido producto precio
<dbl> <chr> <chr> <dbl> <chr> <dbl>
1 1 Ana Madrid 101 Laptop 850
2 3 Carmen Sevilla 102 Móvil 300
3 3 Carmen Sevilla 103 Tablet 200
Outer joins: incluyendo datos no coincidentes
A diferencia del inner join, los outer joins nos permiten conservar filas que no tienen coincidencias en la otra tabla. Dplyr ofrece tres tipos de outer joins:
Left join: mantiene todas las filas de la tabla izquierda
El left_join()
conserva todas las filas de la primera tabla (izquierda) y añade la información de la segunda tabla cuando hay coincidencias:
# Realizamos un left join
todos_clientes_con_pedidos <- left_join(clientes, pedidos, by = "id_cliente")
# Visualizamos el resultado
todos_clientes_con_pedidos
El resultado incluirá a todos los clientes, incluso aquellos sin pedidos (con valores NA en las columnas de pedidos):
# A tibble: 7 × 6
id_cliente nombre ciudad id_pedido producto precio
<dbl> <chr> <chr> <dbl> <chr> <dbl>
1 1 Ana Madrid 101 Laptop 850
2 2 Benito Barcelona NA NA NA
3 3 Carmen Sevilla 102 Móvil 300
4 3 Carmen Sevilla 103 Tablet 200
5 4 David Valencia NA NA NA
6 5 Elena Bilbao NA NA NA
Right join: mantiene todas las filas de la tabla derecha
El right_join()
funciona de manera similar al left join, pero conserva todas las filas de la segunda tabla (derecha):
# Realizamos un right join
pedidos_con_clientes <- right_join(clientes, pedidos, by = "id_cliente")
# Visualizamos el resultado
pedidos_con_clientes
Este resultado incluirá todos los pedidos, incluso aquellos de clientes que no están en nuestra tabla de clientes:
# A tibble: 5 × 6
id_cliente nombre ciudad id_pedido producto precio
<dbl> <chr> <chr> <dbl> <chr> <dbl>
1 1 Ana Madrid 101 Laptop 850
2 3 Carmen Sevilla 102 Móvil 300
3 3 Carmen Sevilla 103 Tablet 200
4 6 NA NA 104 Monitor 150
5 7 NA NA 105 Teclado 25
Full join: mantiene todas las filas de ambas tablas
El full_join()
es la unión más inclusiva, ya que conserva todas las filas de ambas tablas, independientemente de si tienen coincidencias o no:
# Realizamos un full join
todos_datos_combinados <- full_join(clientes, pedidos, by = "id_cliente")
# Visualizamos el resultado
todos_datos_combinados
El resultado incluirá todos los clientes y todos los pedidos:
# A tibble: 9 × 6
id_cliente nombre ciudad id_pedido producto precio
<dbl> <chr> <chr> <dbl> <chr> <dbl>
1 1 Ana Madrid 101 Laptop 850
2 2 Benito Barcelona NA NA NA
3 3 Carmen Sevilla 102 Móvil 300
4 3 Carmen Sevilla 103 Tablet 200
5 4 David Valencia NA NA NA
6 5 Elena Bilbao NA NA NA
7 6 NA NA 104 Monitor 150
8 7 NA NA 105 Teclado 25
Especificando columnas de unión
Cuando las columnas que queremos usar para unir las tablas tienen nombres diferentes, podemos especificarlas usando un vector con nombres:
# Creamos un dataframe con nombre de columna diferente
ventas <- tibble(
id_venta = c(201, 202, 203),
cliente_id = c(1, 3, 5), # Nombre diferente para la misma información
fecha = c("2023-01-15", "2023-01-20", "2023-01-25")
)
# Unimos especificando la relación entre columnas
clientes_ventas <- inner_join(clientes, ventas, by = c("id_cliente" = "cliente_id"))
# Visualizamos el resultado
clientes_ventas
El resultado mostrará los clientes que tienen ventas asociadas:
# A tibble: 3 × 5
id_cliente nombre ciudad id_venta fecha
<dbl> <chr> <chr> <dbl> <chr>
1 1 Ana Madrid 201 2023-01-15
2 3 Carmen Sevilla 202 2023-01-20
3 5 Elena Bilbao 203 2023-01-25
Uniendo por múltiples columnas
También podemos unir tablas basándonos en coincidencias en múltiples columnas:
# Creamos dataframes con múltiples columnas para unir
empleados <- tibble(
departamento = c("Ventas", "Ventas", "IT", "Marketing", "IT"),
id_empleado = c(101, 102, 103, 104, 105),
nombre = c("Laura", "Carlos", "Marta", "Javier", "Sofía")
)
proyectos <- tibble(
departamento = c("Ventas", "IT", "IT", "RRHH", "Marketing"),
id_empleado = c(101, 103, 106, 107, 104),
proyecto = c("CRM", "Web", "App", "Selección", "Campaña")
)
# Unimos por departamento e id_empleado
asignaciones <- inner_join(empleados, proyectos,
by = c("departamento", "id_empleado"))
# Visualizamos el resultado
asignaciones
El resultado mostrará solo los empleados que están asignados a proyectos en su mismo departamento:
# A tibble: 3 × 4
departamento id_empleado nombre proyecto
<chr> <dbl> <chr> <chr>
1 Ventas 101 Laura CRM
2 IT 103 Marta Web
3 Marketing 104 Javier Campaña
Casos de uso prácticos
Los joins son especialmente útiles en análisis de datos reales. Por ejemplo:
- Combinar información demográfica de clientes con su historial de compras
- Relacionar datos de ventas con información de productos
- Unir registros de empleados con datos de rendimiento
# Ejemplo: Análisis de ventas por región
regiones <- tibble(
id_region = c(1, 2, 3),
nombre_region = c("Norte", "Centro", "Sur"),
responsable = c("María", "Pedro", "Lucía")
)
tiendas <- tibble(
id_tienda = c(10, 11, 12, 13, 14),
nombre_tienda = c("Tienda A", "Tienda B", "Tienda C", "Tienda D", "Tienda E"),
id_region = c(1, 1, 2, 3, 4)
)
ventas_mensuales <- tibble(
id_tienda = c(10, 11, 12, 13, 15),
mes = c("Enero", "Enero", "Enero", "Enero", "Enero"),
ventas = c(15000, 12000, 18000, 9000, 7500)
)
# Análisis completo con múltiples joins
analisis_ventas <- tiendas %>%
left_join(regiones, by = "id_region") %>%
inner_join(ventas_mensuales, by = "id_tienda")
# Visualizamos el resultado
analisis_ventas
Este análisis nos permitirá ver las ventas por tienda junto con la información de la región a la que pertenece:
# A tibble: 4 × 7
id_tienda nombre_tienda id_region nombre_region responsable mes ventas
<dbl> <chr> <dbl> <chr> <chr> <chr> <dbl>
1 10 Tienda A 1 Norte María Enero 15000
2 11 Tienda B 1 Norte María Enero 12000
3 12 Tienda C 2 Centro Pedro Enero 18000
4 13 Tienda D 3 Sur Lucía Enero 9000
Los joins en dplyr son herramientas fundamentales para el análisis de datos relacionales en R, permitiéndonos combinar información de diferentes fuentes de manera eficiente y flexible según nuestras necesidades específicas.
Semi-joins y anti-joins para filtrado
Además de los inner y outer joins que vimos anteriormente, dplyr ofrece dos tipos especiales de joins que son extremadamente útiles para filtrar datos: los semi-joins y los anti-joins. A diferencia de los joins tradicionales, estos no combinan columnas de ambas tablas, sino que se utilizan principalmente para filtrar filas basándose en la existencia (o ausencia) de coincidencias en otra tabla.
Semi-join: filtrar filas que tienen coincidencias
Un semi-join (semi_join()
) mantiene las filas de la primera tabla que tienen al menos una coincidencia en la segunda tabla, pero a diferencia del inner join, no añade ninguna columna de la segunda tabla. Es como decir "dame todas las filas de la tabla A que tienen alguna coincidencia en la tabla B".
Veamos un ejemplo práctico:
# Cargamos la librería necesaria
library(dplyr)
# Creamos dos dataframes de ejemplo
productos <- tibble(
id_producto = c(101, 102, 103, 104, 105),
nombre = c("Laptop", "Tablet", "Smartphone", "Monitor", "Teclado"),
categoria = c("Informática", "Móviles", "Móviles", "Periféricos", "Periféricos")
)
ventas_2023 <- tibble(
id_venta = c(1, 2, 3, 4),
id_producto = c(101, 103, 103, 106),
cantidad = c(2, 1, 3, 1)
)
# Aplicamos un semi-join para encontrar productos que se han vendido
productos_vendidos <- semi_join(productos, ventas_2023, by = "id_producto")
# Visualizamos el resultado
productos_vendidos
El resultado mostrará solo los productos que aparecen en la tabla de ventas:
# A tibble: 2 × 3
id_producto nombre categoria
<dbl> <chr> <chr>
1 101 Laptop Informática
2 103 Smartphone Móviles
Observa que el resultado mantiene solo las columnas de la tabla productos, pero filtra las filas para mostrar únicamente aquellos productos que tienen al menos una venta registrada.
Anti-join: filtrar filas que no tienen coincidencias
Por otro lado, un anti-join (anti_join()
) hace exactamente lo contrario: mantiene las filas de la primera tabla que no tienen coincidencias en la segunda tabla. Es como preguntar "dame todas las filas de la tabla A que no aparecen en la tabla B".
Continuando con nuestro ejemplo:
# Aplicamos un anti-join para encontrar productos sin ventas
productos_sin_ventas <- anti_join(productos, ventas_2023, by = "id_producto")
# Visualizamos el resultado
productos_sin_ventas
El resultado mostrará los productos que no aparecen en la tabla de ventas:
# A tibble: 3 × 3
id_producto nombre categoria
<dbl> <chr> <chr>
1 102 Tablet Móviles
2 104 Monitor Periféricos
3 105 Teclado Periféricos
Este resultado nos muestra los productos que no han tenido ninguna venta registrada, lo cual podría ser útil para identificar inventario estancado o productos que necesitan promoción.
Casos de uso prácticos
Los semi-joins y anti-joins son herramientas poderosas para análisis de datos en situaciones específicas:
Identificación de registros faltantes o inconsistentes
# Creamos dataframes de ejemplo
estudiantes <- tibble(
id_estudiante = c(1, 2, 3, 4, 5),
nombre = c("Ana", "Bruno", "Carmen", "Daniel", "Elena"),
carrera = c("Informática", "Matemáticas", "Física", "Química", "Biología")
)
examenes <- tibble(
id_examen = c(101, 102, 103, 104),
id_estudiante = c(1, 2, 5, 6),
asignatura = c("Programación", "Álgebra", "Genética", "Estadística"),
calificacion = c(8.5, 7.2, 9.0, 6.8)
)
# Estudiantes que no han realizado ningún examen
estudiantes_sin_examenes <- anti_join(estudiantes, examenes, by = "id_estudiante")
# Exámenes de estudiantes que no están en nuestra base de datos
examenes_sin_estudiante <- anti_join(examenes, estudiantes, by = "id_estudiante")
# Visualizamos los resultados
estudiantes_sin_examenes
examenes_sin_estudiante
Estos resultados nos permitirían identificar:
- Estudiantes que no han realizado exámenes (Carmen y Daniel)
- Exámenes registrados para estudiantes que no están en nuestra base de datos (id_estudiante = 6)
Filtrado eficiente de datos
Los semi-joins y anti-joins son más eficientes en memoria que los joins completos cuando solo necesitamos filtrar datos, ya que no duplican información:
# Creamos dataframes de ejemplo
clientes <- tibble(
id_cliente = c(1, 2, 3, 4, 5),
nombre = c("María", "Pedro", "Lucía", "Jorge", "Sara"),
ciudad = c("Madrid", "Barcelona", "Valencia", "Sevilla", "Bilbao")
)
clientes_vip <- tibble(
id_cliente = c(1, 3, 6),
fecha_alta_vip = c("2022-01-15", "2022-03-20", "2022-06-10")
)
# Filtramos para obtener solo los clientes VIP
solo_clientes_vip <- semi_join(clientes, clientes_vip, by = "id_cliente")
# Filtramos para obtener los clientes que no son VIP
clientes_no_vip <- anti_join(clientes, clientes_vip, by = "id_cliente")
# Visualizamos los resultados
solo_clientes_vip
clientes_no_vip
Este enfoque es más limpio que usar un left_join seguido de un filtro, especialmente cuando trabajamos con grandes volúmenes de datos.
Combinando semi-joins y anti-joins con otras operaciones
Estos joins se pueden combinar con otras operaciones de dplyr para crear flujos de análisis más complejos:
# Creamos dataframes de ejemplo
productos <- tibble(
id_producto = c(101, 102, 103, 104, 105),
nombre = c("Laptop", "Tablet", "Smartphone", "Monitor", "Teclado"),
precio = c(1200, 400, 600, 250, 80),
categoria = c("Informática", "Móviles", "Móviles", "Periféricos", "Periféricos")
)
ventas <- tibble(
id_venta = c(1, 2, 3, 4, 5),
id_producto = c(101, 103, 103, 102, 105),
fecha = c("2023-01-15", "2023-01-20", "2023-02-05", "2023-02-10", "2023-03-01"),
cantidad = c(1, 2, 1, 3, 2)
)
# Productos vendidos más de una vez
productos_populares <- ventas %>%
group_by(id_producto) %>%
summarise(total_vendido = sum(cantidad)) %>%
filter(total_vendido > 1) %>%
semi_join(productos, by = "id_producto")
# Productos caros que no se han vendido
productos_caros_sin_ventas <- productos %>%
filter(precio > 300) %>%
anti_join(ventas, by = "id_producto")
# Visualizamos los resultados
productos_populares
productos_caros_sin_ventas
Diferencias clave con otros tipos de joins
Es importante entender las diferencias fundamentales entre estos joins y los que vimos anteriormente:
Semi-join vs Inner join: El semi-join solo devuelve columnas de la primera tabla, mientras que el inner join combina columnas de ambas tablas.
Anti-join vs Left join con filtro: El anti-join es más eficiente y claro que hacer un left join y luego filtrar los NA.
Propósito principal: Los semi-joins y anti-joins están diseñados específicamente para filtrar datos, no para combinarlos.
Veamos una comparación visual con un ejemplo sencillo:
# Comparación entre diferentes tipos de joins
empleados <- tibble(
id = c(1, 2, 3, 4),
nombre = c("Ana", "Berto", "Carmen", "David")
)
proyectos <- tibble(
id_proyecto = c(101, 102, 103),
id_empleado = c(1, 2, 5),
proyecto = c("Web", "App", "Base de datos")
)
# Diferentes tipos de joins
inner <- inner_join(empleados, proyectos, by = c("id" = "id_empleado"))
left <- left_join(empleados, proyectos, by = c("id" = "id_empleado"))
semi <- semi_join(empleados, proyectos, by = c("id" = "id_empleado"))
anti <- anti_join(empleados, proyectos, by = c("id" = "id_empleado"))
# Visualizamos los resultados
inner # Ana y Berto con sus proyectos
left # Todos los empleados, Carmen y David con NA en proyectos
semi # Solo Ana y Berto, sin información de proyectos
anti # Solo Carmen y David
Consejos prácticos para usar semi-joins y anti-joins
Usa semi-joins cuando necesites filtrar registros que existen en otra tabla sin necesitar los datos adicionales.
Utiliza anti-joins para identificar excepciones o registros que faltan entre conjuntos de datos.
Estos joins son más eficientes que sus equivalentes con inner_join o left_join seguidos de filtros, especialmente con grandes conjuntos de datos.
Recuerda que estos joins no añaden columnas de la segunda tabla, solo filtran filas de la primera.
# Ejemplo de eficiencia: Encontrar clientes con compras recientes
# Enfoque con semi-join (más eficiente)
clientes_activos <- semi_join(clientes,
filter(compras, fecha > "2023-01-01"),
by = "id_cliente")
# Enfoque alternativo menos eficiente
clientes_activos_alt <- clientes %>%
left_join(compras, by = "id_cliente") %>%
filter(fecha > "2023-01-01") %>%
select(id_cliente, nombre, ciudad) %>%
distinct()
Los semi-joins y anti-joins son herramientas de filtrado especializado que complementan perfectamente a los inner y outer joins, permitiéndote realizar operaciones de filtrado basadas en relaciones entre tablas de manera clara y eficiente.
Otros ejercicios de programación de R
Evalúa tus conocimientos de esta lección joins en r para combinación y relaciones de tablas con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.
Todas las lecciones de R
Accede a todas las lecciones de R y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.
Instalación De R Y Rstudio
Introducción Y Entorno
Introducción A R
Introducción Y Entorno
Operadores
Sintaxis
Estructuras De Datos
Sintaxis
Funciones
Sintaxis
Estructuras De Control Iterativo
Sintaxis
Scopes Y Closures
Sintaxis
Estructuras De Control Condicional
Sintaxis
Funciones Anónimas
Sintaxis
Tipos De Datos Y Variables
Sintaxis
Sistema R6: Clases Referenciales Y Encapsulamiento
Programación Orientada A Objetos
Sistema S4: Clases Formales Y Validación
Programación Orientada A Objetos
Herencia Y Polimorfismo En R
Programación Orientada A Objetos
Sistemas De Oop En R
Programación Orientada A Objetos
Sistema S3: Clases Implícitas Y Métodos Genéricos
Programación Orientada A Objetos
Tidyverse Para Transformación De Datos
Manipulación De Datos
Lubridate Para Fechas Y Tiempo
Manipulación De Datos
Group_by Y Summarize Para Agrupación Y Resumen
Manipulación De Datos
Stringr Para Expresiones Regulares
Manipulación De Datos
Tidyr Para Limpieza De Valores Faltantes
Manipulación De Datos
Joins En R Para Combinación Y Relaciones De Tablas
Manipulación De Datos
Pivot_longer Y Pivot_wider Para Reestructuración
Manipulación De Datos
Mutate Y Transmute Para Transformación
Manipulación De Datos
Dplyr Para Filtrado Y Selección
Manipulación De Datos
Readr Y Read.csv Para Importar Datos
Manipulación De Datos
Gráficos Bivariantes En R
Visualización De Datos
Gráficos Univariantes En R
Visualización De Datos
Facetas En Ggplot2
Visualización De Datos
Personalización Y Temas
Visualización De Datos
Ggplot2 Para Visualización De Datos
Visualización De Datos
Gráficos Multivariantes En R
Visualización De Datos
Correlación En R
Estadística
Regresión Lineal En R
Estadística
Pruebas De Hipótesis En R
Estadística
Anova En R
Estadística
Estadística Descriptiva En R
Estadística
En esta lección
Objetivos de aprendizaje de esta lección
- Comprender qué son los joins y su utilidad para combinar tablas en R.
- Aprender a usar inner_join, left_join, right_join y full_join para diferentes tipos de combinaciones.
- Saber especificar columnas de unión cuando tienen nombres diferentes y unir por múltiples columnas.
- Entender el uso de semi_join y anti_join para filtrar filas basándose en coincidencias o ausencia de ellas.
- Aplicar joins en casos prácticos de análisis de datos para combinar y filtrar información eficientemente.