library(pacman)
p_load(dplyr, ggplot2, datos)

1 Presentación

El presente documento contiene el solucionario a los ejercicios 5.5.2 del libro de R for Data Science de Hadley Wickham y Garrett Grolemund en su versión en español.

Este documento se realiza con fines académicos para el curso de Técnicas de Exploración de Datos de la carrera de Estadística e Informática de la Universidad Nacional Agraria La Molina de Lima, Perú.

Estos ejercicios corresponden al tema de Funciones de creación útiles.

2 Funciones de creación útiles

Hay muchas funciones para crear nuevas variables que puedes usar con mutate(). La propiedad clave es que la función debe ser vectorizada: debe tomar un vector de valores como input, y devolver un vector con el mismo número de valores como output. No hay forma de enumerar todas las posibles funciones que podrías usar, pero aquí hay una selección de funciones que frecuentemente son útiles:

  • Operadores aritméticos: +, -, *,/,^. Todos están vectorizados usando las llamadas “reglas de reciclaje”. Si un parámetro es más corto que el otro, se extenderá automáticamente para tener la misma longitud. Esto es muy útil cuando uno de los argumentos es un solo número: tiempo_vuelo / 60, horas * 60 + minuto, etc.

    Los operadores aritméticos también son útiles junto con las funciones de agregar que aprenderás más adelante. Por ejemplo, x / sum(x) calcula la proporción de un total, y y - mean(y) calcula la diferencia de la media.

  • Aritmética modular: %/% (división entera) y %% (resto), donde x == y * (x %/% y) + (x %% y). La aritmética modular es una herramienta útil porque te permite dividir enteros en partes. Por ejemplo, en el conjunto de datos de vuelos, puedes calcular hora y minutos de horario_salida con:

transmute(vuelos,
  horario_salida,
  hora = horario_salida %/% 100,
  minuto = horario_salida %% 100
)
## # A tibble: 336,776 × 3
##    horario_salida  hora minuto
##             <int> <dbl>  <dbl>
##  1            517     5     17
##  2            533     5     33
##  3            542     5     42
##  4            544     5     44
##  5            554     5     54
##  6            554     5     54
##  7            555     5     55
##  8            557     5     57
##  9            557     5     57
## 10            558     5     58
## # ℹ 336,766 more rows
  • Logaritmos: log(), log2(), log10(). Los logaritmos son increíblemente útiles como transformación para trabajar con datos con múltiples órdenes de magnitud. También convierten las relaciones multiplicativas en aditivas, una característica que retomaremos en los capítulos sobre modelos.

    En igualdad de condiciones, recomendamos usar log2() porque es más fácil de interpretar: una diferencia de 1 en la escala de registro corresponde a la duplicación de la escala original y una diferencia de -1 corresponde a dividir a la mitad.

  • Rezagos: lead() y lag() te permiten referirte a un valor adelante o un valor atrás (con rezago). Esto te permite calcular las diferencias móviles (por ejemplo, x - lag(x)) o encontrar cuándo cambian los valores (x! = lag (x)). Estos comandos son más útiles cuando se utilizan junto con group_by(), algo que aprenderás en breve.

(x <- 1:10)
##  [1]  1  2  3  4  5  6  7  8  9 10
lag(x)
##  [1] NA  1  2  3  4  5  6  7  8  9
lead(x)
##  [1]  2  3  4  5  6  7  8  9 10 NA
  • Agregados acumulativos y móviles: R proporciona funciones para ejecutar sumas, productos, mínimos y máximos: cumsum(), cumprod(), cummin(), cummax(); dplyr, por su parte, proporciona cummean() para las medias acumuladas. Si necesitas calcular agregados móviles (es decir, una suma calculada en una ventana móvil), prueba el paquete RcppRoll.
x
##  [1]  1  2  3  4  5  6  7  8  9 10
cumsum(x)
##  [1]  1  3  6 10 15 21 28 36 45 55
cummean(x)
##  [1] 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5
  • Comparaciones lógicas: <, <=, >, >=, != sobre las cuales aprendiste antes. Si estás haciendo una secuencia compleja de operaciones lógicas, es a menudo una buena idea almacenar los valores provisionales en nuevas variables para que puedas comprobar que cada paso funciona como se espera.

  • Ordenamiento: hay una serie de funciones de ordenamiento (ranking), pero deberías comenzar con min_rank(). Esta función realiza el tipo más común de ordenamiento (por ejemplo, primero, segundo, tercero, etc.). El valor predeterminado otorga la menor posición a los valores más pequeños; usa desc(x) para dar la menor posición a los valores más grandes.

y <- c (1, 2, 2, NA, 3, 4)
min_rank(y)
## [1]  1  2  2 NA  4  5
min_rank(desc(y))
## [1]  5  3  3 NA  2  1

