Visualización de tablas

Sesión del lunes, 3 de noviembre de 2025

Objetivo de la práctica

El objetivo de esta guía práctica es aprender cómo generar y reportar tablas.

Recursos de la práctica

En esta práctica trabajaremos con un subconjunto de datos previamente procesados derivados de las encuestas realizadas en diferentes países por el Latin American Public Opinion Proyect (LAPOP) en su ola del 2018. Para este ejercicio, obtendremos directamente esta base desde internet. No obstante, también tienes la opción de acceder a la misma información a través del siguiente enlace: LAPOP 2018. Desde allí, podrás descargar el archivo que contiene el subconjunto procesado de la base de datos LAPOP 2018.

Preparación de datos

Comencemos por preparar nuestros datos. Iniciamos cargando las librerías necesarias.

pacman::p_load(tidyverse, # Manipulacion datos
               sjmisc, # Descriptivos
               knitr, # Render y tablas
               kableExtra, # Formateo tablas
               summarytools, # Tablas
               sjPlot, # Tablas y gráficos
               stargazer, # Tablas
               janitor, # Tablas y formateo
               crosstable, # Tablas
               table1 # Tablas
               ) 

options(scipen = 999) # para desactivar notacion cientifica
rm(list = ls()) # para limpiar el entorno de trabajo

Cargamos los datos desde internet.

load(url("https://github.com/cursos-metodos-facso/datos-ejemplos/raw/main/lapop_proc_2018.RData")) #Cargar base de datos

# Un pequeño procesamiento para algunas variables que usaremos más adelante
lapop <- lapop %>% mutate(across(c("gini", "gdp"), ~ as.numeric(.))) 

A continuación, exploramos la base de datos lapop.

names(lapop) # Nombre de columnas
 [1] "year"        "pais"        "pais_name"   "idnum"       "upm"        
 [6] "strata"      "wt"          "weight1500"  "sexo"        "edad"       
[11] "educ"        "l1"          "ideologia_f" "empleo"      "decile"     
[16] "it1"         "prot3"       "aoj12"       "b2"          "b3"         
[21] "b4"          "b10a"        "b12"         "b20"         "b20a"       
[26] "b21"         "b21a"        "n9"          "n11"         "n15"        
[31] "ros4"        "ing4"        "eff1"        "pn4"         "exc7"       
[36] "pol1"        "vb2"         "gini"        "gdp"        
dim(lapop) # Dimensiones
[1] 23386    39

Contamos con 39 variables (columnas) y 23.386 observaciones (filas).

Tablas con Kable

La mejor forma de generar tablas es con la función kable() del paquete knitr y las distintas funciones de formateo que ofrece el paquete kableExtra. Esto se debe a que kable() y las funciones de kableExtra aplican estilo y formato a un objeto de R (generalmente un data.frame). Esto quiere decir que para hacer una tabla debemos:

  1. Procesar nuestros datos de manera que generemos un objeto tipo data.frame (u otros similares) con la información requerida. Esto lo hacemos a través de dplyr o algún otro paquete dedicado al manejo de datos.

  2. Aplicar el estilo y el formateo que queramos para ese objeto. Esto lo hacemos a través de kableExtra (hay otras opciones, por ejemplo flextable).

Ejemplifiquemos con nuestros datos.

Primero, generaremos un objeto llamado tab1 que usaremos como contenido de la tabla. Este objeto tendrá la distribución de it1 (confianza interpersonal) por país, es decir, es una tabla bivariada.

tab1 <- lapop %>%
  group_by(pais, it1) %>% # agrupamos por pais y variable
  summarise(n = n()) %>% # contamos por categ de respuesta
  mutate(prop = round((n / sum(n)) * 100, 2)) %>% # porcentaje
  na.omit() %>% # borramos NA
  pivot_wider(id_cols = pais, names_from = it1, values_from = prop) # convertimos a formato ancho

tab1
# A tibble: 15 × 5
# Groups:   pais [15]
   pais    `1`   `2`   `3`   `4`
   <chr> <dbl> <dbl> <dbl> <dbl>
 1 ARG    7.98  21.7  45.1  23.2
 2 BOL   13.6   40.5  31.9  11.6
 3 BRA   12.9   45.4  19.8  19.8
 4 CHL   10.6   23.4  40.5  24.6
 5 COL    9.14  25.7  34.4  29.0
 6 CRI    8.53  22.6  34.6  32.2
 7 DOM   11.3   29.0  31.3  24.0
 8 ECU   11.7   37.8  32.2  17.3
 9 HND   14.0   28.6  22.8  29.3
10 MEX   11.2   33.2  31.5  20.7
11 PAN   14.2   34    31.5  18.5
12 PER   14.9   42.3  31.2  10.6
13 PRY    9.7   24.1  35.6  26.9
14 SLV    8.6   32.3  26.3  29.2
15 URY    7.08  18.7  43.8  27.1

Creemos nuestra tabla. Usemos primero la función kable() directamente:

