1. Introducción


Hacer cuadros/tablas1 para mostrar resultados es una parte importante (y time consuming) de cualquier informe o investigación. En este tutorial nos ocuparemos de obtener los resultados que van a llenar los cuadros. Nos servirá para practicar un poco más con dplyr. Una vez tengamos los resultados que queremos mostrar ya veremos como podemos mostrarlos en cuadros good-looking.

Principalmente utilizaremos lo que hemos aprendido de dplyr para obtener los resultados que queremos mostrar en los cuadros. Con dplyr calcularemos los estadísticos que queramos mostrar almacenándolos en un dataframe. Una vez tengamos los resultados en un dataframe nos quedará la tarea de presentarlos como cuadros en el documento final.

Veremos que presentar los resultados (previamente almacenados en un df) como un cuadro en el documento final es muy sencillo, sólo tendremos que llamar a la función kable(). Kable nos permitirá mostrar los resultados como cuadros en el documento final, ya sea este un documento . html, .pdf, .doc, …



2. Datos que usaremos


Ilustraremos la creación de tablas con datos de PIACC (Programa para la Evaluación Internacional de las Competencias de los adultos de la OCDE. Información detallada sobre el programa PIAAC puede encontrarse en su pagina web http://www.oecd.org/skills/piaac/. Los datos se obtuvieron en un primer momento del pkg RPIACC creado Por Jose C. Pernias.


Cargamos datos (ya procesados) de PIACC. Concrétamente 10 variables.

#- cargamos datos procesados previamente con "./datos/datos_raw/crear_datos_PIAAC_SFP.R"
datos <- read_csv("./datos/datos_raw/PIAAC_data_SFP.csv")
aa <- names_v_df_pjp(datos)
bb <- val_unicos_df_pjp(datos)

El dataframe datos contiene datos de 23 países. Contiene 40854 filas y 10 variables


Vamos a reducir la muestra y concentrar nuestra atención a sólo 4 países: ESP, FRA, GBR, ITA

paises_ok <- c( "ESP" , "FRA", "GBR", "ITA")  
df_4 <- datos %>% filter(Country %in% paises_ok)

Es decir, trabajaremos con df_4


3. Cuadros con dplyr


Cuadros básicos

Empecemos con algunos cuadros básicos:


  • Cuadro con el número de observaciones de cada país.
df <- df_4 %>% group_by(Country) %>% count()
df <- df_4 %>% group_by(Country) %>% summarise(NN = n())
knitr::kable(df)
Country NN
ESP 1991
FRA 3346
GBR 1075
ITA 1610

  • Añadir a la tabla el % que representa cada país en el Total
df <- df_4 %>% group_by(Country) %>% 
               summarise(NN = n(), percent = n()/nrow(.) )

df <- df_4 %>% group_by(Country) %>%
               summarise (NN = n()) %>%
               mutate(percent = NN / sum(NN))
knitr::kable(df)
Country NN percent
ESP 1991 0.2481925
FRA 3346 0.4171030
GBR 1075 0.1340065
ITA 1610 0.2006981


  • Porcentaje de Hombres y Mujeres en cada país
df <- df_4 %>%  count(Country, Gender) %>%
                group_by(Country) %>%
                mutate(percent = n / sum(n)) %>%
                select(-n) %>%
                spread(Gender, percent, fill = 0) %>% ungroup()
knitr::kable(df)
Country Female Male
ESP 0.4841788 0.5158212
FRA 0.5065750 0.4934250
GBR 0.6893023 0.3106977
ITA 0.4850932 0.5149068


  • Porcentaje de Hombres y Mujeres en cada nivel educativo
df <- df_4 %>%  count(Education, Gender)   %>% group_by(Education) %>%
                   mutate(percent = n / sum(n)) %>%
                   select(-n) %>%
                   spread(Gender, percent, fill = 0) %>% ungroup()
knitr::kable(df)
Education Female Male
Primary 0.4377224 0.5622776
Secondary 0.4804831 0.5195169
Tertiary 0.6159875 0.3840125
Upper_second 0.5796460 0.4203540
NA 0.8000000 0.2000000


Salario

  • Veamos el salario medio por país
df <- df_4 %>% group_by(Country) %>% 
               summarise(W_hora_medio = mean(Wage_hour , na.rm = TRUE), 
                         W_mes_medio  = mean(Wage_month, na.rm = TRUE) ) %>% ungroup()
knitr::kable(df)
Country W_hora_medio W_mes_medio
ESP 9.386217 1437.340
FRA 12.850094 1992.606
GBR 10.624071 1507.472
ITA 11.746581 1808.500


  • Calcula la media, el mínimo, el máximo y la desviación típica de Wage_month
df <- df_4 %>% group_by(Country) %>% 
               summarise(W_medio  = mean(Wage_month, na.rm = TRUE) ,
                         W_minimo = min(Wage_month, na.rm = TRUE)  ,
                         W_maximo = max(Wage_month, na.rm = TRUE)  ,
                         W_sd = sd(Wage_month, na.rm = TRUE) ) %>% ungroup()
knitr::kable(df)
Country W_medio W_minimo W_maximo W_sd
ESP 1437.340 110 3800 702.6642
FRA 1992.606 115 5850 906.5507
GBR 1507.472 116 10000 1003.7897
ITA 1808.500 150 5000 819.6863


  • salario medio en España (Hombre y Mujeres)
df <- df_4 %>% filter(Country == "ESP") %>%  group_by(Gender) %>% 
               summarise(W_hora_medio = mean(Wage_hour, na.rm = TRUE), 
                         W_mes_medio = mean(Wage_month, na.rm = TRUE) ) %>% ungroup()

knitr::kable(df)
Gender W_hora_medio W_mes_medio
Female 8.789178 1245.076
Male 9.946525 1617.810


  • salario medio en TODOS los países (Hombre y Mujeres)
df <- df_4 %>%  group_by(Country, Gender) %>% 
                summarise(W_hora_medio = mean(Wage_hour, na.rm = TRUE), 
                          W_mes_medio = mean(Wage_month, na.rm = TRUE) ) %>% ungroup()
knitr::kable(df)
Country Gender W_hora_medio W_mes_medio
ESP Female 8.789178 1245.076
ESP Male 9.946525 1617.810
FRA Female 12.443723 1802.254
FRA Male 13.266840 2188.032
GBR Female 10.609256 1377.953
GBR Male 10.656991 1794.817
ITA Female 11.584393 1629.828
ITA Male 11.898988 1976.826


  • ¿Cuanto de más cobran los hombres (en %)?
df <- df_4 %>%  group_by(Country, Gender) %>% 
                summarise(W_mes_medio = mean(Wage_month, na.rm = TRUE)) %>% ungroup()
dfa <- df %>% spread(Gender, W_mes_medio)  
dfa <- dfa %>% mutate(dif_W = Male-Female, di_percent_W = dif_W/Female)
knitr::kable(dfa)
Country Female Male dif_W di_percent_W
ESP 1245.076 1617.810 372.7344 0.2993669
FRA 1802.254 2188.032 385.7784 0.2140533
GBR 1377.953 1794.817 416.8640 0.3025240
ITA 1629.828 1976.826 346.9983 0.2129048


Numeracy Score

  • Numeracy Score por país y nivel de estudios
df <- df_4 %>%  group_by(Country, Education) %>% 
                summarise(NUM_medio = mean(Numeracy_score, na.rm = TRUE)) %>% ungroup() 
knitr::kable(df)
Country Education NUM_medio
ESP Primary 213.0135
ESP Secondary 245.1109
ESP Tertiary 282.1070
ESP Upper_second 265.7699
FRA Primary 184.9306
FRA Secondary 246.6609
FRA Tertiary 304.0075
FRA Upper_second 289.0088
FRA NA 197.6502
GBR Primary 207.3143
GBR Secondary 252.9237
GBR Tertiary 286.1454
GBR Upper_second 263.2052
GBR NA 213.1912
ITA Primary 200.7297
ITA Secondary 257.5339
ITA Tertiary 279.7166
ITA Upper_second 271.6400
  • Una columna para cada país
df <- df_4 %>%  group_by(Country, Education) %>% 
                summarise(NUM_medio = mean(Numeracy_score, na.rm = TRUE)) %>% ungroup()
dfa <- df  %>% spread(key = Education, value = NUM_medio) 
knitr::kable(dfa)
Country Primary Secondary Tertiary Upper_second
ESP 213.0135 245.1109 282.1070 265.7699 NA
FRA 184.9306 246.6609 304.0075 289.0088 197.6502
GBR 207.3143 252.9237 286.1454 263.2052 213.1912
ITA 200.7297 257.5339 279.7166 271.6400 NA


Queremos ordenar el cuadro

Resulta que en el cuadro, las categorías de niveles de estudio se han ordenado alfabéticamente pero queremos ordenarla de menor a mayor nivel de estudios. Se puede hacer de otras maneras, pero lo haremos usando factores.

La variable Education tiene 4 categorías: Primary, Secondary, Upper-second y Tertiary; ADEMÁS estas categoría están fijas, no cambian. En estos casos es mejor tratar esas variables como factores; PERO si miramos la clase de la variable “Education” con class(datos$Education) veremos que es character, así que vamos a convertir la variable “Education” a factor.

Podríamos usar la función as.factor(), pero una vez más usaremos pkgs del tidyverse; en este caso el pkg “forcats” y la función as_factor()

datos <- datos %>% mutate(Education = as_factor(Education) )
levels(datos$Education)
[1] "Primary"      "Secondary"    "Tertiary"     "Upper_second"


Si queremos cambiar los labels del factor, lo haremos con fct_recode(). Para saber un poco más sobre como manipular factores debes ir aquí

datos1 <- datos %>% mutate(Education = fct_recode(Education,
                   "Primaria"    = "Primary",
                   "Secundaria"  = "Secondary" )) %>% count(Education)
knitr::kable(datos1)
Education n
Primaria 1355
Secundaria 21535
Tertiary 11020
Upper_second 6923
NA 21


Como vemos, el factor “Education” tiene 4 “levels” pero están ordenados en orden alfabético. vamos a cambiar el orden de los levels con fct_relevel().

datos$Education <- fct_relevel(datos$Education, 
                        "Primary", "Secondary", "Upper_second", "Tertiary" ) 
datos %>% count(Education)
# A tibble: 5 x 2
     Education     n
        <fctr> <int>
1      Primary  1355
2    Secondary 21535
3 Upper_second  6923
4     Tertiary 11020
5         <NA>    21

Como se puede ver en el cuadro de arriba, ya hemos cambiado el orden de los “levels”, así que volvamos a rehacer el cuadro con el Numeracy Score por países:

df_4 <- datos %>% filter(Country %in% paises_ok)


df <- df_4 %>%  group_by(Country, Education) %>% 
                summarise(NUM_medio = mean(Numeracy_score, na.rm = TRUE)) %>% ungroup() 
dfa <- df %>% spread(key = Education, value = NUM_medio) 
knitr::kable(dfa)
Country Primary Secondary Upper_second Tertiary
ESP 213.0135 245.1109 265.7699 282.1070 NA
FRA 184.9306 246.6609 289.0088 304.0075 197.6502
GBR 207.3143 252.9237 263.2052 286.1454 213.1912
ITA 200.7297 257.5339 271.6400 279.7166 NA



4. ¿Cómo hacer mis cuadros?


Bueno, ya sabemos como ir generando un dataframe con los estadísticos descriptivos que nos interesa mostrar. En realidad esos df ya son tablas que puedo exportar a Excel para trabajarlas a mi gusto, o puedo mostrarlas en mi documento final (ya sea .html, .doc o .pdf) con la función kable de knitr; osea, con knitr::kable()


En el próximo tutorial mostraremos algunos paquetes específicos para formatear los cuadros y hacerlos BONITOS, pero también conviene saber que kable() tambien tiene opciones para personalizar un poco nuestras tablas. Por ejemplo:

knitr::kable(dfa, digits = 2, align = "c", caption = "Numeracy Score by country" )
Numeracy Score by country
Country Primary Secondary Upper_second Tertiary
ESP 213.01 245.11 265.77 282.11 NA
FRA 184.93 246.66 289.01 304.01 197.65
GBR 207.31 252.92 263.21 286.15 213.19
ITA 200.73 257.53 271.64 279.72 NA


Recapitulando, en nuestra opinión, una vez tenemos un df con los resultados que queremos mostrar en el documento final, las opciones más sencillas son:

  • Si quieres las tablas en un documento html, lo mejor es hacerlas directamente desde el documento .Rmd con knitr::kable()

  • Si quieres las tablas en latex, mejor hazlas en latex, aunque hay varios paquetes (incluido knitr) que permiten exportar las tablas a latex. Solo tienes que poner kable(format = "latex")

  • Si las quieres en Word, lo más sencillo es:

    1. grabar la tabla como un df y exportarla a Excel (ya sea como .csv o .xlsx). Desde allí ya puedes formatearla a tu gusto

    2. Desde el documento en .Rmd puedes crear un documento word con la tabla. Una vez tienes la tabla en word ya puedes darle el formato que quieras




5. kableextra


kableExtra es un nuevo package que permite mejorar las tablas creadas con knitr::kable(). Aquí tienes la vignette.


La descripción de kableExtra en CRAN es:

A collection of functions to help build complex HTML or ‘LaTeX’ tables using ‘kable()’ from ‘knitr’ and the piping syntax from ‘magrittr’. Function ‘kable()’ is a light weight table generator coming from ‘knitr’. This package simplifies the way to manipulate the HTML or ‘LaTeX’ codes generated by ‘kable()’ and allows users to construct complex tables and customize styles using a readable syntax.


Puedes ver las posibilidades que tiene este pkg para customizar las tablas generadas con kable() en su vignette: https://cran.r-project.org/web/packages/kableExtra/vignettes/awesome_table_in_html.html




6. printr

printr es un package, que no es exactamente para hacer tablas, pero que es como un acompañante de knitr que es el pkg que gestiona como se muestran las tablas al compilar un documento .Rmd. En palabras de su autor (Yihui Xie), printr es:

The printr package is a companion package to knitr. Its main purpose is to extend the S3 generic function knit_print() in knitr, which is the default value of the chunk option render, as explained in the vignette knit_print.html.

En concreto, printr hace que se modifique la forma en que se muestran algunos objetos de R; concrétamente:

  • Las matrices, data frames, y tablas de contingencia, en lugar de imprimirse como texto, se mostrarán (en el documento final que nos sale al compilar el .Rmd con knitr) como tablas. Veámoslo:
#install.packages( "printr",  type = 'source',  repos = c('http://yihui.name/xran', 'http://cran.rstudio.com'))
library("printr")
head(mtcars)
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1
table(mtcars$gear, mtcars$cyl)
/ 4 6 8
3 1 2 12
4 8 4 0
5 2 1 2


  • Las páginas de ayuda(help pages: ?dplyr or help(dplyr)) se mostrarán como HTML, LaTeX, or plain text (dependiendo del formato de salida de nuestro .Rmd); además se puede especificar que secciones de la ayuda mostrar:


  • Los resultados que salen de browseVignettes(), help.search(), data(), and vignette() se mostrarán como tablas. La información que sale de library(help = ‘dplyr’) se mostrará como texto plano.


help.search("contourplot")
Package Topic Title
LearnBayes mycontour Contour plot of a bivariate density function
mosaic panel.levelcontourplot Lattice plot that draws a filled contour plot
raster contour Contour plot
raster filledContour Filled contour plot
graphics filled.contour Level (Contour) Plots
lattice levelplot Level plots and contour plots
lattice panel.levelplot Panel Functions for levelplot and contourplot


help.search('filter', package = 'dplyr')
Package Topic Title
dplyr filter Return rows with matching conditions
dplyr filter_all Filter within a selection of variables
dplyr tally_ Deprecated SE versions of main verbs.


vignette(package = "dplyr")
Vignettes in dplyr
Item Title
compatibility dplyr compatibility (source, html)
dplyr Introduction to dplyr (source, html)
programming Programming with dplyr (source, html)
two-table Two-table verbs (source, html)
window-functions Window functions (source, html)


data(package = "dplyr")
Data sets in dplyr
Item Title
band_instruments Band membership
band_instruments2 Band membership
band_members Band membership
nasa NASA spatio-temporal data
starwars Starwars characters
storms Storm tracks data


browseVignettes(package = "knitr")
Vignette Title
knitr-html.html An R HTML Vignette with knitr
knitr-markdown.html An R Markdown Vignette with knitr
knit_print.html Custom Print Methods
datatables.html Display Tables with the JavaScript Library DataTables
knitr-refcard.pdf knitr Reference Card
knitr-intro.html Not an Introduction to knitr
docco-classic.html R Markdown with the Docco Classic Style
docco-linear.html R Markdown with the Docco Linear Style
knit_expand.html Templating with knit_expand()


library(help = "printr")
        Information on package 'printr'

Description:

Package:            printr
Type:               Package
Title:              Automatically Print R Objects to Appropriate
                    Formats According to the 'knitr' Output Format
Version:            0.1
Date:               2017-05-19
Author:             Yihui Xie
Maintainer:         Yihui Xie <xie@yihui.name>
Description:        Extends the S3 generic function knit_print()
                    in 'knitr' to automatically print some objects
                    using an appropriate format such as Markdown
                    or LaTeX. For example, data frames are
                    automatically printed as tables, and the
                    help() pages can also be rendered in 'knitr'
                    documents.
Imports:            knitr (>= 1.16)
Suggests:           tools, rmarkdown
License:            GPL
URL:                https://yihui.name/printr/
BugReports:         https://github.com/yihui/printr/issues
VignetteBuilder:    knitr
LazyData:           TRUE
RoxygenNote:        6.0.1
NeedsCompilation:   no
Packaged:           2017-05-19 06:36:31 UTC; travis
Built:              R 3.3.2; ; 2017-11-15 13:24:41 UTC; windows

Index:

printr                  Print R objects in 'knitr' documents nicely

Further information is available in the following vignettes in
directory
'C:/Users/perezp/Desktop/Documents/R/win-library/3.3/printr/doc':

printr: An Introduction to the printr Package (source, pdf)



Yihui Xie explica las funcionalidades de printr más en detalle en su vignette. No la he leído del todo, pero entiendo que printr permite, a los desarrolladores de paquetes, customizar (a su gusto) la forma en que knitr mostrará las tablas de los objetos que se creen con sus packages.



  1. A partir de ahora usaremos el término tablas