Divide-aplica-combina (split-apply-combine)

Muchos problemas de análisis de datos involucran la aplicación de la estrategia divide-aplica-combina, (Hadley Whickam, 2011) esta consiste en romper un problema en pedazos (de acuerdo a una variable de interés), operar sobre cada subconjunto de manera independiente (ej. calcular la media de cada grupo, ordenar observaciones por grupo, estandarizar por grupo) y después unir los pedazos nuevamente. El siguiente diagrama ejemplifiaca el paradigma de divide-aplica-combina:

Bibliografía recomendada: The Slit-Apply-Combine Strategy for Data Analysis, Hadley Wickham 2011.

En esta sección trabajaremos con las siguientes bases de datos para ejemplifcar las funciones de divide-aplica-combina:

flights <- read.csv("Prac_Uni7/ejemplosgenerales/data/flights.csv")
head(flights)
##                  date hour minute  dep  arr dep_delay arr_delay carrier
## 1 2011-01-01 12:00:00   14      0 1400 1500         0       -10      AA
## 2 2011-01-02 12:00:00   14      1 1401 1501         1        -9      AA
## 3 2011-01-03 12:00:00   13     52 1352 1502        -8        -8      AA
## 4 2011-01-04 12:00:00   14      3 1403 1513         3         3      AA
## 5 2011-01-05 12:00:00   14      5 1405 1507         5        -3      AA
## 6 2011-01-06 12:00:00   13     59 1359 1503        -1        -7      AA
##   flight dest  plane cancelled time dist
## 1    428  DFW N576AA         0   40  224
## 2    428  DFW N557AA         0   45  224
## 3    428  DFW N541AA         0   48  224
## 4    428  DFW N403AA         0   39  224
## 5    428  DFW N492AA         0   44  224
## 6    428  DFW N262AA         0   45  224

Cuando pensamos como implementar la estrategia divide-aplica-combina es natural pensar en iteraciones, por ejemplo utilizar un ciclo for para recorrer cada grupo de interés y aplicar las funciones, sin embargo la aplicación de
for loops desemboca en código difícil de entender. Adicionalmente, dplyr es mucho más veloz.

Estudiaremos las siguientes funciones del paquete dplyr:

library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union

Estas funciones trabajan de manera similar, el primer argumento que reciben es un data frame (usualmente en formato limpio), los argumentos que siguen indican que operación se va a efectuar y el resultado es un nuevo data frame.

Veamos con ejemplos.

Filtrar

Ejemplo con base de datos de juguete para mostrar el funcionamiento de cada instrucción:

df_ej <- data.frame(genero= c("mujer", "hombre", "mujer", "mujer", "hombre"), 
  estatura = c(1.65, 1.80, 1.70, 1.60, 1.67))
df_ej
##   genero estatura
## 1  mujer     1.65
## 2 hombre     1.80
## 3  mujer     1.70
## 4  mujer     1.60
## 5 hombre     1.67
dplyr::filter(df_ej, genero == "mujer")
##   genero estatura
## 1  mujer     1.65
## 2  mujer     1.70
## 3  mujer     1.60
dplyr::filter(df_ej, estatura > 1.65 & estatura < 1.75)
##   genero estatura
## 1  mujer     1.70
## 2 hombre     1.67

Algunos operadores importantes para filtrar son:

x > 1
x >= 1
x < 1
x <= 1
x != 1
x == 1
x %in% ("a", "b")

# Conjuntos
a | b
a & b
a & !b
xor(a, b)

Ejercicio: Encuentra todos los vuelos hacia SFO ó OAK en flights

Seleccionar

Elegir columnas de un conjunto de datos.

df_ej
##   genero estatura
## 1  mujer     1.65
## 2 hombre     1.80
## 3  mujer     1.70
## 4  mujer     1.60
## 5 hombre     1.67
select(df_ej, genero)
##   genero
## 1  mujer
## 2 hombre
## 3  mujer
## 4  mujer
## 5 hombre
select(df_ej, -genero)
##   estatura
## 1     1.65
## 2     1.80
## 3     1.70
## 4     1.60
## 5     1.67
select(df_ej, starts_with("g"))
select(df_ej, contains("g"))

Arreglar (arrange)

Arreglar u ordenar de acuerdo al valor de una o más variables:

arrange(df_ej, genero)
##   genero estatura
## 1 hombre     1.80
## 2 hombre     1.67
## 3  mujer     1.65
## 4  mujer     1.70
## 5  mujer     1.60
arrange(df_ej, desc(estatura))
##   genero estatura
## 1 hombre     1.80
## 2  mujer     1.70
## 3 hombre     1.67
## 4  mujer     1.65
## 5  mujer     1.60

Mutar (mutate)

Mutar consiste en crear nuevas variables (columnas):

mutate(df_ej, estatura_cm = estatura * 100) 
##   genero estatura estatura_cm
## 1  mujer     1.65         165
## 2 hombre     1.80         180
## 3  mujer     1.70         170
## 4  mujer     1.60         160
## 5 hombre     1.67         167
mutate(df_ej, estatura_cm = estatura * 100, estatura_in = estatura_cm * 0.3937) 
##   genero estatura estatura_cm estatura_in
## 1  mujer     1.65         165     64.9605
## 2 hombre     1.80         180     70.8660
## 3  mujer     1.70         170     66.9290
## 4  mujer     1.60         160     62.9920
## 5 hombre     1.67         167     65.7479

Summarise y resúmenes por grupo

Summarise sirve para crear nuevas bases de datos con resúmenes o agregaciones de los datos originales.

summarise(df_ej, promedio = mean(estatura))
##   promedio
## 1    1.684

Podemos hacer resúmenes por grupo, primero creamos una base de datos agrupada:

by_genero <- group_by(df_ej, genero)
by_genero
## # A tibble: 5 x 2
## # Groups:   genero [2]
##   genero estatura
##   <fct>     <dbl>
## 1 mujer      1.65
## 2 hombre     1.80
## 3 mujer      1.70
## 4 mujer      1.60
## 5 hombre     1.67

y después operamos sobre cada grupo, creando un resumen a nivel grupo y uniendo los subconjuntos en una base nueva:

summarise(by_genero, promedio = mean(estatura))
## # A tibble: 2 x 2
##   genero promedio
##   <fct>     <dbl>
## 1 hombre     1.74
## 2 mujer      1.65
  • Algunas funciones útiles con summarise son min(x), median(x), max(x), quantile(x, p), n(), sum(x), sum(x > 1), mean(x > 1), sd(x).
flights$date_only <- as.Date(flights$date)
by_date <- group_by(flights, date_only)
no_miss <- dplyr::filter(by_date, !is.na(dep))
delays <- summarise(no_miss, mean_delay = mean(dep_delay), n = n())

Ejercicio Reescribe el código anterior utilizando %>%