tab1 %>% kable()
pais 1 2 3 4
ARG 7.98 21.66 45.09 23.23
BOL 13.56 40.49 31.87 11.59
BRA 12.88 45.39 19.76 19.76
CHL 10.56 23.44 40.54 24.60
COL 9.14 25.74 34.40 28.98
CRI 8.53 22.58 34.64 32.25
DOM 11.28 29.02 31.27 24.01
ECU 11.68 37.83 32.22 17.29
HND 14.04 28.65 22.82 29.29
MEX 11.20 33.16 31.46 20.70
PAN 14.24 34.00 31.49 18.47
PER 14.92 42.34 31.23 10.59
PRY 9.70 24.09 35.64 26.86
SLV 8.60 32.30 26.27 29.19
URY 7.08 18.72 43.77 27.07

Ahora tenemos una tabla, pero es muy simple y poco presentable. Especifiquemos opciones de formato:

  • format: para especificar formato de la tabla (html, markdown, latex)
  • aling: para especificar alineacion de las celdas (‘r’=derecha, ‘c’=centro, ‘l’=izquierda),
  • col.names: para nombres de columnas visibles en la tabla, se ingresan como un vector c()
tab1 %>% 
  kable(
    format = "markdown",
    align = "c",
    col.names = c("País", "Nada confiable", "Poco confiable", "Algo confiable", "Muy confiable"))
País Nada confiable Poco confiable Algo confiable Muy confiable
ARG 7.98 21.66 45.09 23.23
BOL 13.56 40.49 31.87 11.59
BRA 12.88 45.39 19.76 19.76
CHL 10.56 23.44 40.54 24.60
COL 9.14 25.74 34.40 28.98
CRI 8.53 22.58 34.64 32.25
DOM 11.28 29.02 31.27 24.01
ECU 11.68 37.83 32.22 17.29
HND 14.04 28.65 22.82 29.29
MEX 11.20 33.16 31.46 20.70
PAN 14.24 34.00 31.49 18.47
PER 14.92 42.34 31.23 10.59
PRY 9.70 24.09 35.64 26.86
SLV 8.60 32.30 26.27 29.19
URY 7.08 18.72 43.77 27.07

Ahora agregemos otros elementos importantes, como el título, estilo y fuente a la tabla:

  • caption: para dar titulo de la tabla
  • kable_classic(): para dar estilo
  • add_footnote(): para agregar fuente o pie a la tabla
tab1 %>% 
  kable(format = "markdown",
        align = "c",
        col.names = c("País", "Nada confiable", "Poco confiable", "Algo confiable", "Muy confiable"),
        caption = "Tabla 1. Confianza interpersonal según país") %>% 
  kableExtra::kable_classic() %>% 
  kableExtra::add_footnote(label = "Fuente: Elaboración propia en base a LAPOP 2018.")
Tabla 1. Confianza interpersonal según país
País Nada confiable Poco confiable Algo confiable Muy confiable
ARG 7.98 21.66 45.09 23.23
BOL 13.56 40.49 31.87 11.59
BRA 12.88 45.39 19.76 19.76
CHL 10.56 23.44 40.54 24.60
COL 9.14 25.74 34.40 28.98
CRI 8.53 22.58 34.64 32.25
DOM 11.28 29.02 31.27 24.01
ECU 11.68 37.83 32.22 17.29
HND 14.04 28.65 22.82 29.29
MEX 11.20 33.16 31.46 20.70
PAN 14.24 34.00 31.49 18.47
PER 14.92 42.34 31.23 10.59
PRY 9.70 24.09 35.64 26.86
SLV 8.60 32.30 26.27 29.19
URY 7.08 18.72 43.77 27.07
a Fuente: Elaboración propia en base a LAPOP 2018.

¿Muy grande? También podemos ajustar el ancho que ocupa la tabla, el tamaño de la letra y la posición:

  • full_width: para indicar si la tabla cubre todo el ancho o no (TRUE/FALSE)
  • position: para indicar posición de la tabla en el documento
  • font_size: para indicar tamaño de la letra
tabla1 <- tab1 %>% 
  kable(format = "markdown",
                    align = "c",
                    col.names = c("País", "Nada confiable", "Poco confiable", "Algo confiable", "Muy confiable"),
                    caption = "Tabla 1. Confianza interpersonal según país") %>% 
  kableExtra::kable_classic(full_width = FALSE, position = "center", font_size = 14) %>% 
  kableExtra::add_footnote(label = "Fuente: Elaboración propia en base a LAPOP 2018.")

tabla1
Tabla 1. Confianza interpersonal según país
País Nada confiable Poco confiable Algo confiable Muy confiable
ARG 7.98 21.66 45.09 23.23
BOL 13.56 40.49 31.87 11.59
BRA 12.88 45.39 19.76 19.76
CHL 10.56 23.44 40.54 24.60
COL 9.14 25.74 34.40 28.98
CRI 8.53 22.58 34.64 32.25
DOM 11.28 29.02 31.27 24.01
ECU 11.68 37.83 32.22 17.29
HND 14.04 28.65 22.82 29.29
MEX 11.20 33.16 31.46 20.70
PAN 14.24 34.00 31.49 18.47
PER 14.92 42.34 31.23 10.59
PRY 9.70 24.09 35.64 26.86
SLV 8.60 32.30 26.27 29.19
URY 7.08 18.72 43.77 27.07
a Fuente: Elaboración propia en base a LAPOP 2018.

