Mostrar tablas estadisticas con kableExtra

r
recursos
kableExtra
Autor/a

Patricio Said

Fecha de publicación

25 de septiembre de 2019

En cualquier trabajo de investigación que involucre una muestra o conjunto de datos es importante mostrar un cuadro resumen que contenga estadísticas descriptivas del conjunto, de esta manera se puede comunicar de forma clara la dimensión de los datos del estudio.

Con solo dos herramientas la construcción de tablas resúmnes resulta muy facil y sencilla. Las funciones de dplyr permiten calcular diferentes estadísticas según grupos. Una vez terminada la tabla el paquete kableExtra transforma facimente la información de la tabla a formato HTML o Latex (para visualizar en PDF).

Los datos a usar

Para este ejemplo utilizo los datos vuelos que están dentro del paquete datos. vuelos es la traducción al español del conjunto nycflights13::flights. Este conjunto contiene los datos de los vuelos que despegaron de Nueva York durante el 2013.

library(datos)
library(tidyverse)
vuelos
# 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>

Los datos vienen en formato tibble. De manera de ejemplo y poder probar las agrupaciones de columnas y filas al momento de mostrar la tabla voy a filtrar el conjunto de datos en un rango de tres meses (septiembre a noviembre) y trabajar con los datos de las 3 aerolíneas con más vuelos.

Preparando los datos

mayores_aerolineas guarda las 3 aerolineas con mas vuelos:

mayores_aerolineas <- vuelos %>% select(mes, aerolinea) %>% 
  filter(mes %in% (9:11)) %>% 
  group_by( aerolinea) %>% 
    summarise(n = n()) %>% 
  arrange(desc(n)) %>% 
  slice(1:3) %>% 
  ungroup()

# Busca los nombres  
aerolineas %>% 
  filter(aerolinea %in% mayores_aerolineas$aerolinea)
# A tibble: 3 × 2
  aerolinea nombre                  
  <chr>     <chr>                   
1 B6        JetBlue Airways         
2 EV        ExpressJet Airlines Inc.
3 UA        United Air Lines Inc.   

En datos guarda los datos a utilizar para este ejemplo.

datos <- vuelos %>% 
  select(mes, aerolinea, atraso_llegada, atraso_salida) %>% 
  filter(atraso_salida > 0 , atraso_llegada > 0) %>% 
  filter(mes >=9, mes <=11) %>% 
  filter(aerolinea %in% mayores_aerolineas$aerolinea) %>% 
  arrange(mes)
datos
# A tibble: 8,688 × 4
     mes aerolinea atraso_llegada atraso_salida
   <int> <chr>              <dbl>         <dbl>
 1     9 B6                     3            10
 2     9 B6                   139           152
 3     9 EV                     8            11
 4     9 B6                     9             2
 5     9 B6                    13            18
 6     9 B6                    46            57
 7     9 EV                    61            80
 8     9 EV                     4            25
 9     9 UA                    16            50
10     9 EV                    30            38
# ℹ 8,678 more rows

De manera de hacer un ejemplo práctico, generalmente en los papers que ajustan modelos de predicción suele mostrarse el conjunto de datos separados en “ajuste” y “prueba”. Para esto, el conjunto datos se dividió aleatoriamente en proporción 80:20. Luego para cada conjunto se calcularon algunas estadísticas en base a la variable atraso_llegada.

datos <- datos %>%  
  mutate(conjunto = sample(c("train","test"), nrow(datos), replace = T, prob = c(0.8,0.2)))

datos_train <- datos %>% select(mes,aerolinea, conjunto, atraso_llegada) %>% 
  filter(conjunto == "train") %>% 
  group_by(mes, aerolinea) %>% 
  summarise(n_train = n(), 
            min_llegada_train = min(atraso_llegada),
            prom_llegada_train = mean(atraso_llegada),
            max_llegada_train = max(atraso_llegada),
            sd_llegada_train = sd(atraso_llegada)
            ) %>% 
  ungroup()

datos_test <- datos %>% select(mes,aerolinea, conjunto, atraso_llegada) %>% 
  filter(conjunto == "test") %>% 
  group_by(mes, aerolinea) %>% 
  summarise(n_test = n(), 
            min_llegada_test = min(atraso_llegada),
            prom_llegada_test = mean(atraso_llegada),
            max_llegada_test = max(atraso_llegada),
            sd_llegada_test = sd(atraso_llegada)
            ) %>% 
  ungroup()

