Capítulo20 Datos Relacionados
## [1] "2026-09-09"
El tema proviene de los siguientes sitios.
English: https://r4ds.had.co.nz/relational-data.html
Español: https://es.r4ds.hadley.nz/13-relational-data.html
20.1 Temas: Datos Relacionados
- Qué es una clave: primaria, foránea y sustituta
- Cómo se comprueba que una clave lo es de verdad
- Uniones de transformación (mutating joins):
left_join(),inner_join(),right_join(),full_join() - Uniones de filtro (filtering joins):
semi_join(),anti_join() - Definir las columnas clave con
by - Los tres problemas que arruinan una unión
20.2 Por qué hace falta más de una tabla
Hasta ahora cada análisis cabía en una tabla. En un proyecto real casi nunca es
así: los datos llegan repartidos en varias, y hay que juntarlos. Y eso está bien
hecho, no es un descuido. Si en vuelos guardáramos el nombre completo de la
aerolínea en cada fila, escribiríamos “United Air Lines Inc.” 336 776 veces,
y el día que hubiera que corregir una letra habría que corregirla en todas.
La solución es guardar cada cosa una sola vez, en su propia tabla, y conectarlas por una columna común. A un conjunto de tablas conectadas así se le llama datos relacionados, y es como funcionan todas las bases de datos del mundo.
En este capítulo trabajamos con cinco tablas del paquete datos, que juntas
describen los vuelos que salieron de Nueva York en 2013:
vueloses la tabla central: una fila por vuelo.aerolineastraduce el código de dos letras al nombre completo de la compañía.aeropuertosda el nombre, la latitud y la longitud de cada aeropuerto.avionesdescribe cada avión: año de fabricación, modelo, número de asientos.climada las condiciones del tiempo en cada aeropuerto de origen, hora por hora.
Y se conectan así:
vuelos$aerolineaapunta aaerolineas$aerolineavuelos$codigo_colaapunta aaviones$codigo_colavuelos$origenyvuelos$destinoapuntan aaeropuertos$codigo_aeropuertovuelosse conecta conclimapor cinco columnas a la vez:anio,mes,dia,horayorigen
Antes de escribir una sola línea de código, dibuja en papel las tablas y las flechas entre ellas. Los errores de unión casi siempre vienen de no tener claro cuál columna apunta a cuál.
Mira las cinco tablas antes de unir nada. Fíjate sobre todo en qué columnas comparten:
## # A tibble: 336,776 × 19
## anio mes dia horario_salida salida_programada atraso_salida
## <int> <int> <int> <int> <int> <dbl>
## 1 2013 1 1 517 515 2
## 2 2013 1 1 533 529 4
## 3 2013 1 1 542 540 2
## 4 2013 1 1 544 545 -1
## 5 2013 1 1 554 600 -6
## 6 2013 1 1 554 558 -4
## 7 2013 1 1 555 600 -5
## 8 2013 1 1 557 600 -3
## 9 2013 1 1 557 600 -3
## 10 2013 1 1 558 600 -2
## # ℹ 336,766 more rows
## # ℹ 13 more variables: horario_llegada <int>, llegada_programada <int>,
## # atraso_llegada <dbl>, aerolinea <chr>, vuelo <int>, codigo_cola <chr>,
## # origen <chr>, destino <chr>, tiempo_vuelo <dbl>, distancia <dbl>,
## # hora <dbl>, minuto <dbl>, fecha_hora <dttm>
## [1] "anio" "mes" "dia"
## [4] "horario_salida" "salida_programada" "atraso_salida"
## [7] "horario_llegada" "llegada_programada" "atraso_llegada"
## [10] "aerolinea" "vuelo" "codigo_cola"
## [13] "origen" "destino" "tiempo_vuelo"
## [16] "distancia" "hora" "minuto"
## [19] "fecha_hora"
## # A tibble: 16 × 2
## aerolinea nombre
## <chr> <chr>
## 1 9E Endeavor Air Inc.
## 2 AA American Airlines Inc.
## 3 AS Alaska Airlines Inc.
## 4 B6 JetBlue Airways
## 5 DL Delta Air Lines Inc.
## 6 EV ExpressJet Airlines Inc.
## 7 F9 Frontier Airlines Inc.
## 8 FL AirTran Airways Corporation
## 9 HA Hawaiian Airlines Inc.
## 10 MQ Envoy Air
## 11 OO SkyWest Airlines Inc.
## 12 UA United Air Lines Inc.
## 13 US US Airways Inc.
## 14 VX Virgin America
## 15 WN Southwest Airlines Co.
## 16 YV Mesa Airlines Inc.
## [1] "aerolinea" "nombre"
## # A tibble: 1,458 × 8
## codigo_aeropuerto nombre latitud longitud altura zona_horaria horario_verano
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 04G Lansdo… 41.1 -80.6 1044 -5 A
## 2 06A Moton … 32.5 -85.7 264 -6 A
## 3 06C Schaum… 42.0 -88.1 801 -6 A
## 4 06N Randal… 41.4 -74.4 523 -5 A
## 5 09J Jekyll… 31.1 -81.4 11 -5 A
## 6 0A9 Elizab… 36.4 -82.2 1593 -5 A
## 7 0G6 Willia… 41.5 -84.5 730 -5 A
## 8 0G7 Finger… 42.9 -76.8 492 -5 A
## 9 0P2 Shoest… 39.8 -76.6 1000 -5 U
## 10 0S9 Jeffer… 48.1 -123. 108 -8 A
## # ℹ 1,448 more rows
## # ℹ 1 more variable: zona_horaria_iana <chr>
## [1] "codigo_aeropuerto" "nombre" "latitud"
## [4] "longitud" "altura" "zona_horaria"
## [7] "horario_verano" "zona_horaria_iana"
## # A tibble: 3,322 × 9
## codigo_cola anio tipo fabricante modelo motores asientos velocidad
## <chr> <int> <chr> <chr> <chr> <int> <int> <int>
## 1 N10156 2004 Ala fija mult… EMBRAER EMB-1… 2 55 NA
## 2 N102UW 1998 Ala fija mult… AIRBUS IN… A320-… 2 182 NA
## 3 N103US 1999 Ala fija mult… AIRBUS IN… A320-… 2 182 NA
## 4 N104UW 1999 Ala fija mult… AIRBUS IN… A320-… 2 182 NA
## 5 N10575 2002 Ala fija mult… EMBRAER EMB-1… 2 55 NA
## 6 N105UW 1999 Ala fija mult… AIRBUS IN… A320-… 2 182 NA
## 7 N107US 1999 Ala fija mult… AIRBUS IN… A320-… 2 182 NA
## 8 N108UW 1999 Ala fija mult… AIRBUS IN… A320-… 2 182 NA
## 9 N109UW 1999 Ala fija mult… AIRBUS IN… A320-… 2 182 NA
## 10 N110UW 1999 Ala fija mult… AIRBUS IN… A320-… 2 182 NA
## # ℹ 3,312 more rows
## # ℹ 1 more variable: tipo_motor <chr>
## # A tibble: 26,115 × 15
## origen anio mes dia hora temperatura punto_rocio humedad
## <chr> <int> <int> <int> <int> <dbl> <dbl> <dbl>
## 1 EWR 2013 1 1 1 39.0 26.1 59.4
## 2 EWR 2013 1 1 2 39.0 27.0 61.6
## 3 EWR 2013 1 1 3 39.0 28.0 64.4
## 4 EWR 2013 1 1 4 39.9 28.0 62.2
## 5 EWR 2013 1 1 5 39.0 28.0 64.4
## 6 EWR 2013 1 1 6 37.9 28.0 67.2
## 7 EWR 2013 1 1 7 39.0 28.0 64.4
## 8 EWR 2013 1 1 8 39.9 28.0 62.2
## 9 EWR 2013 1 1 9 39.9 28.0 62.2
## 10 EWR 2013 1 1 10 41 28.0 59.6
## # ℹ 26,105 more rows
## # ℹ 7 more variables: direccion_viento <dbl>, velocidad_viento <dbl>,
## # velocidad_rafaga <dbl>, precipitacion <dbl>, presion <dbl>,
## # visibilidad <dbl>, fecha_hora <dttm>
## # A tibble: 336,776 × 19
## anio mes dia horario_salida salida_programada atraso_salida
## <int> <int> <int> <int> <int> <dbl>
## 1 2013 1 1 517 515 2
## 2 2013 1 1 533 529 4
## 3 2013 1 1 542 540 2
## 4 2013 1 1 544 545 -1
## 5 2013 1 1 554 600 -6
## 6 2013 1 1 554 558 -4
## 7 2013 1 1 555 600 -5
## 8 2013 1 1 557 600 -3
## 9 2013 1 1 557 600 -3
## 10 2013 1 1 558 600 -2
## # ℹ 336,766 more rows
## # ℹ 13 more variables: horario_llegada <int>, llegada_programada <int>,
## # atraso_llegada <dbl>, aerolinea <chr>, vuelo <int>, codigo_cola <chr>,
## # origen <chr>, destino <chr>, tiempo_vuelo <dbl>, distancia <dbl>,
## # hora <dbl>, minuto <dbl>, fecha_hora <dttm>
## # A tibble: 3,322 × 9
## codigo_cola anio tipo fabricante modelo motores asientos velocidad
## <chr> <int> <chr> <chr> <chr> <int> <int> <int>
## 1 N10156 2004 Ala fija mult… EMBRAER EMB-1… 2 55 NA
## 2 N102UW 1998 Ala fija mult… AIRBUS IN… A320-… 2 182 NA
## 3 N103US 1999 Ala fija mult… AIRBUS IN… A320-… 2 182 NA
## 4 N104UW 1999 Ala fija mult… AIRBUS IN… A320-… 2 182 NA
## 5 N10575 2002 Ala fija mult… EMBRAER EMB-1… 2 55 NA
## 6 N105UW 1999 Ala fija mult… AIRBUS IN… A320-… 2 182 NA
## 7 N107US 1999 Ala fija mult… AIRBUS IN… A320-… 2 182 NA
## 8 N108UW 1999 Ala fija mult… AIRBUS IN… A320-… 2 182 NA
## 9 N109UW 1999 Ala fija mult… AIRBUS IN… A320-… 2 182 NA
## 10 N110UW 1999 Ala fija mult… AIRBUS IN… A320-… 2 182 NA
## # ℹ 3,312 more rows
## # ℹ 1 more variable: tipo_motor <chr>
## # A tibble: 0 × 2
## # ℹ 2 variables: codigo_cola <chr>, n <int>
20.3 Claves
Una clave es la columna, o el conjunto de columnas, que identifica una observación sin ambigüedad. Hay tres tipos, y conviene distinguirlos:
- Una clave primaria identifica una observación en su propia tabla.
codigo_colaes la clave primaria deaviones: cada avión aparece una sola vez. - Una clave foránea identifica una observación de otra tabla.
codigo_colaenvueloses una clave foránea: ahí se repite miles de veces, una por cada vuelo que hizo ese avión. - Una clave sustituta es la que uno se inventa cuando la tabla no tiene
ninguna, casi siempre un número de fila (
mutate(id = row_number())).
A veces la clave es una sola columna y a veces hacen falta varias. vuelos
no tiene clave primaria: ni el número de vuelo ni la fecha bastan, porque el
mismo vuelo sale todos los días y varios vuelos salen a la misma hora.
20.3.1 Cómo se comprueba una clave
Hay una sola manera, y es la que aparece una y otra vez en los bloques de abajo: contar y quedarse con lo que se repite. Si la columna es de verdad una clave, el resultado tiene que estar vacío.
La receta para verificar una clave: count() seguido de filter(n > 1).
tabla |> count(columna) |> filter(n > 1): si devuelve cero filas, esa columna es una clave.- Con varias columnas:
count(a, b, c) |> filter(n > 1), que comprueba si la combinación es única. - Ojo con los
NA: una columna con valores faltantes no sirve como clave, porque unNAno identifica nada. Compruébalo aparte confilter(is.na(columna)).
Ese filter(n > 1) que devuelve una tabla vacía es una prueba superada, no un
fallo. Si devuelve filas, ahí tienes tus duplicados.
Identify the keys in the following datasets
Lahman::Batting, babynames::babynames nasaweather::atmos fueleconomy::vehicles ggplot2::diamonds
## playerID yearID stint teamID lgID G AB R H X2B X3B HR RBI SB CS BB SO IBB
## 1 aardsda01 2004 1 SFN NL 11 0 0 0 0 0 0 0 0 0 0 0 0
## 2 aardsda01 2006 1 CHN NL 45 2 0 0 0 0 0 0 0 0 0 0 0
## 3 aardsda01 2007 1 CHA AL 25 0 0 0 0 0 0 0 0 0 0 0 0
## 4 aardsda01 2008 1 BOS AL 47 1 0 0 0 0 0 0 0 0 0 1 0
## 5 aardsda01 2009 1 SEA AL 73 0 0 0 0 0 0 0 0 0 0 0 0
## 6 aardsda01 2010 1 SEA AL 53 0 0 0 0 0 0 0 0 0 0 0 0
## HBP SH SF GIDP
## 1 0 0 0 0
## 2 0 1 0 0
## 3 0 0 0 0
## 4 0 0 0 0
## 5 0 0 0 0
## 6 0 0 0 0
## id_jugador id_anio orden_equipos id_equipo id_liga juegos al_bate carreras
## 1 aardsda01 2004 1 SFN NL 11 0 0
## 2 aardsda01 2006 1 CHN NL 45 2 0
## 3 aardsda01 2007 1 CHA AL 25 0 0
## 4 aardsda01 2008 1 BOS AL 47 1 0
## 5 aardsda01 2009 1 SEA AL 73 0 0
## 6 aardsda01 2010 1 SEA AL 53 0 0
## golpes dobles triples cuadrangulares carreras_empujadas bases_robadas
## 1 0 0 0 0 0 0
## 2 0 0 0 0 0 0
## 3 0 0 0 0 0 0
## 4 0 0 0 0 0 0
## 5 0 0 0 0 0 0
## 6 0 0 0 0 0 0
## atrapado_robando base_bolas ponches base_intencional golpeado
## 1 0 0 0 0 0
## 2 0 0 0 0 0
## 3 0 0 0 0 0
## 4 0 0 1 0 0
## 5 0 0 0 0 0
## 6 0 0 0 0 0
## toque_sacrificio elavado_sacrificio doble_matanza
## 1 0 0 0
## 2 1 0 0
## 3 0 0 0
## 4 0 0 0
## 5 0 0 0
## 6 0 0 0
## playerID n
## 1 aardsda01 9
## 2 aaronha01 23
## 3 aaronto01 7
## 4 aasedo01 13
## 5 abadan01 3
## 6 abadfe01 12
## [1] id_jugador id_anio orden_equipos n
## <0 rows> (or 0-length row.names)
## [1] playerID yearID stint n
## <0 rows> (or 0-length row.names)
## # A tibble: 0 × 4
## # ℹ 4 variables: year <dbl>, name <chr>, sex <chr>, n <int>
¿Cuál fue el primer año que su nombre aparece en la base de datos?
## # A tibble: 0 × 5
## # ℹ 5 variables: year <dbl>, sex <chr>, name <chr>, n <int>, prop <dbl>
## [1] 2017
## # A tibble: 41,472 × 11
## lat long year month surftemp temp pressure ozone cloudlow cloudmid
## <dbl> <dbl> <int> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 36.2 -114. 1995 1 273. 272. 835 304 7.5 34.5
## 2 33.7 -114. 1995 1 280. 282. 940 304 11.5 32.5
## 3 31.2 -114. 1995 1 285. 285. 960 298 16.5 26
## 4 28.7 -114. 1995 1 289. 291. 990 276 20.5 14.5
## 5 26.2 -114. 1995 1 292. 293. 1000 274 26 10.5
## 6 23.7 -114. 1995 1 294. 294. 1000 264 30 9.5
## 7 21.2 -114. 1995 1 295 295. 1000 258 29.5 11
## 8 18.7 -114. 1995 1 298. 297. 1000 252 26.5 17.5
## 9 16.2 -114. 1995 1 300. 298. 1000 250 27.5 18.5
## 10 13.7 -114. 1995 1 300. 299. 1000 250 26 16.5
## # ℹ 41,462 more rows
## # ℹ 1 more variable: cloudhigh <dbl>
## # A tibble: 0 × 5
## # ℹ 5 variables: lat <dbl>, long <dbl>, year <int>, month <int>, n <int>
## # A tibble: 33,442 × 12
## id make model year class trans drive cyl displ fuel hwy cty
## <dbl> <chr> <chr> <dbl> <chr> <chr> <chr> <dbl> <dbl> <chr> <dbl> <dbl>
## 1 13309 Acura 2.2CL/3.0CL 1997 Subc… Auto… Fron… 4 2.2 Regu… 26 20
## 2 13310 Acura 2.2CL/3.0CL 1997 Subc… Manu… Fron… 4 2.2 Regu… 28 22
## 3 13311 Acura 2.2CL/3.0CL 1997 Subc… Auto… Fron… 6 3 Regu… 26 18
## 4 14038 Acura 2.3CL/3.0CL 1998 Subc… Auto… Fron… 4 2.3 Regu… 27 19
## 5 14039 Acura 2.3CL/3.0CL 1998 Subc… Manu… Fron… 4 2.3 Regu… 29 21
## 6 14040 Acura 2.3CL/3.0CL 1998 Subc… Auto… Fron… 6 3 Regu… 26 17
## 7 14834 Acura 2.3CL/3.0CL 1999 Subc… Auto… Fron… 4 2.3 Regu… 27 20
## 8 14835 Acura 2.3CL/3.0CL 1999 Subc… Manu… Fron… 4 2.3 Regu… 29 21
## 9 14836 Acura 2.3CL/3.0CL 1999 Subc… Auto… Fron… 6 3 Regu… 26 17
## 10 11789 Acura 2.5TL 1995 Comp… Auto… Fron… 5 2.5 Prem… 23 18
## # ℹ 33,432 more rows
## # A tibble: 0 × 2
## # ℹ 2 variables: id <dbl>, n <int>
## # A tibble: 53,940 × 10
## carat cut color clarity depth table price x y z
## <dbl> <ord> <ord> <ord> <dbl> <dbl> <int> <dbl> <dbl> <dbl>
## 1 0.23 Ideal E SI2 61.5 55 326 3.95 3.98 2.43
## 2 0.21 Premium E SI1 59.8 61 326 3.89 3.84 2.31
## 3 0.23 Good E VS1 56.9 65 327 4.05 4.07 2.31
## 4 0.29 Premium I VS2 62.4 58 334 4.2 4.23 2.63
## 5 0.31 Good J SI2 63.3 58 335 4.34 4.35 2.75
## 6 0.24 Very Good J VVS2 62.8 57 336 3.94 3.96 2.48
## 7 0.24 Very Good I VVS1 62.3 57 336 3.95 3.98 2.47
## 8 0.26 Very Good H SI1 61.9 55 337 4.07 4.11 2.53
## 9 0.22 Fair E VS2 65.1 61 337 3.87 3.78 2.49
## 10 0.23 Very Good H VS1 59.4 61 338 4 4.05 2.39
## # ℹ 53,930 more rows
## # A tibble: 283 × 10
## carat cut color clarity depth price x y z n
## <dbl> <ord> <ord> <ord> <dbl> <int> <dbl> <dbl> <dbl> <int>
## 1 0.23 Very Good E VVS2 60.9 530 3.96 3.99 2.42 2
## 2 0.24 Very Good E VVS1 61.7 485 3.95 3.99 2.45 2
## 3 0.24 Very Good G VVS2 62 449 4 4.03 2.49 2
## 4 0.26 Ideal G SI1 62 394 4.08 4.11 2.54 2
## 5 0.3 Good J VS1 63.4 394 4.23 4.26 2.69 2
## 6 0.3 Very Good D SI1 62.5 552 4.26 4.28 2.67 2
## 7 0.3 Very Good E SI1 62.9 526 4.25 4.3 2.69 2
## 8 0.3 Very Good E VVS2 61.4 789 4.25 4.28 2.62 2
## 9 0.3 Very Good G VS2 63 526 4.29 4.31 2.71 2
## 10 0.3 Very Good H SI1 62.9 421 4.28 4.31 2.7 2
## # ℹ 273 more rows
Draw a diagram illustrating the connections between the Batting, People, and Salaries tables in the Lahman package. Draw another diagram that shows the relationship between People, Managers, AwardsManagers.
Dibuja un diagrama que ilustre las conexiones entre las tablas bateadores, personas y salarios incluidas en el paquete datos. Dibuja otro diagrama que muestre la relación entre personas, dirigentes y premios_dirigentes.
## [1] "playerID" "yearID" "stint" "teamID" "lgID" "G"
## [7] "AB" "R" "H" "X2B" "X3B" "HR"
## [13] "RBI" "SB" "CS" "BB" "SO" "IBB"
## [19] "HBP" "SH" "SF" "GIDP"
## [1] "yearID" "teamID" "lgID" "playerID" "salary"
## [1] "playerID" "birthYear" "birthMonth" "birthDay" "birthCity"
## [6] "birthCountry" "birthState" "deathYear" "deathMonth" "deathDay"
## [11] "deathCountry" "deathState" "deathCity" "nameFirst" "nameLast"
## [16] "nameGiven" "weight" "height" "bats" "throws"
## [21] "debut" "bbrefID" "finalGame" "retroID" "deathDate"
## [26] "birthDate"
20.4 Uniones de transformaciones
Una unión de transformación (mutating join) añade columnas de una tabla a
otra, emparejando las filas por la clave. El nombre viene de que hace lo mismo
que mutate(): la tabla sale con más columnas que entró.
- mutating join
left_join(), inner_join(), full_join(), right_join() (dplyr): combinar tablas.
- Qué hacen: unen dos tablas emparejando filas por una columna clave (
by =). left_join(x, y): conserva todas las filas dex;inner_joinsolo las coincidencias;full_jointodas las de ambas.- De filtro:
semi_join()yanti_join()no añaden columnas, solo filtran filas dex.
vuelos2 <- vuelos %>%
dplyr::select(anio, dia, hora, origen, destino, codigo_cola, aerolinea)
vuelos2## # A tibble: 336,776 × 7
## anio dia hora origen destino codigo_cola aerolinea
## <int> <int> <dbl> <chr> <chr> <chr> <chr>
## 1 2013 1 5 EWR IAH N14228 UA
## 2 2013 1 5 LGA IAH N24211 UA
## 3 2013 1 5 JFK MIA N619AA AA
## 4 2013 1 5 JFK BQN N804JB B6
## 5 2013 1 6 LGA ATL N668DN DL
## 6 2013 1 5 EWR ORD N39463 UA
## 7 2013 1 6 EWR FLL N516JB B6
## 8 2013 1 6 LGA IAD N829AS EV
## 9 2013 1 6 JFK MCO N593JB B6
## 10 2013 1 6 LGA ORD N3ALAA AA
## # ℹ 336,766 more rows
## [1] "aerolinea" "nombre"
## # A tibble: 16 × 2
## aerolinea nombre
## <chr> <chr>
## 1 9E Endeavor Air Inc.
## 2 AA American Airlines Inc.
## 3 AS Alaska Airlines Inc.
## 4 B6 JetBlue Airways
## 5 DL Delta Air Lines Inc.
## 6 EV ExpressJet Airlines Inc.
## 7 F9 Frontier Airlines Inc.
## 8 FL AirTran Airways Corporation
## 9 HA Hawaiian Airlines Inc.
## 10 MQ Envoy Air
## 11 OO SkyWest Airlines Inc.
## 12 UA United Air Lines Inc.
## 13 US US Airways Inc.
## 14 VX Virgin America
## 15 WN Southwest Airlines Co.
## 16 YV Mesa Airlines Inc.
## # A tibble: 336,776 × 6
## anio dia hora codigo_cola aerolinea nombre
## <int> <int> <dbl> <chr> <chr> <chr>
## 1 2013 1 5 N14228 UA United Air Lines Inc.
## 2 2013 1 5 N24211 UA United Air Lines Inc.
## 3 2013 1 5 N619AA AA American Airlines Inc.
## 4 2013 1 5 N804JB B6 JetBlue Airways
## 5 2013 1 6 N668DN DL Delta Air Lines Inc.
## 6 2013 1 5 N39463 UA United Air Lines Inc.
## 7 2013 1 6 N516JB B6 JetBlue Airways
## 8 2013 1 6 N829AS EV ExpressJet Airlines Inc.
## 9 2013 1 6 N593JB B6 JetBlue Airways
## 10 2013 1 6 N3ALAA AA American Airlines Inc.
## # ℹ 336,766 more rows
Ahora vamos a entender las cuatro uniones con dos tablas mínimas, de tres filas
cada una. Fíjate en que la clave 1 y la 2 están en las dos, pero la 3 solo
está en x y la 4 solo está en y. Todo el capítulo se resume en qué le pasa
a esas dos filas sueltas.
x <- tribble(
~key, ~val_x,
1, "x1",
2, "x2",
3, "x3"
)
y <- tribble(
~key, ~val_y,
1, "y1",
2, "y2",
4, "y3"
)
x## # A tibble: 3 × 2
## key val_x
## <dbl> <chr>
## 1 1 x1
## 2 2 x2
## 3 3 x3
## # A tibble: 3 × 2
## key val_y
## <dbl> <chr>
## 1 1 y1
## 2 2 y2
## 3 4 y3
inner_join() se queda solo con lo que coincide. La fila 3 de x y la
fila 4 de y desaparecen, así que el resultado tiene dos filas:
## # A tibble: 2 × 3
## key val_x val_y
## <dbl> <chr> <chr>
## 1 1 x1 y1
## 2 2 x2 y2
inner_join() pierde filas sin avisar. Es la causa número uno de análisis
equivocados con datos relacionados: uno une dos tablas, sigue trabajando, y nunca
se entera de que a mitad de camino se quedó sin la tercera parte de sus datos.
Compara siempre nrow() antes y después de unir.
Las otras tres son uniones exteriores: conservan filas que no tienen pareja y
rellenan con NA lo que falta. Se diferencian solo en cuál tabla es la que manda:
left_join(x, y)conserva todas las filas dex. Es la que se usa el 90 % de las veces, porque casi siempre uno tiene una tabla principal y quiere añadirle información de una tabla de consulta.right_join(x, y)conserva todas las dey. Es lo mismo queleft_join(y, x)con las columnas en otro orden.full_join(x, y)conserva todas las de las dos.
## # A tibble: 3 × 3
## key val_x val_y
## <dbl> <chr> <chr>
## 1 1 x1 y1
## 2 2 x2 y2
## 3 3 x3 <NA>
## # A tibble: 3 × 3
## key val_x val_y
## <dbl> <chr> <chr>
## 1 1 x1 y1
## 2 2 x2 y2
## 3 4 <NA> y3
## # A tibble: 4 × 3
## key val_x val_y
## <dbl> <chr> <chr>
## 1 1 x1 y1
## 2 2 x2 y2
## 3 3 x3 <NA>
## 4 4 <NA> y3
El mismo ejemplo con nombres y edades, que se lee mejor. Fíjate en Orlando, que no tiene edad, y en la persona de 22 años, que no tiene nombre: son la fila 3 y la fila 4 de antes.
x <- tribble(
~key, ~nombre_x,
1, "Juan",
2, "Maria",
3, "Orlando"
)
y <- tribble(
~key, ~edad_y,
1, 20,
2, 21,
4, 22
)
x## # A tibble: 3 × 2
## key nombre_x
## <dbl> <chr>
## 1 1 Juan
## 2 2 Maria
## 3 3 Orlando
## # A tibble: 3 × 2
## key edad_y
## <dbl> <dbl>
## 1 1 20
## 2 2 21
## 3 4 22
## # A tibble: 4 × 3
## key nombre_x edad_y
## <dbl> <chr> <dbl>
## 1 1 Juan 20
## 2 2 Maria 21
## 3 3 Orlando NA
## 4 4 <NA> 22
## # A tibble: 2 × 3
## key nombre_x edad_y
## <dbl> <chr> <dbl>
## 1 1 Juan 20
## 2 2 Maria 21
## # A tibble: 3 × 3
## key nombre_x edad_y
## <dbl> <chr> <dbl>
## 1 1 Juan 20
## 2 2 Maria 21
## 3 3 Orlando NA
## # A tibble: 3 × 3
## key nombre_x edad_y
## <dbl> <chr> <dbl>
## 1 1 Juan 20
## 2 2 Maria 21
## 3 4 <NA> 22
## # A tibble: 4 × 3
## key nombre_x edad_y
## <dbl> <chr> <dbl>
## 1 1 Juan 20
## 2 2 Maria 21
## 3 3 Orlando NA
## 4 4 <NA> 22
## # A tibble: 2 × 3
## key nombre_x edad_y
## <dbl> <chr> <dbl>
## 1 1 Juan 20
## 2 2 Maria 21
20.5 Las uniones con los datos de verdad
Con las tablas de vuelos, la unión típica es exactamente la del principio:
añadirle a vuelos2 el nombre completo de la aerolínea, que vive en otra tabla.
## # A tibble: 336,776 × 6
## anio dia hora codigo_cola aerolinea nombre
## <int> <int> <dbl> <chr> <chr> <chr>
## 1 2013 1 5 N14228 UA United Air Lines Inc.
## 2 2013 1 5 N24211 UA United Air Lines Inc.
## 3 2013 1 5 N619AA AA American Airlines Inc.
## 4 2013 1 5 N804JB B6 JetBlue Airways
## 5 2013 1 6 N668DN DL Delta Air Lines Inc.
## 6 2013 1 5 N39463 UA United Air Lines Inc.
## 7 2013 1 6 N516JB B6 JetBlue Airways
## 8 2013 1 6 N829AS EV ExpressJet Airlines Inc.
## 9 2013 1 6 N593JB B6 JetBlue Airways
## 10 2013 1 6 N3ALAA AA American Airlines Inc.
## # ℹ 336,766 more rows
## [1] "anio" "dia" "hora" "origen" "destino"
## [6] "codigo_cola" "aerolinea"
## [1] "origen" "anio" "mes" "dia"
## [5] "hora" "temperatura" "punto_rocio" "humedad"
## [9] "direccion_viento" "velocidad_viento" "velocidad_rafaga" "precipitacion"
## [13] "presion" "visibilidad" "fecha_hora"
Cuando dos tablas comparten varias columnas con el mismo nombre y no se dice
nada, dplyr las usa todas como clave. Eso se llama unión natural, y es
cómodo pero peligroso: basta con que una de las tablas cambie de columnas para
que la unión cambie de significado sin que nadie lo note. El segundo bloque hace
lo mismo pero diciendo explícitamente cuáles columnas usar, que es lo
recomendable:
## # A tibble: 3,974,448 × 18
## anio dia hora origen destino codigo_cola aerolinea mes temperatura
## <int> <int> <dbl> <chr> <chr> <chr> <chr> <int> <dbl>
## 1 2013 1 5 EWR IAH N14228 UA 1 39.0
## 2 2013 1 5 EWR IAH N14228 UA 2 28.0
## 3 2013 1 5 EWR IAH N14228 UA 3 35.1
## 4 2013 1 5 EWR IAH N14228 UA 4 45.0
## 5 2013 1 5 EWR IAH N14228 UA 5 44.1
## 6 2013 1 5 EWR IAH N14228 UA 6 72.0
## 7 2013 1 5 EWR IAH N14228 UA 7 75.0
## 8 2013 1 5 EWR IAH N14228 UA 8 72.0
## 9 2013 1 5 EWR IAH N14228 UA 9 73.9
## 10 2013 1 5 EWR IAH N14228 UA 10 53.1
## # ℹ 3,974,438 more rows
## # ℹ 9 more variables: punto_rocio <dbl>, humedad <dbl>, direccion_viento <dbl>,
## # velocidad_viento <dbl>, velocidad_rafaga <dbl>, precipitacion <dbl>,
## # presion <dbl>, visibilidad <dbl>, fecha_hora <dttm>
#> Joining, by = c("anio", "mes", "dia", "hora", "origen")
vuelos2 %>%
left_join(clima, by = c("anio", "dia", "hora", "origen"))## # A tibble: 3,974,448 × 18
## anio dia hora origen destino codigo_cola aerolinea mes temperatura
## <int> <int> <dbl> <chr> <chr> <chr> <chr> <int> <dbl>
## 1 2013 1 5 EWR IAH N14228 UA 1 39.0
## 2 2013 1 5 EWR IAH N14228 UA 2 28.0
## 3 2013 1 5 EWR IAH N14228 UA 3 35.1
## 4 2013 1 5 EWR IAH N14228 UA 4 45.0
## 5 2013 1 5 EWR IAH N14228 UA 5 44.1
## 6 2013 1 5 EWR IAH N14228 UA 6 72.0
## 7 2013 1 5 EWR IAH N14228 UA 7 75.0
## 8 2013 1 5 EWR IAH N14228 UA 8 72.0
## 9 2013 1 5 EWR IAH N14228 UA 9 73.9
## 10 2013 1 5 EWR IAH N14228 UA 10 53.1
## # ℹ 3,974,438 more rows
## # ℹ 9 more variables: punto_rocio <dbl>, humedad <dbl>, direccion_viento <dbl>,
## # velocidad_viento <dbl>, velocidad_rafaga <dbl>, precipitacion <dbl>,
## # presion <dbl>, visibilidad <dbl>, fecha_hora <dttm>
Y cuando las columnas se llaman distinto en cada tabla, se dice con
c("nombre_en_x" = "nombre_en_y"). Aquí el aeropuerto de origen se llama
origen en vuelos2 y codigo_aeropuerto en aeropuertos:
## [1] "anio" "dia" "hora" "origen" "destino"
## [6] "codigo_cola" "aerolinea"
## [1] "codigo_aeropuerto" "nombre" "latitud"
## [4] "longitud" "altura" "zona_horaria"
## [7] "horario_verano" "zona_horaria_iana"
## # A tibble: 3 × 7
## anio dia hora origen destino codigo_cola aerolinea
## <int> <int> <dbl> <chr> <chr> <chr> <chr>
## 1 2013 1 5 EWR IAH N14228 UA
## 2 2013 1 5 LGA IAH N24211 UA
## 3 2013 1 5 JFK MIA N619AA AA
## # A tibble: 1,458 × 8
## codigo_aeropuerto nombre latitud longitud altura zona_horaria horario_verano
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 04G Lansdo… 41.1 -80.6 1044 -5 A
## 2 06A Moton … 32.5 -85.7 264 -6 A
## 3 06C Schaum… 42.0 -88.1 801 -6 A
## 4 06N Randal… 41.4 -74.4 523 -5 A
## 5 09J Jekyll… 31.1 -81.4 11 -5 A
## 6 0A9 Elizab… 36.4 -82.2 1593 -5 A
## 7 0G6 Willia… 41.5 -84.5 730 -5 A
## 8 0G7 Finger… 42.9 -76.8 492 -5 A
## 9 0P2 Shoest… 39.8 -76.6 1000 -5 U
## 10 0S9 Jeffer… 48.1 -123. 108 -8 A
## # ℹ 1,448 more rows
## # ℹ 1 more variable: zona_horaria_iana <chr>
## # A tibble: 338,231 × 14
## anio dia hora origen destino codigo_cola aerolinea nombre latitud
## <int> <int> <dbl> <chr> <chr> <chr> <chr> <chr> <dbl>
## 1 2013 1 5 EWR IAH N14228 UA Newark Libert… 40.7
## 2 2013 1 5 LGA IAH N24211 UA La Guardia 40.8
## 3 2013 1 5 JFK MIA N619AA AA John F Kenned… 40.6
## 4 2013 1 5 JFK BQN N804JB B6 John F Kenned… 40.6
## 5 2013 1 6 LGA ATL N668DN DL La Guardia 40.8
## 6 2013 1 5 EWR ORD N39463 UA Newark Libert… 40.7
## 7 2013 1 6 EWR FLL N516JB B6 Newark Libert… 40.7
## 8 2013 1 6 LGA IAD N829AS EV La Guardia 40.8
## 9 2013 1 6 JFK MCO N593JB B6 John F Kenned… 40.6
## 10 2013 1 6 LGA ORD N3ALAA AA La Guardia 40.8
## # ℹ 338,221 more rows
## # ℹ 5 more variables: longitud <dbl>, altura <dbl>, zona_horaria <dbl>,
## # horario_verano <chr>, zona_horaria_iana <chr>
Un ejemplo de para qué sirve todo esto: quedarse solo con los aeropuertos que de
verdad reciben vuelos, y dibujarlos en un mapa. El semi_join() filtra sin
añadir columnas, que es justo lo que hace falta aquí.
library(maps)
aeropuertos %>%
semi_join(vuelos, c("codigo_aeropuerto" = "destino")) %>%
ggplot(aes(longitud, latitud)) +
borders("state") +
geom_point() +
coord_quickmap()
- mutate()
- select()
- left_join()
- match()
20.6 Entendiendo las uniones
Todas las uniones funcionan igual por dentro. Imagina las dos tablas una al lado de la otra: para cada fila de la izquierda, R busca en la derecha las filas cuya clave coincida, y pega las columnas. Lo único que cambia entre las cinco funciones es qué hacer con las filas que no encontraron pareja.
20.6.1 Unión interiores
inner_join() es la unión interior: solo sobrevive lo que aparece en las dos
tablas. Es la más limpia de entender y la más fácil de usar mal, porque el
resultado nunca dice cuántas filas se quedaron por el camino.
Úsala cuando la ausencia de pareja signifique de verdad que esa fila no debe seguir en el análisis, y comprueba siempre cuántas filas perdiste.
20.6.2 Unión exteriores
Las tres uniones exteriores (left_join(), right_join(), full_join())
conservan filas sin pareja y ponen NA en las columnas que no pudieron llenar.
La regla práctica: empieza siempre por left_join(). Si tu tabla principal
tiene 234 filas, después de un left_join() sigue teniendo 234 (salvo por el
problema de la sección siguiente), y los NA que aparezcan te dicen exactamente
qué no encontró pareja. Es la unión que no pierde datos y que además te informa.
Los NA que salen de un left_join() no son un fallo: son el resultado más
informativo de la operación. Cuéntalos con filter(is.na(columna_nueva)) y mira
qué tienen en común. Casi siempre revelan un problema en la tabla de consulta:
una categoría que se te olvidó, un código escrito de dos maneras, un espacio de
más.
20.6.3 Claves duplicadas
Cuando la clave está duplicada en ambas tablas, la unión genera todas las combinaciones posibles (producto cartesiano) y el resultado tendrá más filas de las esperadas. Verifica con count(clave) %>% filter(n > 1) antes de unir.
Conviene distinguir dos situaciones, porque una es normal y la otra es un error.
Duplicada en una sola tabla: normal. Es el caso de vuelos y aerolineas:
la aerolínea UA aparece miles de veces en vuelos y una sola vez en
aerolineas. El resultado tiene tantas filas como vuelos, y el nombre de la
compañía se repite. Es exactamente lo que uno quiere.
Duplicada en las dos tablas: casi siempre un error. Si la clave se repite dos veces a cada lado, esa fila produce cuatro filas en el resultado. La tabla crece sin que nadie lo pida y los promedios que se calculen después estarán mal.
a <- tribble(
~clave, ~valor_a,
1, "a1",
1, "a2"
)
b <- tribble(
~clave, ~valor_b,
1, "b1",
1, "b2"
)
left_join(a, b, by = "clave") # 4 filas, no 2## # A tibble: 4 × 3
## clave valor_a valor_b
## <dbl> <chr> <chr>
## 1 1 a1 b1
## 2 1 a1 b2
## 3 1 a2 b1
## 4 1 a2 b2
El hábito que evita el 90 % de estos problemas: después de cada unión,
comprueba nrow(). Si cambió y no esperabas que cambiara, para y averigua por
qué antes de seguir.
20.7 Definiendo las columnas clave
El argumento by tiene cuatro formas, y vale la pena conocerlas todas:
| Forma | Qué hace |
|---|---|
by = NULL (o no ponerlo) |
Unión natural: usa todas las columnas con el mismo nombre en las dos tablas |
by = "clave" |
Usa solo esa columna |
by = c("a", "b") |
Usa las dos columnas a la vez |
by = c("x" = "y") |
La columna se llama x en la primera tabla y y en la segunda |
La unión natural (by = NULL) es cómoda para explorar y mala idea en un script
que vas a guardar. vuelos y clima comparten anio, mes, dia, hora y
origen, pero también podrían compartir mañana una columna nueva, y entonces la
unión cambiaría de significado sin que tú tocaras nada. En un análisis serio,
escribe siempre el by completo.
20.8 Otras implementaciones
- merge()
merge() es la función de base R que hace lo mismo. Funciona, pero es más lenta,
tiene los argumentos al revés de lo que uno espera, y no distingue con claridad
las cuatro uniones:
| dplyr | merge() de base R |
|---|---|
inner_join(x, y) |
merge(x, y) |
left_join(x, y) |
merge(x, y, all.x = TRUE) |
right_join(x, y) |
merge(x, y, all.y = TRUE) |
full_join(x, y) |
merge(x, y, all = TRUE) |
Los nombres de dplyr dicen lo que hacen; los argumentos de merge() hay que
recordarlos. Si te encuentras un merge() en código ajeno, esta tabla te dice
cuál unión era.
20.9 Uniones de filtro
Las uniones de filtro (semi_join() y anti_join()) nunca añaden columnas nuevas: solo conservan o descartan filas de la tabla de la izquierda según coincidan con la de la derecha.
- semi_join()
- anti_join()
semi_join() y anti_join() (dplyr): filtrar una tabla usando otra.
semi_join(x, y): conserva las filas dexque sí tienen pareja eny.anti_join(x, y): conserva las filas dexque no la tienen.- Ninguna de las dos añade columnas, y ninguna duplica filas aunque la clave esté repetida en
y. Por eso son más seguras que uninner_join()cuando lo único que quieres es filtrar.
De las dos, la que más se usa en la práctica es anti_join(), y no para filtrar
sino para diagnosticar: contesta la pregunta “¿qué hay en mi tabla que no
encontró pareja?”. Es lo primero que hay que correr cuando un left_join()
devuelve más NA de los esperados.
## # A tibble: 10 × 2
## aerolinea n
## <chr> <int>
## 1 MQ 25397
## 2 AA 22558
## 3 UA 1693
## 4 9E 1044
## 5 B6 830
## 6 US 699
## 7 FL 187
## 8 DL 110
## 9 F9 50
## 10 WN 38
Los vuelos que no encontraron su avión no están repartidos al azar entre las
aerolíneas: se concentran en unas pocas. Eso no es un error de R, es un dato
sobre cómo se recogió la información, y es justo el tipo de hallazgo que un
inner_join() habría borrado en silencio.
20.10 Problemas con las uniones
Tres cosas salen mal casi siempre, y las tres se detectan antes de unir:
- La clave no es única. Comprueba las dos tablas con
count(clave) |> filter(n > 1). Si la clave se repite en las dos, la unión va a multiplicar filas. - La clave tiene valores faltantes. Un
NAno empareja con nada, ni siquiera con otroNA. Búscalos confilter(is.na(clave))antes de unir. - La clave está escrita de dos maneras. Es el problema más común y el más
invisible:
"SJU "con un espacio al final no es"SJU","Carolina"no es"CAROLINA", y un código leído como número perdió sus ceros de delante.anti_join()los saca a la luz enseguida.
La rutina completa, en cuatro líneas, antes de cualquier unión seria:
comprobar la clave en la tabla A, comprobarla en la tabla B, correr el
anti_join() en los dos sentidos para ver qué no empareja, y solo entonces unir.
Cuesta un minuto y ahorra tardes enteras.
20.11 Ejercicios del libro R4DS
Hacer los ejercicios de las siguientes secciones del libro en español:
- sección 13.2.1 (los datos de vuelos),
- sección 13.3.1 (claves),
- sección 13.4.6 (uniones de transformación),
- sección 13.5.1 (uniones de filtro).
20.12 Ejercicios del capítulo
Sobre los ejercicios de este capítulo. Cada ejercicio se entrega con tres
cosas: el script, el resultado (que el bloque corra) y una explicación
en palabras. Los ejercicios usan millas y paises del paquete datos, más
una tabla de consulta que vas a escribir tú, no vuelos ni sus tablas
acompañantes, que son las del capítulo. La hoja completa para entregar está en
Ejercicios/Ejercicios_Capitulo_20_datos-relacionados.Rmd.
20.12.1 Ejercicio 1. Encontrar la clave
Datos: paises. Averigua con count() y filter(n > 1) si pais por sí solo
es una clave, y si la combinación de pais y anio lo es.
Verificación: la primera prueba devuelve 142 filas repetidas (una por país,
con n igual a 12); la segunda devuelve una tabla vacía.
En palabras: una tabla vacía es la prueba superada. Explica por qué, y di
cuál es entonces la clave primaria de paises.
20.12.2 Ejercicio 2. Tu propia tabla de consulta
Averigua cuántos fabricantes distintos hay en millas con n_distinct().
Después escribe con tribble() una tabla de consulta llamada origen_fabricante
con dos columnas, fabricante y pais_origen, pero solo para la mitad de los
fabricantes. Únela a millas con left_join().
Verificación: el resultado tiene las mismas 234 filas que millas, y una
columna nueva con NA en las filas de los fabricantes que no pusiste.
En palabras: los NA no son un error aquí. ¿Qué te están diciendo? ¿Por qué
left_join() es la unión correcta para añadir una tabla de consulta?
20.12.3 Ejercicio 3. left_join() frente a inner_join()
Repite la unión del ejercicio anterior con inner_join() y compara nrow() de
los dos resultados.
Verificación: el inner_join() devuelve menos de 234 filas; el
left_join() devuelve exactamente 234.
En palabras: el inner_join() no dio ningún error ni ninguna advertencia.
Explica por qué eso lo hace más peligroso que un error, y cuál costumbre te
protege.
20.12.4 Ejercicio 4. anti_join() para diagnosticar
Usa anti_join() para averiguar cuáles fabricantes de millas no están en tu
tabla de consulta, y cuántos vehículos representan.
Verificación: la lista tiene que coincidir exactamente con los fabricantes que dejaste fuera a propósito, y el número de vehículos tiene que ser igual a la diferencia entre las dos uniones del Ejercicio 3.
En palabras: anti_join() no añade ninguna columna. ¿Para qué sirve
entonces? Describe una situación de tu propio trabajo donde lo usarías.
20.12.5 Ejercicio 5. La clave duplicada
Añade a tu tabla de consulta una segunda fila para un fabricante que ya
estaba, con otro país. Vuelve a hacer el left_join().
Verificación: el resultado tiene más de 234 filas, y los vehículos de ese fabricante aparecen duplicados.
En palabras: ¿cuántas filas de más salieron, y por qué exactamente esa
cantidad? Si después de esta unión calcularas el consumo promedio por clase,
¿estaría mal? Explica en qué sentido.
20.12.6 Ejercicio 6. Cuando las columnas se llaman distinto
Cambia el nombre de la columna de tu tabla de consulta, de fabricante a
marca. Intenta el left_join() sin tocar nada más, en un bloque con
error=TRUE, y después arréglalo con la forma by = c("a" = "b").
Verificación: el intento sin arreglar da error; la versión arreglada da otra vez 234 filas.
En palabras: copia el mensaje de error y explica qué te estaba diciendo. En
by = c("fabricante" = "marca"), ¿cuál de los dos nombres pertenece a cuál
tabla?
20.12.7 Ejercicio 7 (BONO). semi_join() frente a %in%
Quédate con los vehículos de millas cuyo fabricante sí está en tu tabla de
consulta, de dos maneras: con semi_join() y con filter(fabricante %in% ...).
Verificación: las dos dan exactamente la misma tabla, con el mismo número de filas y las mismas 11 columnas.
En palabras: si las dos dan lo mismo, ¿para qué existe semi_join()? Piensa
en qué pasaría si la condición dependiera de dos columnas a la vez, y en qué
pasaría si usaras inner_join() en lugar de semi_join().