Si min_rank() no hace lo que necesitas, consulta las variantes row_number(), dense_rank(), percent_rank(), cume_dist(), quantile(). Revisa sus páginas de ayuda para más detalles.

row_number(y)
## [1]  1  2  3 NA  4  5
dense_rank(y)
## [1]  1  2  2 NA  3  4
percent_rank(y)
## [1] 0.00 0.25 0.25   NA 0.75 1.00
cume_dist(y)
## [1] 0.2 0.6 0.6  NA 0.8 1.0

3 Ejercicios

3.1 Ejercicio 1

Las variables horario_salida y salida_programada tienen un formato conveniente para leer, pero es difícil realizar cualquier cálculo con ellas porque no son realmente números continuos. Transfórmalas hacia un formato más conveniente como número de minutos desde la medianoche.

vuelos |> mutate(min_horario_salida= (horario_salida %/% 100 * 60 + horario_salida %% 100),
                 min_salida_programada= (salida_programada %/% 100 * 60 + salida_programada %% 100)) -> vuelos

vuelos |> select(horario_salida, min_horario_salida,salida_programada, min_salida_programada)
## # A tibble: 336,776 × 4
##    horario_salida min_horario_salida salida_programada min_salida_programada
##             <int>              <dbl>             <int>                 <dbl>
##  1            517                317               515                   315
##  2            533                333               529                   329
##  3            542                342               540                   340
##  4            544                344               545                   345
##  5            554                354               600                   360
##  6            554                354               558                   358
##  7            555                355               600                   360
##  8            557                357               600                   360
##  9            557                357               600                   360
## 10            558                358               600                   360
## # ℹ 336,766 more rows

3.2 Ejercicio 2

Compara tiempo_vuelo con horario_llegada - horario_salida. ¿Qué esperas ver? ¿Qué ves? ¿Qué necesitas hacer para arreglarlo?

Lo que se espera ver es que tiempo_vuelo = horario_llegada - horario_salida. Entonces, se crea la variable llegada_salida = horario_llegada - horario_salida y se compara la diferencia entre tiempo_vuelo y llegada_salida.

vuelos |> group_by(tiempo_vuelo) |> reframe(llegada_salida= horario_llegada - horario_salida,
                                             diferencia1 = llegada_salida - tiempo_vuelo) 
## # A tibble: 336,776 × 3
##    tiempo_vuelo llegada_salida diferencia1
##           <dbl>          <int>       <dbl>
##  1           20             87          67
##  2           20             85          65
##  3           21             99          78
##  4           21             94          73
##  5           21             39          18
##  6           21             88          67
##  7           21             97          76
##  8           21            105          84
##  9           21             77          56
## 10           21             79          58
## # ℹ 336,766 more rows

En tabla anterior se puede observar fácilmente que los valores de tiempo_vuelo y la resta de horario_llegada - horario_salida son diferentes. Esto se debe a que se deben transformar los datos a minutos.

vuelos |> mutate(min_horario_llegada= (horario_llegada %/% 100 * 60 + horario_llegada %% 100) ) -> vuelos
vuelos |> group_by(tiempo_vuelo) |> reframe(min_llegada_salida = min_horario_llegada - min_horario_salida,
                                            diferencia2 = min_llegada_salida - tiempo_vuelo)
## # A tibble: 336,776 × 3
##    tiempo_vuelo min_llegada_salida diferencia2
##           <dbl>              <dbl>       <dbl>
##  1           20                 47          27
##  2           20                 45          25
##  3           21                 59          38
##  4           21                 54          33
##  5           21                 39          18
##  6           21                 48          27
##  7           21                 57          36
##  8           21                 65          44
##  9           21                 37          16
## 10           21                 39          18
## # ℹ 336,766 more rows

A pesar de que se transformó el horario de llegada a minutos, se observa que al realizar la resta entre el horario de llegada (min_horario_llegada) y el horario de salida (min_horario_salida), los valores resultantes no son iguales a los de tiempo_vuelo. Esto puede deberse a un error al registrar los datos.

3.3 Ejercicio 3

Compara horario_salida, salida_programada, y atraso_salida. ¿Cómo esperarías que esos tres números estén relacionados?

 vuelos |> select(horario_salida, salida_programada, atraso_salida)
## # A tibble: 336,776 × 3
##    horario_salida salida_programada atraso_salida
##             <int>             <int>         <dbl>
##  1            517               515             2
##  2            533               529             4
##  3            542               540             2
##  4            544               545            -1
##  5            554               600            -6
##  6            554               558            -4
##  7            555               600            -5
##  8            557               600            -3
##  9            557               600            -3
## 10            558               600            -2
## # ℹ 336,766 more rows