En este caso, nuestro ejemplo fue para hacer una tabla bivariada con dos variables categóricas. Sin embargo, podríamos hacer lo mismo para una variable continua y crear una tabla bivariada con los principales estadisticos descriptivos.

Creemos el objeto tab2, el cual serán los estadísticos descriptivos de la variable edad por país en nuestra base de datos.

::: {.cell}

tab2 <- lapop %>% 
   group_by(pais) %>% 
   summarise(
       n = n(), # Tamaño muestral
       min = min(edad, na.rm = T), # Mínimo
       max = max(edad, na.rm = T), # Máximo
       media = round(mean(edad, na.rm = T), 2), # Media redondeada a 2 digitos
       sd = round(sd(edad, na.rm = T), 2), # Desviación estándar redondeada a 2 digitos
       mediana = median(edad, na.rm = T), # Mediana
       cv = round((media/sd)*100, 2) # Coeficiente de variación redondeado a 2 digi
       )

:::

Y ahora apliquemos el formato con kable() y las funcionalidades del paquete de kableExtra:

tabla2 <- tab2 %>% 
  kable(format = "markdown",
                    align = "c",
                    col.names = c("País", "Tamaño muestral", "Mínimo", "Máximo", "Media", "Desv. estándar", "Mediana", "Coef. variación"),
                    caption = "Tabla 2. Edad según país") %>% 
  kableExtra::kable_classic(full_width = FALSE, position = "center", font_size = 14) %>% 
  kableExtra::add_footnote(label = "Fuente: Elaboración propia en base a LAPOP 2018.")

tabla2
Tabla 2. Edad según país
País Tamaño muestral Mínimo Máximo Media Desv. estándar Mediana Coef. variación
ARG 1528 16 90 41.84 17.75 39.0 235.72
BOL 1682 18 89 39.52 16.30 36.0 242.45
BRA 1498 16 92 39.15 16.25 37.0 240.92
CHL 1638 18 92 42.22 16.80 40.0 251.31
COL 1663 18 90 40.36 16.33 37.0 247.15
CRI 1501 18 89 40.50 16.88 37.0 239.93
DOM 1516 18 87 40.05 16.98 37.0 235.87
ECU 1533 16 92 38.16 17.10 35.0 223.16
HND 1560 18 89 38.17 16.26 34.0 234.75
MEX 1580 18 88 42.09 17.03 40.0 247.15
PAN 1559 18 93 39.56 16.17 37.5 244.65
PER 1521 18 91 38.85 15.54 36.0 250.00
PRY 1515 18 87 40.00 16.28 37.0 245.70
SLV 1511 18 99 39.99 16.62 38.0 240.61
URY 1581 18 95 46.19 17.89 44.0 258.19
a Fuente: Elaboración propia en base a LAPOP 2018.

Para ver todas las funcionalidades y estilos que se pueden generar con kableExtra, ver aquí.

Tablas con otros paquetes

Si bien la combinación de crear nuestra tabla (probablemente con dplyr) y formatear con kableExtra es la mejor forma para reportar tablas, existen otras funciones. Las funciones varían de acuerdo a qué es lo que se quiere reportar, es decir, si es una variable categorica o númerica y si es el reporte debe ser univariado o bivariado. De todos modos, solo algunas funciones tienen una salida directa en HTML (pensando en que se utilizarán en Quarto), por lo que algunas veces solo nos ahorraremos el procesamiento, el formateo deberemos hacerlo igual.

La principal virtud de estas funciones es que nos ahorra hacer el procesamiento de la tabla. Sin embargo, el desafío es que debemos saber bien qué es lo que queremos reportar para utilizar la función adecuada.

A continuación, presentaremos algunas de las funcionas más conocidas, dividiendo si son para tablas univariadas o bivariadas.

Vamos a crear una versión recortada de lapop para ejemplifcar cada función:

# Creemos una version de lapop solo con algunas variables como ejemplo
data_example <- lapop %>% 
  select(pais, it1, edad, sexo, gini, gdp)

Funciones para tablas univariadas

Estas tablas suelen incluir estadísticas descriptivas de una sola variable como medias, medianas, desviaciones estándar, entre otras.

summarytools:

  • summarytools::dfSummary(): Genera un resumen univariado completo de cada variable en el dataset, con estadísticas, frecuencia de valores y gráficos.
summarytools::dfSummary(data_example) %>% 
  summarytools::view(method = "render") 

Data Frame Summary

summarytools::dfSummary