Luego en resumen se guardó la información a mostrar en la tabla.

resumen <- left_join(datos_train,datos_test) %>% 
  mutate(mes = case_when(
                      mes == 9 ~ "Septiembre",
                      mes ==10 ~ "Octubre",
                      mes ==11 ~ "Noviembre")) %>% 
  left_join(aerolineas) %>% 
  select(mes, nombre, everything(), - (aerolinea))

Para mostrar la tabla en formato se utilizó la función kable() del paquete kableExtra. Por defecto el tipo de formato está en HTML. En los nombres de columnas se agregó <br> (salto de línea en HTML). Para agrupar filas se podría usar collapse_rows() según la variable mes.

Creando tabla

HTML

library(kableExtra) 
resumen %>% select(-mes) %>% 
kable( format = "html", 
       format.args = list(decimal.mark = ',', big.mark = "."),
       col.names = ( c("Aerolínea",
                       rep(c("N","Min.<br>*(minutos)*",
                             "Media<br>*(minutos)*",
                             "Max.<br>*(minutos)*",
                             "D.E<br>*(minutos)*"),
                           2))), 
         digits = 1 , escape = F) %>%
  kable_styling(c("striped"),font_size = 11) %>% 
  add_header_above(header = c(" "=1, 
                              "Conjunto entrenamiento (N=6.973)" = 5,
                              "Conjunto prueba (N=1.715)" = 5 ) ) %>% 
  pack_rows("Septiembre", 1, 3) %>% 
  pack_rows("Octubre", 4, 6) %>% 
  pack_rows("Noviembre", 7,9) %>% 
   footnote(general = "D.E: Desviación estandar.",
            footnote_as_chunk = F)
Conjunto entrenamiento (N=6.973)
Conjunto prueba (N=1.715)
Aerolínea N Min.
*(minutos)*
Media
*(minutos)*
Max.
*(minutos)*
D.E
*(minutos)*
N Min.
*(minutos)*
Media
*(minutos)*
Max.
*(minutos)*
D.E
*(minutos)*
Septiembre
JetBlue Airways 594 1 54,3 396 64,5 154 1 40,9 195 43,2
ExpressJet Airlines Inc. 734 1 49,5 364 55,9 189 1 56,2 444 70,1
United Air Lines Inc. 563 1 51,6 406 70,5 150 1 52,7 373 71,3
Octubre
JetBlue Airways 551 1 36,2 366 43,6 146 1 41,7 335 49,2
ExpressJet Airlines Inc. 1.171 1 51,5 318 50,5 289 1 51,7 300 48,4
United Air Lines Inc. 831 1 35,6 288 43,8 242 1 33,9 239 38,7
Noviembre
JetBlue Airways 622 1 35,9 299 37,3 179 1 39,7 217 43,0
ExpressJet Airlines Inc. 995 1 42,8 334 42,7 244 1 42,0 389 44,0
United Air Lines Inc. 830 1 34,8 346 46,9 204 1 38,1 335 49,2
Note:
D.E: Desviación estandar.

Latex

Para formato Latex se debe especificar en el argumento formato = "latex". Algunos argumentos son difentes, como en el caso de los saltos en líneas en los nombres:

resumen %>% select(-mes) %>% 
 kable( format.args = list(decimal.mark = ',', big.mark = "."),
        digits = 2, "latex", booktabs= T, linesep="", 
        escape = F, 
        caption = "Resumen estadístico",
        col.names = linebreak( c("Aerolínea",
                       rep(c("N","Min.\n(minutos",
                             "Media\n(minutos)",
                             "Max.\n(minutos)",
                             "D.E\n(minutos)"),
                           2)))) %>%
  kable_styling(latex_options="scale_down") %>% 
  add_header_above(header = c(" "=1, 
                              "Conjunto entrenamiento (N=6.973)" = 5,
                              "Conjunto prueba (N=1.715)" = 5 ) ) %>% 
  pack_rows("Septiembre", 1, 3) %>% 
  pack_rows("Octubre", 4, 6) %>% 
  pack_rows("Noviembre", 7,9) %>% 
   footnote(symbol = "D.E: Desviación estandar.",
            footnote_as_chunk = F)

La salida sería algo así: