Como hemos visto, dplyr actúa sobre bases de datos utilizando cinco verbos fundamentales:
filter que filtra observacionesselect que selecciona variablesarrange que ordena por una variable en orden ascendente o descendentemutate que genera columnas (i.e. variables) de forma recursivasummarise que resume los valores de la base de datos en estadísticos unidimensionalesPara continuar con nuestro aprendizaje carguemos la base de datos de todos los vuelos que salieron del aeropuerto de Houston en el año de 2011 que hemos estado utilizando en clase (debe de estar en tu espacio de trabajo del proyecto, si creaste uno).
library(dplyr)
flights <- tbl_df(read.csv("flights.csv", stringsAsFactors = FALSE))
flights$date <- as.Date(flights$date)
head(flights)
## # A tibble: 6 x 14
## date hour minute dep arr dep_delay arr_delay carrier flight dest
## <date> <int> <int> <int> <int> <int> <int> <chr> <int> <chr>
## 1 2011-01-01 14 0 1400 1500 0 -10 AA 428 DFW
## 2 2011-01-02 14 1 1401 1501 1 -9 AA 428 DFW
## 3 2011-01-03 13 52 1352 1502 -8 -8 AA 428 DFW
## 4 2011-01-04 14 3 1403 1513 3 3 AA 428 DFW
## 5 2011-01-05 14 5 1405 1507 5 -3 AA 428 DFW
## 6 2011-01-06 13 59 1359 1503 -1 -7 AA 428 DFW
## # … with 4 more variables: plane <chr>, cancelled <int>, time <int>, dist <int>
Junto con los cinco verbos básicos, dplyr puede trabajar con datos agrupados usando el comando group_by cuya función es ejecutar las acciones posteriores al nivel que la agrupación indique. Para ejemplificar, supongamos que queremos resumir el tiempo de retraso de llegadas, arr_delay por día. Para ello, seleccionamos como medidas de tendencia central la media y la mediana, como medidas de dispersión la desviación estándar y el rango intercuartil, y como medidas particulares de contexto la proporción de vuelos cuyo retraso es mayor a 15, 30, o 60 minutos. Nuestro resumen por día se calcula como sigue:
por_dia <- group_by(na.omit(flights), date)
# para agrupar la base por día y que los cálculos
# siguientes se realicen a ese nivel
summarise(por_dia, media = mean(arr_delay),
mediana = median(arr_delay),
sd = sd(arr_delay),
iqr = IQR(arr_delay),
mayor_15 = mean(arr_delay > 15),
mayor_30 = mean(arr_delay > 30),
mayor_60 = mean(arr_delay > 60))
## # A tibble: 365 x 8
## date media mediana sd iqr mayor_15 mayor_30 mayor_60
## <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 2011-01-01 10.1 5 21.2 21 0.280 0.121 0.0329
## 2 2011-01-02 10.5 3 29.5 22 0.267 0.145 0.0435
## 3 2011-01-03 6.04 -2 27.3 19.5 0.207 0.116 0.0386
## 4 2011-01-04 7.97 4 21.0 22 0.258 0.108 0.0224
## 5 2011-01-05 4.17 -1 25.1 18 0.183 0.0735 0.0120
## 6 2011-01-06 6.07 2 18.6 18 0.205 0.0729 0.0243
## 7 2011-01-07 3.91 0 19.0 16 0.170 0.0638 0.0198
## 8 2011-01-08 3.07 -2 21.1 16 0.158 0.0741 0.0261
## 9 2011-01-09 17.3 10 28.6 31 0.427 0.240 0.0709
## 10 2011-01-10 11.0 5 25.4 22.5 0.288 0.134 0.0388
## # … with 355 more rows
La lógica del cálculo es inmediata: Agrupando primero por día, pedimos la media, mediana, etc. de la variable arr_delay. Estos estadísticos se calculan, por el uso de group_by para cada uno de los días. Observe que se pueden utilizar funciones prestablecidas para hacer el resumen, como mean, median, sd, IQR (otros ejemplos son min, max, quantile(x, p), n(), ndistinct(), sum(), var(), mad()).
Observe también el uso de na.omit(flights) cuya función es eliminar todas las observaciones que tengan por lo menos un NA. Recuerde que en R el NA es epistémico, es decir, apunta a un “no saber” que, por lo tanto, se propaga a todos los cálculos. En caso de no haber incluido la función na.omit tendríamos que haber utilizado el argumento na.rm = TRUE en las funciones siguientes para remover los NAs antes del cálculo. Hay una sutil diferencia entre estos dos métodos: El primero quita todas las observaciones que tengan NA en alguna columna, mientras que el segundo sólo quita los NAs de la variable de interés. Complete el siguiente código para ver la diferencia:
completas <- filter(flights, !is.na(arr_delay))
summarise(...)
La nueva base, completas, excluye solo las observaciones en las que la variable de interés, arr_delay es NA.
La gran desventaja de utilizar esta sintaxis funcional es que se vuelve difícil leer (y programar) operaciones complejas, por ejemplo, qué resulta de ejecutar el siguiente código?
who_is <- filter(
summarise(
group_by(
filter(
flights,
!is.na(arr_delay)
),
date, hour
),
medio = mean(arr_delay),
num = n()
),
num > 10
)
La escritura y lectura de código en dplyr se facilita con el operador pipeline, %>% (atajo de teclado Ctrl + Shift + M), cuya operación puede representarse simbolicamente como \[x \;{\tiny\%>\%}\; f(y) = f(x, y).\]
Por ejemplo, los siguientes son equivalentes:
filter(flights, !is.na(arr_delay))
flights %>% filter(!is.na(arr_delay))
Los operadores pipeline pueden concatenarse, mandando el resultado de la última operacón, a la siguietne. Utilizando el operador pipeline (de adentro hacia afuera), vemos que la base who_is puede calcularse como
who_is <- fligths %>%
filter(!is.na(arr_delay)) %>%
group_by(date, hour) %>%
summarise(medio = mean(arr_delay),
num = n()) %>%
filter(num > 10)
Para leer el código, se puede interpretar el operador pipeline como “y luego”. En este ejemplo, la base who_isse consigue con los siguienetes pasos: Pimero tomar flights, luego filtarla evitando datos faltantes de la variable arr_delay luego agrupando por fecha y hora, luego resumiendo con el valor medio y el número de observaciones, y luego, finalmente, filtrando cuando hubo más de 10 observaciones. Esta breve historia nos cuenta que estamos calculando el promedio y número de vuelos por día y hora; pero solo observando el resultado si en esa combinación de día/hora ha habido más de 10 vuelos.
Construya pipelines, utilizando todos los verbos básicos y el operador group_by, para responder a las siguientes preguntas:
carrier y flight) ocurren diario, y a dónde van?time = hour + minute/60 en este ejercicio.Compare sus respuestas:
## # A tibble: 116 x 3
## dest mean_arr_delay n
## <chr> <dbl> <int>
## 1 ANC 26.1 125
## 2 CID 17.8 410
## 3 DSM 16.0 647
## 4 SFO 14.9 2818
## 5 BPT 14.3 3
## 6 GRR 13.7 677
## 7 DAY 13.7 451
## 8 VPS 12.5 880
## 9 ECP 12.4 729
## 10 SAV 12.3 863
## # … with 106 more rows
## # A tibble: 7 x 4
## # Groups: carrier, flight [7]
## carrier flight dest n
## <chr> <int> <chr> <int>
## 1 AA 1294 MIA 365
## 2 AS 731 SEA 365
## 3 CO 1 HNL 365
## 4 CO 62 EWR 365
## 5 CO 89 EWR 365
## 6 CO 106 EWR 365
## 7 MQ 3859 ORD 365
## # A tibble: 1,207 x 3
## time arr_delay n
## <dbl> <dbl> <int>
## 1 0.0167 29.7 7
## 2 0.0333 64 2
## 3 0.05 141 4
## 4 0.0667 91.7 7
## 5 0.0833 114 3
## 6 0.1 51 5
## 7 0.117 90.3 6
## 8 0.133 91 2
## 9 0.15 103. 3
## 10 0.167 131. 3
## # … with 1,197 more rows
Universidad Iberoamericana; Depto, nelson.muriel@ibero.mx↩