Dimensions: 23386 x 6
Duplicates: 16464
No Variable Label Stats / Values Freqs (% of Valid) Graph Valid Missing
1 pais [character] País
1. BOL
2. COL
3. CHL
4. URY
5. MEX
6. HND
7. PAN
8. ECU
9. ARG
10. PER
[ 5 others ]
1682 ( 7.2% )
1663 ( 7.1% )
1638 ( 7.0% )
1581 ( 6.8% )
1580 ( 6.8% )
1560 ( 6.7% )
1559 ( 6.7% )
1533 ( 6.6% )
1528 ( 6.5% )
1521 ( 6.5% )
7541 ( 32.2% )
23386 (100.0%) 0 (0.0%)
2 it1 [numeric] Confianza Interpersonal
Mean (sd) : 2.7 (1)
min ≤ med ≤ max:
1 ≤ 3 ≤ 4
IQR (CV) : 1 (0.4)
1 : 2580 ( 11.3% )
2 : 7157 ( 31.4% )
3 : 7693 ( 33.8% )
4 : 5353 ( 23.5% )
22783 (97.4%) 603 (2.6%)
3 edad [numeric] Edad
Mean (sd) : 40.5 (16.8)
min ≤ med ≤ max:
16 ≤ 38 ≤ 99
IQR (CV) : 25 (0.4)
81 distinct values 23372 (99.9%) 14 (0.1%)
4 sexo [factor] Sexo
1. Hombre
2. Mujer
11634 ( 49.8% )
11739 ( 50.2% )
23373 (99.9%) 13 (0.1%)
5 gini [numeric]
Mean (sd) : 45.8 (4)
min ≤ med ≤ max:
38 ≤ 45.7 ≤ 53.3
IQR (CV) : 6.1 (0.1)
15 distinct values 23386 (100.0%) 0 (0.0%)
6 gdp [numeric]
Mean (sd) : 8.7 (4.3)
min ≤ med ≤ max:
2.5 ≤ 8 ≤ 16
IQR (CV) : 7.2 (0.5)
15 distinct values 23386 (100.0%) 0 (0.0%)

Generated by summarytools 1.0.1 (R version 4.3.2)
2025-11-03

  • summarytools::descr(): Proporciona estadísticas descriptivas para variables numéricas.
summarytools::descr(data_example$edad) %>%
  summarytools::view(method = "render")
Error : Can't find summarytools

Descriptive Statistics

value

Label: Edad
N: 23386
value
Mean 40.46
Std.Dev 16.80
Min 16.00
Q1 27.00
Median 38.00
Q3 52.00
Max 99.00
MAD 17.79
IQR 25.00
CV 0.42
Skewness 0.57
SE.Skewness 0.02
Kurtosis -0.58
N.Valid 23372
Pct.Valid 99.94

Generated by summarytools 1.0.1 (R version 4.3.2)
2025-11-03

stargazer:

  • stargazer::stargazer(): Para reportar estadísticas descriptivas.
stargazer(as.data.frame(data_example), type = "text", summary.stat = c("mean", "sd", "min", "max"))
Statistic Mean St. Dev. Min Max
it1 2.694 0.953 1 4
edad 40.461 16.798 16 99
gini 45.778 4.043 38.000 53.300
gdp 8.748 4.278 2.475 16.038

psych:

  • psych::describe(): Calcula estadísticas descriptivas adicionales, como curtosis y asimetría.
psych::describe(data_example) %>%
  kable() %>%
  kable_styling(full_width = TRUE)
vars n mean sd median trimmed mad min max range skew kurtosis se
pais* 1 23386 7.950911 4.3253391 8.000000 7.935810 5.930400 1.00000 15.00000 14.00000 0.0201754 -1.2152000 0.0282841
it1 2 22783 2.694333 0.9532423 3.000000 2.742909 1.482600 1.00000 4.00000 3.00000 -0.1424032 -0.9507169 0.0063154
edad 3 23372 40.460551 16.7983821 38.000000 39.158199 17.791200 16.00000 99.00000 83.00000 0.5674996 -0.5770780 0.1098802
sexo* 4 23373 1.502246 0.5000057 2.000000 1.502808 0.000000 1.00000 2.00000 1.00000 -0.0089842 -2.0000048 0.0032705
gini 5 23386 45.777846 4.0429160 45.700000 45.896141 4.151280 38.00000 53.30000 15.30000 -0.2035078 -0.6251471 0.0264373
gdp 6 23386 8.747801 4.2779214 7.997761 8.634054 6.045964 2.47517 16.03793 13.56276 0.2534969 -1.2525404 0.0279740

sjmisc:

  • sjmisc::frq(): Para tablas de frecuencias detalladas de variables categóricas. Incluye labels.
sjmisc::frq(data_example$it1) %>%
  kable() 
val label frq raw.prc valid.prc cum.prc
1 Nada confiable 2580 11.03 11.32 11.32
2 Poco confiable 7157 30.60 31.41 42.74
3 Algo confiable 7693 32.90 33.77 76.50
4 Muy confiable 5353 22.89 23.50 100.00
NA NA 603 2.58 NA NA

table1:

  • table1::table1(): Permite ver tanto variables categoricas como numericas en la misma tabla de manera estética
