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, …
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
Empecemos con algunos cuadros básicos:
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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" )
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:
grabar la tabla como un df y exportarla a Excel (ya sea como .csv o .xlsx). Desde allí ya puedes formatearla a tu gusto
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
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
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:
#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 |
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")
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")
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.
A partir de ahora usaremos el término tablas↩