-
Notifications
You must be signed in to change notification settings - Fork 12
/
13-relational-data.Rmd
509 lines (397 loc) · 14.8 KB
/
13-relational-data.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
# Datos relacionales
```{r, warning=FALSE, message=FALSE, include=FALSE}
library(tidyverse)
library(datos)
```
## 13.2 Datos sobre vuelos {-#vuelos-relacionales}
### 13.2.1 Ejercicios{-#ejercicios-1321}
1. Imagina que necesitas dibujar (aproximadamente) la ruta que cada avión vuela
desde su origen hasta el destino. ¿Qué variables necesitas? ¿Qué tablas
necesitas combinar?
<div class="solucion">
<h3>Solución</h3>
Necesitas combinar `aeropuertos` con `vuelos` ya que el dataset `aeropuertos`
contiene las coordenadas de los aeropuertos. Puedes unir las tablas por medio
de la variable `codigo_aeropuerto` en `aeropuertos` y `origen` y `destino` en
`vuelos`.
```{r}
```
</div>
2. Olvidamos incluir la relación entre `clima` y `aeropuertos`. ¿Cuál es la
relación y cómo debe aparecer en el diagrama?
<div class="solucion">
<h3>Solución</h3>
De manera similar al ejercicio anterior, se pueden unir mediante
`codigo_aeropuerto` en `aeropuertos` y `origen` en `clima`.
</div>
3. `clima` únicamente contiene información de los aeropuertos de origen
(Nueva York). Si contuviera registros para todos los aeropuertos de EEUU, ¿Qué
relación tendría con `vuelos`?
<div class="solucion">
<h3>Solución</h3>
Puedes conectar `clima` con `vuelos` usando la columna `destino` e incluir el
clima de los aeropuertos de EEUU que están presentes en la tabla `vuelos`.
</div>
4. Sabemos que hay días "especiales" en el año y pocas personas vuelan esos
días. ¿Cómo se representarían en un data frame? ¿Cuáles serían las claves
primarias de esa tabla? ¿Cómo se conectaría con las tablas existentes?
<div class="solucion">
<h3>Solución</h3>
Una posibilidad es contar con un dataset de los días festivos en EEUU indicando
mes y día. Esta información se puede unir con cada vuelo en la tabla `vuelos` y
y a la vez con el dataset `clima`.
</div>
## 13.3 Claves{-#claves}
### 13.3.1 Ejercicios{-#ejercicios-1331}
1. Agrega una clave subrogada a `vuelos`.
<div class="solucion">
<h3>Solución</h3>
```{r}
vuelos %>%
mutate(id = row_number(anio)) %>%
select(id, everything())
```
</div>
2. Identifica las claves en los siguientes conjuntos de datos
1. `datos::bateadores`
1. `datos::nombres`
1. `datos::atmosfera`
1. `datos::vehiculos`
1. `datos::diamantes`
(Puede que necesites leer un poco de documentación.)
<div class="solucion">
<h3>Solución</h3>
1. En `datos::bateadores` corresponde a `id_jugador`.
1. En `datos::nombres` corresponde a la combinación de `anio` y `nombre`,
con esto se puede unir cada par año-nombre con las otras tablas.
1. En `datos::atmosfera` corresponde a latitud`, `longitud`, `anio` y `mes`,
lo cual identifica de manera única un lugar en el tiempo.
1. En `datos::vehiculos` corresponde a `id`.
1. En `datos::diamantes` no hay claves ya que estas tienen sentido en datos
relacionales, es decir cuando existen otras tablas para combinar información.
</div>
2. Dibuja un diagrama que ilustre las conexiones entre las tablas `bateadores`,
`personas` y `salarios` en el paquete datos. Dibuja otro diagrama que muestre la
relación entre `personas`, `dirigentes` y `premios_dirigentes`.
¿Cómo caracterizarías las relación entre `bateadores`, `lanzadores` y `jardineros`?
<div class="solucion">
<h3>Solución</h3>
Es directo. Las tres tablas contienen los campos `id_jugador` y `anio` y cada
tabla contiene información que complementa las demás. La relación es uno a uno.
</div>
## 13.4 Uniones de transformación {#mutating-joins}
### 13.4.6 Ejercicios{-#ejercicios-1346}
1. Calcula el atraso promedio por destino, luego une los datos en `aeropuertos`
para que puedas mostrar la distribución espacial de los atrasos. Te presentamos
una forma fácil de dibujar un mapa de los Estados Unidos:
```{r, eval = FALSE}
aeropuertos %>%
semi_join(vuelos, c("codigo_aeropuerto" = "destino")) %>%
ggplot(aes(longitud, latitud)) +
borders("state") +
geom_point() +
coord_quickmap()
```
(No te preocupes si no entiendes que hace `semi_join()`.
Lo aprenderás a continuación.)
Quizás quieras usar `size` o `colour` para editar los puntos y mostrar
el atraso promedio de cada aeropuerto.
<div class="solucion">
<h3>Solución</h3>
```{r}
atraso_promedio_destino <- vuelos %>%
group_by(destino) %>%
# los vuelos con NA en atraso_llegada son vuelos cancelados
summarise(atraso = mean(atraso_llegada, na.rm = TRUE)) %>%
inner_join(aeropuertos, by = c(destino = "codigo_aeropuerto"))
```
```{r}
atraso_promedio_destino %>%
ggplot(aes(longitud, latitud, colour = atraso)) +
borders("state") +
geom_point() +
coord_quickmap()
```
</div>
2. Agrega la ubicación de origen _y_ destino (e.g. `latitud` y `longitud`)
a `vuelos`.
<div class="solucion">
<h3>Solución</h3>
Es posible realizar varias uniones. Si hay variables duplicadas, dplyr va a
distinguirlas agregando `.x` y `.y` al nombre de la variable para resolver
los nombres duplicados.
```{r}
ubicacion_aeropuertos <- aeropuertos %>%
select(codigo_aeropuerto, latitud, longitud)
vuelos %>%
select(anio:dia, hora, origen, destino) %>%
left_join(
ubicacion_aeropuertos,
by = c("origen" = "codigo_aeropuerto")
) %>%
left_join(
ubicacion_aeropuertos,
by = c("destino" = "codigo_aeropuerto")
)
```
Es una buena práctica tener nombres indicativos para las variables. Usaremos
el sufijo `_destino` y `_origen` para especificar a qué aeropuerto nos referimos.
```{r}
vuelos %>%
select(anio:dia, hora, origen, destino) %>%
left_join(
ubicacion_aeropuertos,
by = c("origen" = "codigo_aeropuerto")
) %>%
left_join(
ubicacion_aeropuertos,
by = c("destino" = "codigo_aeropuerto"),
suffix = c("_origen", "_destino")
)
```
</div>
3. ¿Existe una relación entre la antiguedad de un avión y sus atrasos?
<div class="solucion">
<h3>Solución</h3>
Ya que no se indica si se refiere a atrasos de salida o llegada, se explorará
el atraso en la salida, quedando el otro caso como ejercicio.
Para comparar la antiguedad de un avión con sus atrasos, hay que unir
`vuelos` con `aviones`, esta última tabla contiene la variable `anio` que se
refiere al año de fabricación del avión.
Dado que hay pocos aviones de más de 25 años, truncaremos los datos y luego
vamos a calcular el promedio de llegada y salida dada la antiguedad.
```{r}
atrasos_por_antiguedad <- inner_join(vuelos,
select(aviones, codigo_cola, anio_fabricacion = anio), by = "codigo_cola") %>%
mutate(antiguedad = anio - anio_fabricacion) %>%
filter(!is.na(antiguedad)) %>%
mutate(antiguedad = if_else(antiguedad > 25, 25L, antiguedad)) %>%
group_by(antiguedad) %>%
summarise(
prom_atraso_salida = mean(atraso_salida, na.rm = TRUE),
desv_est_atraso_salida = sd(atraso_salida, na.rm = TRUE),
nro_vuelos_atrasados_salida = sum(!is.na(atraso_salida))
)
```
Ahora podemos explorar la reglación entre los atrasos en la salida y la
antiguedad.
El atraso en la salida es creciente en relación a la antiguedad para los
aviones de hasta de 10 años. Luego este atraso decae.
La reducción de los atrasos en la salida en relación a la antiguedad puede
deberse a que en los aviones más antiguos se planfica la mantención para evitar
tales atrasos y desperfectos mecánicos.
```{r}
ggplot(atrasos_por_antiguedad, aes(x = antiguedad, y = prom_atraso_salida)) +
geom_point() +
scale_x_continuous("Antiguedad del avión (años)", breaks = seq(0, 30, by = 10)) +
scale_y_continuous("Atraso promedio en la salida (minutos)")
```
</div>
4. ¿Qué condiciones climáticas hacen más probables los atrasos?
<div class="solucion">
<h3>Solución</h3>
Las lluvias están asociadas con los atrasos. Sin embargo, para un nivel
mayor a 0.02 pulgadas de lluvia no hay una tendencia fuerte.
```{r}
vuelo_clima <- vuelos %>%
inner_join(clima, by = c(
"origen",
"anio",
"mes",
"dia",
"hora"
))
vuelo_clima %>%
group_by(precipitacion) %>%
summarise(atraso = mean(atraso_salida, na.rm = TRUE)) %>%
ggplot(aes(x = precipitacion, y = atraso)) +
geom_line() +
geom_point()
```
</div>
5. ¿Qué sucedió el día 13 de junio de 2013? Muestra el patrón espacial de los atrasos,
luego usa un buscador para encontrar referencias cruzadas con el clima.
```{r, eval = FALSE, include = FALSE}
peores <- filter(vuelos, !is.na(horario_salida), mes == 6, dia == 13)
peores %>%
group_by(destino) %>%
summarise(atraso = mean(atraso_llegada), n = n()) %>%
filter(n > 5) %>%
inner_join(aeropuertos, by = c("destino" = "codigo_aeropuerto")) %>%
ggplot(aes(longitud, latitud)) +
borders("state") +
geom_point(aes(size = n, colour = atraso)) +
coord_quickmap()
```
<div class="solucion">
<h3>Solución</h3>
Hubo una serie de tormentas en el sureste de los EEUU (consulta la [Wikipedia](https://en.wikipedia.org/wiki/June_12%E2%80%9313,_2013_derecho_series)).
El siguiente gráfico muestra que los mayores atrasos se presentaron en
Tennessee (Nashville), el sureste y medio oeste es donde ocurrieron las
tormentas.
```{r}
vuelos %>%
filter(anio == 2013, mes == 6, dia == 13) %>%
group_by(destino) %>%
summarise(atraso = mean(atraso_salida, na.rm = TRUE)) %>%
inner_join(aeropuertos, by = c("destino" = "codigo_aeropuerto")) %>%
ggplot(aes(y = latitud, x = longitud, size = atraso, colour = atraso)) +
borders("state") +
geom_point() +
coord_quickmap() +
scale_colour_viridis_c()
```
</div>
## 13.5 Uniones de filtro {#filtering-joins}
### 13.5.1 Ejercicios{-#ejercicios-1351}
1. ¿Qué significa que un vuelo no tenga `codigo_cola`? ¿Qué tienen en común los códigos
de cola que no tienen registros coincidentes en `aviones`? (Pista: Una variable explica
~90% de los problemas.)
<div class="solucion">
<h3>Solución</h3>
Los vuelos que no registran código cola tampoco registran hora de llegada, por
lo que son vuelos cancelados.
```{r}
vuelos %>%
filter(is.na(codigo_cola), !is.na(horario_llegada)) %>%
nrow()
```
Muchos de los vuelos sin código cola en `aviones` pertenecen a
American Airlines (AA) o Envoy Airlines (EQ) como se detalla en la documentación.
```{r}
vuelos %>%
anti_join(aviones, by = "codigo_cola") %>%
count(aerolinea, sort = TRUE) %>%
mutate(p = n / sum(n))
```
Sin embargo, no todos los códigos que aparecen en `vuelos` están perdidos en
`aviones`.
```{r}
vuelos %>%
distinct(aerolinea, codigo_cola) %>%
left_join(aviones, by = "codigo_cola") %>%
group_by(aerolinea) %>%
summarise(total_aviones = n(),
faltan_en_aviones = sum(is.na(modelo))) %>%
mutate(porcentaje_perdidos = faltan_en_aviones / total_aviones) %>%
arrange(desc(porcentaje_perdidos))
```
</div>
2. Filtra los vuelos para mostrar únicamente los aviones que han realizado al menos cien
viajes.
<div class="solucion">
<h3>Solución</h3>
Debemos calcular que aviones tienen 100 o más vuelos. Hay que filtrar los
aviones sin código cola o estos se van a considerar como un único avión.
```{r}
cien_vuelos <- vuelos %>%
filter(!is.na(codigo_cola)) %>%
group_by(codigo_cola) %>%
count() %>%
filter(n >= 100)
```
Ahora se puede unir el resultado con la tabla `vuelos` y así conservar los que
cumplen con el criterio.
```{r}
vuelos %>%
semi_join(cien_vuelos, by = "codigo_cola")
```
Otra posibilidad es agrupar y luego usar `mutate()`.
```{r}
vuelos %>%
filter(!is.na(codigo_cola)) %>%
group_by(codigo_cola) %>%
mutate(n = n()) %>%
filter(n >= 100)
```
</div>
3. Combina `vehiculos` y `comunes` para encontrar los registros de los
modelos más comunes.
<div class="solucion">
<h3>Solución</h3>
Debemos unir por fabricante y modelo, a modo de evitar hacer un match
incorrecto debido a que dos fabricantes tengan un vehículo con el mismo
nombre.
```{r}
vehiculos %>%
semi_join(comunes, by = c("fabricante", "modelo"))
```
</div>
4. Encuentra las 48 horas (en el transcurso del año) que tengan los peores atrasos. Haz
una referencia cruzada con la tabla `clima`. ¿Puedes observar patrones?
<div class="solucion">
<h3>Solución</h3>
Haremos el desarrollo considerando las horas con mayor acumulación de atrasos en
la salida. El otro caso queda como ejercicio.
El ejercicio no pide que sean los dos peores días, sino las peores 48 horas,
por lo que debemos tomar las peores horas en el transcurso de varios días.
```{r}
peores_horas <- vuelos %>%
mutate(hora = salida_programada %/% 100) %>%
group_by(origen, anio, mes, dia, hora) %>%
summarise(atraso_salida = mean(atraso_salida, na.rm = TRUE)) %>%
ungroup() %>%
arrange(desc(atraso_salida)) %>%
slice(1:48)
```
Este resultado se debe unir con la tabla `clima`.
```{r}
clima_peores_horas <- semi_join(clima, peores_horas,
by = c("origen", "anio", "mes", "dia", "hora"))
```
Para el clima, nos enfocaremos en la precipitación, velocidad del viento y
temperatura. Muchas de estas observaciones tienen una velocidad del viento
por sobre el promedio (10 millas por hora) o lluvias.
```{r}
select(clima_peores_horas, temperatura, velocidad_viento, precipitacion) %>%
print(n = 48)
```
```{r}
ggplot(clima_peores_horas, aes(x = precipitacion, y = velocidad_viento, color = temperatura)) +
geom_point()
```
Para extenderse con mayor detalle en ese ejercicio, es necesario usar las
herramientas del capítulo Análisis Exploratorio de Datos.
</div>
5. ¿Qué te indica `anti_join(vuelos, aeropuertos, by = c("destino" = "codigo_aeropuerto"))`?
¿Qué te indica `anti_join(aeropuertos, vuelos, by = c("codigo_aeropuerto" = "destino"))`?
<div class="solucion">
<h3>Solución</h3>
La primera expresión entrega los vuelos cuyo destino es un aeropuerto fuera
de los EEUU.
La segunda expresión entrega lo aeropuertos de los EEUU que no son el destino
de los vuelos contenidos en los datos.
Los datos contienen todos los vuelos de los aeropuertos de Nueva York, por
lo que también contiene los vuelos con escalas intermedias.
</div>
6. Puedes esperar que exista una relación implícita entre aviones y aerolíneas, dado que cada
avión es operado por una única aerolínea. Confirma o descarta esta hipótesis usando las
herramientas que aprendiste más arriba.
<div class="solucion">
<h3>Solución</h3>
Veamos las combinaciones únicas de aerolínea y avión.
```{r}
aerolinea_avion <- vuelos %>%
filter(!is.na(codigo_cola)) %>%
distinct(aerolinea, codigo_cola)
```
Podría darse el caso en que una aerolínea vende algunos de sus aviones a otra.
Estos aviones tendrán una cuenta mayor a uno en la tabla anterior.
```{r}
aerolinea_avion %>%
count(codigo_cola) %>%
filter(n > 1) %>%
nrow()
```
Veamos ahora las transferencias de aviones entre aerolíneas.
```{r carrier_transfer_tbl}
aviones_transferidos <- aerolinea_avion %>%
# conservo los aviones que han volado para más de una aerolínea
group_by(codigo_cola) %>%
filter(n() > 1) %>%
# uno los códigos con los nombres de aerolínea
left_join(aerolineas, by = "aerolinea") %>%
arrange(aerolinea, codigo_cola)
aviones_transferidos
```
</div>