table1::table1(~ factor(sexo) + edad + gini + gdp, data = data_example)
Overall
(N=23386)
factor(sexo)
Hombre 11634 (49.7%)
Mujer 11739 (50.2%)
Missing 13 (0.1%)
Edad
Mean (SD) 40.5 (16.8)
Median [Min, Max] 38.0 [16.0, 99.0]
Missing 14 (0.1%)
gini
Mean (SD) 45.8 (4.04)
Median [Min, Max] 45.7 [38.0, 53.3]
gdp
Mean (SD) 8.75 (4.28)
Median [Min, Max] 8.00 [2.48, 16.0]

Funciones para tablas bivariadas

Las tablas bivariadas permiten explorar relaciones entre pares de variables, útiles para comparar medias o analizar frecuencias conjuntas en tablas de contingencia.

sjPlot:

  • sjPlot::tab_xtab(): Produce tablas cruzadas de frecuencias y porcentajes, y es útil para comparar variables categóricas entre grupos.
sjPlot::tab_xtab(data_example$pais, data_example$it1, show.row.prc = TRUE)
País Confianza
Interpersonal
Total
Nada confiable Poco confiable Algo confiable Muy confiable
ARG 122
8.1 %
331
22.1 %
689
46 %
355
23.7 %
1497
100 %
BOL 228
13.9 %
681
41.5 %
536
32.7 %
195
11.9 %
1640
100 %
BRA 193
13.2 %
680
46.4 %
296
20.2 %
296
20.2 %
1465
100 %
CHL 173
10.7 %
384
23.6 %
664
40.9 %
403
24.8 %
1624
100 %
COL 152
9.3 %
428
26.2 %
572
35 %
482
29.5 %
1634
100 %
CRI 128
8.7 %
339
23 %
520
35.4 %
484
32.9 %
1471
100 %
DOM 171
11.8 %
440
30.4 %
474
32.7 %
364
25.1 %
1449
100 %
ECU 179
11.8 %
580
38.2 %
494
32.5 %
265
17.5 %
1518
100 %
HND 219
14.8 %
447
30.2 %
356
24.1 %
457
30.9 %
1479
100 %
MEX 177
11.6 %
524
34.4 %
497
32.6 %
327
21.4 %
1525
100 %
PAN 222
14.5 %
530
34.6 %
491
32.1 %
288
18.8 %
1531
100 %
PER 227
15.1 %
644
42.7 %
475
31.5 %
161
10.7 %
1507
100 %
PRY 147
10.1 %
365
25 %
540
37 %
407
27.9 %
1459
100 %
SLV 130
8.9 %
488
33.5 %
397
27.3 %
441
30.3 %
1456
100 %
URY 112
7.3 %
296
19.4 %
692
45.3 %
428
28 %
1528
100 %
Total 2580
11.3 %
7157
31.4 %
7693
33.8 %
5353
23.5 %
22783
100 %
χ2=1306.960 · df=42 · Cramer's V=0.138 · p=0.000

summarytools:

  • summarytools::ctable(): Para tablas de contingencia que incluyen porcentajes y frecuencias, con opciones de personalización.
summarytools::ctable(data_example$pais, data_example$sexo) %>% 
  summarytools::view(method = "viewer")
Error : Can't find summarytools
Error : Can't find summarytools

Cross-Tabulation, Row Proportions

data_example$pais * data_example$sexo

data_example$sexo
data_example$pais Hombre Mujer <NA> Total
ARG 758 ( 49.6% ) 770 ( 50.4% ) 0 ( 0.00% ) 1528 ( 100.0% )
BOL 846 ( 50.3% ) 836 ( 49.7% ) 0 ( 0.00% ) 1682 ( 100.0% )
BRA 748 ( 49.9% ) 750 ( 50.1% ) 0 ( 0.00% ) 1498 ( 100.0% )
CHL 813 ( 49.6% ) 824 ( 50.3% ) 1 ( 0.06% ) 1638 ( 100.0% )
COL 830 ( 49.9% ) 833 ( 50.1% ) 0 ( 0.00% ) 1663 ( 100.0% )
CRI 750 ( 50.0% ) 751 ( 50.0% ) 0 ( 0.00% ) 1501 ( 100.0% )
DOM 753 ( 49.7% ) 761 ( 50.2% ) 2 ( 0.13% ) 1516 ( 100.0% )
ECU 760 ( 49.6% ) 764 ( 49.8% ) 9 ( 0.59% ) 1533 ( 100.0% )
HND 778 ( 49.9% ) 782 ( 50.1% ) 0 ( 0.00% ) 1560 ( 100.0% )
MEX 775 ( 49.1% ) 805 ( 50.9% ) 0 ( 0.00% ) 1580 ( 100.0% )
PAN 782 ( 50.2% ) 777 ( 49.8% ) 0 ( 0.00% ) 1559 ( 100.0% )
PER 758 ( 49.8% ) 762 ( 50.1% ) 1 ( 0.07% ) 1521 ( 100.0% )
PRY 755 ( 49.8% ) 760 ( 50.2% ) 0 ( 0.00% ) 1515 ( 100.0% )
SLV 755 ( 50.0% ) 756 ( 50.0% ) 0 ( 0.00% ) 1511 ( 100.0% )
URY 773 ( 48.9% ) 808 ( 51.1% ) 0 ( 0.00% ) 1581 ( 100.0% )
Total 11634 ( 49.7% ) 11739 ( 50.2% ) 13 ( 0.06% ) 23386 ( 100.0% )