La relación entre las variables es: atraso_salida = horario_salida - salida_programada

vuelos |> mutate(diferencia_salida=  min_horario_salida - min_salida_programada) -> vuelos

table(vuelos$atraso_salida == vuelos$diferencia_salida)
## 
##  FALSE   TRUE 
##   1207 327314
(vuelos |> filter(diferencia_salida != atraso_salida)|>
  select(horario_salida, salida_programada, atraso_salida,
                                            diferencia_salida, min_horario_salida, min_salida_programada) -> P3)
## # A tibble: 1,207 × 6
##    horario_salida salida_programada atraso_salida diferencia_salida
##             <int>             <int>         <dbl>             <dbl>
##  1            848              1835           853              -587
##  2             42              2359            43             -1397
##  3            126              2250           156             -1284
##  4             32              2359            33             -1407
##  5             50              2145           185             -1255
##  6            235              2359           156             -1284
##  7             25              2359            26             -1414
##  8            106              2245           141             -1299
##  9             14              2359            15             -1425
## 10             37              2230           127             -1313
## # ℹ 1,197 more rows
## # ℹ 2 more variables: min_horario_salida <dbl>, min_salida_programada <dbl>

Se observa que la relación atraso_salida = horario_salida - salida_programada se cumple cuando se han transformado las dos últimas variables a minutos. Sin embargo, existen algunas excepciones que se generan cuando la hora de salida programada es anterior a las 00:00 y la hora de salida se da al día siguiente, es entonces que al realizar la resta no se obtiene el resultado adecuado. Esto se debe a que no se tiene en cuenta el cambio de día, lo que produce resultados diferentes a los de atraso_salida.

3.4 Ejercicio 4

Encuentra los 10 vuelos más retrasados utilizando una función de ordenamiento. ¿Cómo quieres manejar los empates? Lee atentamente la documentación de min_rank().

vuelos |> mutate(atraso_min_rank = min_rank(desc(atraso_salida)), 
                 atraso_row_number = row_number(desc(atraso_salida)),
                 atraso_dense_rank = dense_rank(desc(atraso_salida))) -> P4

P4 |> filter(atraso_min_rank <= 10 & atraso_row_number <= 10 & atraso_dense_rank <= 10) -> P4

P4 |> arrange(atraso_min_rank) -> P4
P4
## # A tibble: 10 × 26
##     anio   mes   dia horario_salida salida_programada atraso_salida
##    <int> <int> <int>          <int>             <int>         <dbl>
##  1  2013     1     9            641               900          1301
##  2  2013     6    15           1432              1935          1137
##  3  2013     1    10           1121              1635          1126
##  4  2013     9    20           1139              1845          1014
##  5  2013     7    22            845              1600          1005
##  6  2013     4    10           1100              1900           960
##  7  2013     3    17           2321               810           911
##  8  2013     6    27            959              1900           899
##  9  2013     7    22           2257               759           898
## 10  2013    12     5            756              1700           896
## # ℹ 20 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>, min_horario_salida <dbl>,
## #   min_salida_programada <dbl>, min_horario_llegada <dbl>,
## #   diferencia_salida <dbl>, atraso_min_rank <int>, atraso_row_number <int>,
## #   atraso_dense_rank <int>

Los empates se manejan utilizando las funciones: min_rank, row_number y dense_rank conjuntamente.

3.5 Ejercicio 5

¿Qué devuelve 1:3 + 1:10? ¿Por qué?

1:3 + 1:10
##  [1]  2  4  6  5  7  9  8 10 12 11

Devuelve la suma de los números del 1 al 3 y los números del 1 al 10, sumando los tres valores (1,2,3) repetidamente a los valores respectivos del (1:10). Esto se da debido a que la longitud de ambos vectores es desigual.

3.6 Ejercicio 6

¿Qué funciones trigonométricas proporciona R?

  • Se puede calcular el coseno, seno y tangente de un ángulo en radianes:
x <- (pi/2)
cos(x)
## [1] 6.123032e-17
sin(x)
## [1] 1
tan(x)
## [1] 1.633124e+16
  • Se puede calcular el arcocoseno, arcoseno, arcotangente y el arcotangente de dos argumentos:
acos(4/5)
## [1] 0.6435011
asin(3/5)
## [1] 0.6435011
atan(1)
## [1] 0.7853982
atan2(1, 0.5)
## [1] 1.107149
  • Se puede calcular del coseno, seno y tangente de los múltiplos de pi:
cospi(pi)
## [1] -0.9026854
sinpi(pi)
## [1] -0.4303012
tanpi(pi)
## [1] 0.4766901

Todas las funciones trigonométricas anteriormente mostradas se pueden hallar con el codigo ?Trig.