Generated by summarytools 1.0.1 (R version 4.3.2)
2025-11-03

crosstable:

  • crosstable::crosstable(): También produce tablas de continencia con opciones de personalización.
crosstable::crosstable(data_example, pais, by = sexo, margin=c("row", "col"), total = "both") %>% 
  kable() %>%
  kable_styling(full_width = TRUE)
.id label variable Hombre Mujer NA Total
pais País ARG 758 (6.52% / 49.61%) 770 (6.56% / 50.39%) 0 1528 (6.53%)
pais País BOL 846 (7.27% / 50.30%) 836 (7.12% / 49.70%) 0 1682 (7.19%)
pais País BRA 748 (6.43% / 49.93%) 750 (6.39% / 50.07%) 0 1498 (6.41%)
pais País CHL 813 (6.99% / 49.66%) 824 (7.02% / 50.34%) 1 1638 (7.00%)
pais País COL 830 (7.13% / 49.91%) 833 (7.10% / 50.09%) 0 1663 (7.11%)
pais País CRI 750 (6.45% / 49.97%) 751 (6.40% / 50.03%) 0 1501 (6.42%)
pais País DOM 753 (6.47% / 49.74%) 761 (6.48% / 50.26%) 2 1516 (6.48%)
pais País ECU 760 (6.53% / 49.87%) 764 (6.51% / 50.13%) 9 1533 (6.56%)
pais País HND 778 (6.69% / 49.87%) 782 (6.66% / 50.13%) 0 1560 (6.67%)
pais País MEX 775 (6.66% / 49.05%) 805 (6.86% / 50.95%) 0 1580 (6.76%)
pais País PAN 782 (6.72% / 50.16%) 777 (6.62% / 49.84%) 0 1559 (6.67%)
pais País PER 758 (6.52% / 49.87%) 762 (6.49% / 50.13%) 1 1521 (6.50%)
pais País PRY 755 (6.49% / 49.83%) 760 (6.47% / 50.17%) 0 1515 (6.48%)
pais País SLV 755 (6.49% / 49.97%) 756 (6.44% / 50.03%) 0 1511 (6.46%)
pais País URY 773 (6.64% / 48.89%) 808 (6.88% / 51.11%) 0 1581 (6.76%)
pais País Total 11634 (49.78%) 11739 (50.22%) 13 23386 (100.00%)

table1:

  • table1::table1(): También se puede utilizar agrupando las variables (numericas o categoricas) por alguna variable categórica.
table1::table1(~ factor(sexo) + edad + gini + gdp | pais, data = data_example)
ARG
(N=1528)
BOL
(N=1682)
BRA
(N=1498)
CHL
(N=1638)
COL
(N=1663)
CRI
(N=1501)
DOM
(N=1516)
ECU
(N=1533)
HND
(N=1560)
MEX
(N=1580)
PAN
(N=1559)
PER
(N=1521)
PRY
(N=1515)
SLV
(N=1511)
URY
(N=1581)
Overall
(N=23386)
factor(sexo)
Hombre 758 (49.6%) 846 (50.3%) 748 (49.9%) 813 (49.6%) 830 (49.9%) 750 (50.0%) 753 (49.7%) 760 (49.6%) 778 (49.9%) 775 (49.1%) 782 (50.2%) 758 (49.8%) 755 (49.8%) 755 (50.0%) 773 (48.9%) 11634 (49.7%)
Mujer 770 (50.4%) 836 (49.7%) 750 (50.1%) 824 (50.3%) 833 (50.1%) 751 (50.0%) 761 (50.2%) 764 (49.8%) 782 (50.1%) 805 (50.9%) 777 (49.8%) 762 (50.1%) 760 (50.2%) 756 (50.0%) 808 (51.1%) 11739 (50.2%)
Missing 0 (0%) 0 (0%) 0 (0%) 1 (0.1%) 0 (0%) 0 (0%) 2 (0.1%) 9 (0.6%) 0 (0%) 0 (0%) 0 (0%) 1 (0.1%) 0 (0%) 0 (0%) 0 (0%) 13 (0.1%)
Edad
Mean (SD) 41.8 (17.8) 39.5 (16.3) 39.1 (16.2) 42.2 (16.8) 40.4 (16.3) 40.5 (16.9) 40.0 (17.0) 38.2 (17.1) 38.2 (16.3) 42.1 (17.0) 39.6 (16.2) 38.8 (15.5) 40.0 (16.3) 40.0 (16.6) 46.2 (17.9) 40.5 (16.8)
Median [Min, Max] 39.0 [16.0, 90.0] 36.0 [18.0, 89.0] 37.0 [16.0, 92.0] 40.0 [18.0, 92.0] 37.0 [18.0, 90.0] 37.0 [18.0, 89.0] 37.0 [18.0, 87.0] 35.0 [16.0, 92.0] 34.0 [18.0, 89.0] 40.0 [18.0, 88.0] 37.5 [18.0, 93.0] 36.0 [18.0, 91.0] 37.0 [18.0, 87.0] 38.0 [18.0, 99.0] 44.0 [18.0, 95.0] 38.0 [16.0, 99.0]
Missing 0 (0%) 0 (0%) 0 (0%) 1 (0.1%) 0 (0%) 0 (0%) 2 (0.1%) 9 (0.6%) 0 (0%) 0 (0%) 1 (0.1%) 1 (0.1%) 0 (0%) 0 (0%) 0 (0%) 14 (0.1%)
gini
Mean (SD) 41.1 (0) 44.6 (0) 53.3 (0) 44.4 (0) 49.7 (0) 48.3 (0) 45.7 (0) 44.7 (0) 49.4 (0) 46.3 (0) 49.9 (0) 43.3 (0) 48.5 (0) 38.0 (0) 39.5 (0) 45.8 (4.04)
Median [Min, Max] 41.1 [41.1, 41.1] 44.6 [44.6, 44.6] 53.3 [53.3, 53.3] 44.4 [44.4, 44.4] 49.7 [49.7, 49.7] 48.3 [48.3, 48.3] 45.7 [45.7, 45.7] 44.7 [44.7, 44.7] 49.4 [49.4, 49.4] 46.3 [46.3, 46.3] 49.9 [49.9, 49.9] 43.3 [43.3, 43.3] 48.5 [48.5, 48.5] 38.0 [38.0, 38.0] 39.5 [39.5, 39.5] 45.7 [38.0, 53.3]
gdp
Mean (SD) 13.1 (0) 3.29 (0) 8.58 (0) 13.9 (0) 6.27 (0) 12.5 (0) 8.00 (0) 5.95 (0) 2.48 (0) 9.95 (0) 14.9 (0) 6.57 (0) 5.87 (0) 3.92 (0) 16.0 (0) 8.75 (4.28)
Median [Min, Max] 13.1 [13.1, 13.1] 3.29 [3.29, 3.29] 8.58 [8.58, 8.58] 13.9 [13.9, 13.9] 6.27 [6.27, 6.27] 12.5 [12.5, 12.5] 8.00 [8.00, 8.00] 5.95 [5.95, 5.95] 2.48 [2.48, 2.48] 9.95 [9.95, 9.95] 14.9 [14.9, 14.9] 6.57 [6.57, 6.57] 5.87 [5.87, 5.87] 3.92 [3.92, 3.92] 16.0 [16.0, 16.0] 8.00 [2.48, 16.0]

dplyr y janitor:

  • dplyr + janitor::tabyl(): Puedes hacer resúmenes bivariados personalizados con count() o group_by(), y tabyl() genera tablas de contingencia de frecuencias para un vistazo rápido.
data_example %>%
  janitor::tabyl(pais, it1) %>% # Esto reemplaza el procesamiento, buena alternativa
  kable() %>%
  kable_styling(full_width = TRUE)
pais 1 2 3 4 NA_
ARG 122 331 689 355 31
BOL 228 681 536 195 42
BRA 193 680 296 296 33
CHL 173 384 664 403 14
COL 152 428 572 482 29
CRI 128 339 520 484 30
DOM 171 440 474 364 67
ECU 179 580 494 265 15
HND 219 447 356 457 81
MEX 177 524 497 327 55
PAN 222 530 491 288 28
PER 227 644 475 161 14
PRY 147 365 540 407 56
SLV 130 488 397 441 55
URY 112 296 692 428 53

Resumen

Hoy aprendimos a generar y presentar tablas . En detalle, aprendímos:

  1. Generación y presentación de tablas en Quarto a través de kable() y kableExtra
  2. Otras opciones de tablas rapidas para distintos tipos de análisis

Ejercicio autónomo

El objetivo de este ejercicio es que generes al menos dos tablas utilizando la base lapop trabajada en la práctica, aplicando lo aprendido sobre procesamiento de datos y formateo de tablas

Tabla 1 — Bivariada categórica

  1. Elige un formato de tabla que permita visualizar el cruce entre las variables prot3 (participación en protestas) y decile (deciles de ingreso).
  2. Elabora la tabla con nombres de columnas y filas en español y con formato legible.
  3. Incorporar un título (caption) y una nota de pie de tabla.
tab <- lapop %>%
  group_by(decile, prot3) %>% # agrupamos por decile y variable
  summarise(n = n()) %>% # contamos por categ de respuesta
  mutate(prop = round((n / sum(n)) * 100, 2)) %>% # porcentaje
  na.omit() %>% # borramos NA
  pivot_wider(id_cols = decile, names_from = prot3, values_from = prop) # convertimos a formato ancho
`summarise()` has grouped output by 'decile'. You can override using the
`.groups` argument.
tab
# A tibble: 10 × 3
# Groups:   decile [10]
   decile    Sí    No
    <int> <dbl> <dbl>
 1      1  9.04  90.7
 2      2  8.55  91.3
 3      3  8.07  91.6
 4      4  8.68  91.2
 5      5  8.59  91.3
 6      6 10.0   90.0
 7      7 10.5   89.3
 8      8 11.9   87.9
 9      9 12.2   87.7
10     10 15.8   83.9
tabla1 <- tab %>% 
  kable(format = "markdown",
                    align = "c",
                    col.names = c("Decil de ingreso", "Sí ha protestado", "No ha protestado"),
                    caption = "Tabla 1. Frecuencia de protesta según decil de ingreso") %>% 
  kableExtra::kable_classic(full_width = FALSE, position = "center", font_size = 14) %>% 
  kableExtra::add_footnote(label = "Fuente: Elaboración propia en base a LAPOP 2018.")

tabla1
Tabla 1. Frecuencia de protesta según decil de ingreso
Decil de ingreso Sí ha protestado No ha protestado
1 9.04 90.71
2 8.55 91.30
3 8.07 91.63
4 8.68 91.22
5 8.59 91.26
6 10.02 89.98
7 10.53 89.27
8 11.87 87.88
9 12.23 87.67
10 15.84 83.91
a Fuente: Elaboración propia en base a LAPOP 2018.

Tabla 2 - Bivariada con estadísticos descriptivos

  1. Resume la relación (estadísticos descriptivos) de la variable b21 (confianza en partidos políticos) y pais.
  2. Elige un formato de tabla que permita visualizar el cruce entre las variables b21 (confianza en partidos políticos) y pais.
  3. La tabla debe reportar: n, media, desviación estándar, mínimo, máximo y mediana.
  4. Debe estar formateada visualmente (con kableExtra u otro paquete de tu elección).
tab2 <- lapop %>% 
   group_by(pais) %>% 
   summarise(
       n = n(), # Tamaño muestral
       min = min(b21, na.rm = T), # Mínimo
       max = max(b21, na.rm = T), # Máximo
       media = round(mean(b21, na.rm = T), 2), # Media redondeada a 2 digitos
       sd = round(sd(b21, na.rm = T), 2), # Desviación estándar redondeada a 2 digitos
       mediana = median(b21, na.rm = T), # Mediana
       cv = round((media/sd)*100, 2) # Coeficiente de variación redondeado a 2 digi
       )

tab2
# A tibble: 15 × 8
   pais      n   min   max media    sd mediana    cv
   <chr> <int> <dbl> <dbl> <dbl> <dbl>   <dbl> <dbl>
 1 ARG    1528     1     7  2.65  1.64       2  162.
 2 BOL    1682     1     7  2.66  1.61       2  165.
 3 BRA    1498     1     7  2.39  1.7        2  141.
 4 CHL    1638     1     7  2.41  1.48       2  163.
 5 COL    1663     1     7  2.65  1.57       2  169.
 6 CRI    1501     1     7  2.67  1.6        2  167.
 7 DOM    1516     1     7  2.7   1.89       2  143.
 8 ECU    1533     1     7  2.94  1.69       3  174.
 9 HND    1560     1     7  2.49  1.77       2  141.
10 MEX    1580     1     7  2.99  1.82       3  164.
11 PAN    1559     1     7  2.34  1.64       2  143.
12 PER    1521     1     7  2.27  1.39       2  163.
13 PRY    1515     1     7  2.92  1.77       3  165.
14 SLV    1511     1     7  2.73  1.71       2  160.
15 URY    1581     1     7  3.11  1.76       3  177.

::: {.cell}

tabla2 <- tab2 %>% 
kable(format = "markdown",
                  align = "c",
                  col.names = c("País", "Tamaño muestral", "Mínimo", "Máximo", "Media", "Desv. estándar", "Mediana", "Coef. variación"),
                  caption = "Tabla 2. Confianza en partidos políticos según país") %>% 
kableExtra::kable_classic(full_width = FALSE, position = "center", font_size = 14) %>% 
kableExtra::add_footnote(label = "Fuente: Elaboración propia en base a LAPOP 2018.")

tabla2
::: {.cell-output-display} `````{=html}
Tabla 2. Confianza en partidos políticos según país
País Tamaño muestral Mínimo Máximo Media Desv. estándar Mediana Coef. variación
ARG 1528 1 7 2.65 1.64 2 161.59
BOL 1682 1 7 2.66 1.61 2 165.22
BRA 1498 1 7 2.39 1.70 2 140.59
CHL 1638 1 7 2.41 1.48 2 162.84
COL 1663 1 7 2.65 1.57 2 168.79
CRI 1501 1 7 2.67 1.60 2 166.88
DOM 1516 1 7 2.70 1.89 2 142.86
ECU 1533 1 7 2.94 1.69 3 173.96
HND 1560 1 7 2.49 1.77 2 140.68
MEX 1580 1 7 2.99 1.82 3 164.29
PAN 1559 1 7 2.34 1.64 2 142.68
PER 1521 1 7 2.27 1.39 2 163.31
PRY 1515 1 7 2.92 1.77 3 164.97
SLV 1511 1 7 2.73 1.71 2 159.65
URY 1581 1 7 3.11 1.76 3 176.70
a Fuente: Elaboración propia en base a LAPOP 2018.

````` ::: :::