3 Tablas marginales

3.1 Una pequeña introducción

Vamos a comenzar explicando un poco qué es expssy su similitud nominal con IBM SPSS. expss es un paquete desarrollado por Demin (2020) que calcula y muestra tablas de todo tipo, con soporte para etiquetas con estilo SPSS y con gran facilidad y flexibilidad para obtener cabeceras múltiples y anidadas, pesos, variables de respuesta múltiple y pruebas de significación de tabla y celda. Ofrece facilidades para una salida formateada de tablas, e incluso, aunque no es objeto de este manual la posibilidad de exportación de esas tablas a EXCEL con el paquete openxlsx. Los métodos para variables etiquetadas agregan soporte de etiquetas de valor a las funciones de R base y a algunas funciones de otros paquetes. Es un paquete destinado a ayudar a los analistas a cambiar el proceso de datos desde EXCEL y SPSS hasta R.

Aquí dejo algunos enlaces para que puedas leer acerca de este paquete y las posibilidades que te ofrece de modo combinado con R Studio:

Vamos a crear nuestra primera tabla utilizando una instrucción muy básica de expss, que evolucionará en posteriores secciones. La que vas a ver seguidamente es la forma básica de pedir que se calcule la media de la variable PESO usando expss; le indicamos:

  • la instrucción de cálculo calculate;
  • el marco de datos a usar, data;
  • y el cálculo a hacer cro_mean (equivalente a calcula la media mean) en forma de tabla.

Así pues, crea un fichero R MarkDown como vimos en la sección 2, y escribe este código (o mejor copy&paste) y obtén el resultado …

setwd("~/R/r-projects/00.tables") # esta es la carpeta donde almacené el archivo (en una subcarpeta llamada data)
library(expss) #cargamos el paquete
data <- read_spss("data/3192.sav") #cargamos los datos
## re-encoding from UTF-8
## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE

## Warning in type.convert.default(val_labs, numerals = "no.loss"): 'as.is' should
## be specified by the caller; using TRUE
calculate(data, cro_mean(PESO)) #hacemos el cálculo
 #Total 
 Ponderación  1

Verás algunos cambios respecto a la salida anterior pues no hemos indicado cuántos decimales, ni que redondeo, ni le hemos dicho que no tenga en cuenta los valores especiales o nulos… y ha respondido de forma correcta.

Ya vamos viendo que eso puede dar mucho juego, pero vamos a ir de forma ordenada y presentando poco a poco todos los tipos de tabla jugando con diferentes variables del banco de datos (¡¡¡ sí… dataframe!!!) que hemos cargado. Comenzaremos con la creación de tablas unidimensionales o conocidas como marginales, para luego continuar con las tablas cruzadas (sección @fig(tse04)), y entre medio, iremos incorporando medidas estadísticas.

Vamos a comenzar con un conjunto de tablas muy sencillas. En ellas representaremos los valores obtenidos del análisis de un campo extraído de nuestra fuente de datos de referencia, la tercera oleada del Barómetro Sanitario en España de 2017 del realizado y publicado por el CIS. Por ahora, trabajaremos sólo con la variable denominada P31 (sexo del entrevistado), variable medida en escala nominal, cuyas etiquetas (valores) son hombre (1) y mujer (2) y con la variable P3, escala de satisfacción (1-10) con el funcionamiento del sistema sanitario español, medida de 1 a 10. En nuestra fuente de datos tenemos 2557 casos (entrevistas realizadas). Puedes ver estas preguntas en el cuestionario PDF que puedes bajar en la sección @fig(tse02).

Utilizaremos un script, es decir una pocas líneas de código que mostraremos en este mismo documento con un fondo gris y que lo hemos llamado chunk. Lo que quede fuera de ese trozo del documento (por arriba o por abajo), será como este texto que estoy escribiendo. Este texto que además, puede ser formateado como si de un HTML se tratará, es lo que llamamos un archivo _markdown_, y como es de R, pues lo llamamos _R Markdown_. Verás que también este documento tiene títulos, que se obtienen anteponiendo el símbolo # desde 1 vez hasta 6 veces y que se corresponde con las etiquetas de título de HTML. Inicialmente, comentaremos las líneas del script utilizando el también el mismo símbolo, pero no al inicio de la línea sino al final Lo que quede por detrás de él, se considera un comentario.

3.2 Frecuencias

Este conjunto de tablas sólo trabajará con el estadístico de cálculo de frecuencias. Comenzaremos con variables de respuesta simple, para luego avanzar a las variables de respuesta múltiple y al uso de medidas estadísticas básicas (suma, media, mediana, máximo, mínimo, etc.).

3.2.1 Variables de respuesta simple

3.2.1.1 Cálculo de frecuencias (estilo SPSS)

Utilizaremos en estos ejemplos de forma inicial un campo del marco de datos, P31, de respuesta simple. La primera tabla que haremos responde a un recuento de frecuencias, y es muy usada para el análisis univariante de una campo. Este comando muestra una tabla básica utilizando la función fre() que copia la salida del SPSS. Nótese que la columna de porcentaje válido y porcentaje es igual ante la inexistencia de NA (valores perdidos).

tab <- fre(data$P31)
as.datatable_widget(tab)

Figura 3.1: Frecuencias marginales de P31, estilo SPSS

Alternativamente se puede presentar la forma que trabajaremos a lo largo de este curso, esta forma es la denominada script encadenado, donde definimos el marco de datos al inicio, y encadenamos instrucciones con el símbolo %>% que irían línea a línea sucesivamente para una mejor lectura y comprensión del texto escrito; podrían perfectamente ir en una línea. Nótese que la tabla sale igual con las dos formas, pero mientras que en el primer caso se usa la nomenclatura estándar de R, y el campo se llama data$P31, es decir nombre del marco de datos en R (data) el símbolo del $ que separa y nombre del campo en el marco de datos P31 en la segunda al definir de inicio que se utilizará data ya se usa el nombre P31 directamente, aunque debamos dar la orden de cálculo con el comando calculate().

as.datatable_widget(data %>%  
  calculate(fre(P31)))

Figura 3.2: Frecuencias marginalesde P31 en tabla

Veamos ahora cómo solicitaremos tablas de frecuencias, porcentajes y estadísticos simples con R.

3.2.1.2 Tablas de frecuencias (absolutos)

La segunda tabla que vamos a hacer, ya responde a la típica presentación de una tabla de contingencia, sólo que en este casos vamos a mostrar sólo un campo y por tanto no va a haber cruce de variables. En el paquete expss, para construir un cuadro deberemos indicar al menos:

  • un marco de datos (dataframe en nomenclatura R)
  • referenciar la variable sobre la que se deben calcular el estadístico seleccionado (frecuencia -casos-, media, mediana, máximo, mínimo…)
  • una orden de impresión de tabla

Estos elementos básicos pueden completarse con campos de columnas, campos de filas, pruebas de significación, etc. Iremos desarrollando estos conceptos a lo largo de este documento. ¡Vamos a por el cuadro!

La que ahora entregamos, es la estructura básica de un script de R con el paquete expss. A lo largo del documento veremos cómo ir introduciendo mínimas variaciones a esta estructura que te permitirán descubrir un sinnúmero de posibilidades que ofrece este paquete de R. Por ejemplo, podemos modificar la etiqueta de TOTAL o indicar donde debe situarse la fila que contiene el cálculo TOTAL. Todas estas posibilidades las puedes conocer en la documentación original del package, aunque en este manual trataremos de ir desgranado las más relevantes para nuestro objetivo. Inicialmente iremos añadiendo tras el operador %>% comentarios precedidos por el símbolo #. Estos comentarios irán desapareciendo a medida que avancemos en el manual, y sólo se recurrirá a ellos cuando se aporte alguna nueva funcionalidad.

Para este primer script, indicaremos que usamos la fuente de datos (dataframe) ya cargado en el análisis. En R Studio, el dataframe tendrá el nombre que le hayas indicado en la carga -en nuestro caso data-. Redactamos pues nuestro script, donde identificamos el dataframe, el campo P31 del cual vamos a calcular el número de casos:

as.datatable_widget(data %>%
  tab_cells(P31) %>%
  tab_stat_cases() %>%
  tab_pivot())

Figura 3.3: Frecuencias de P31

Realicemos ahora una pequeña pero importante variación en el cálculo del estadístico casos -frecuencias- y utilicemos la posibilidad de ubicar donde queramos el total de casos, así como su etiqueta. Ello lo hacemos con total_row_position = "above", label = "Casos" aplicado a la función tab_stat_cases().

as.datatable_widget(data %>% 
  tab_cells(P31) %>% 
  tab_stat_cases(total_row_position = "above", label = "Casos") %>%
  tab_pivot())

Figura 3.4: Frecuencias de P31, moviendo el Total

3.2.1.3 Tablas de frecuencias relativas

Si en lugar de obtener casos (valores absolutos) queremos sacar valores porcentuales, el cambio es mínimo. Usaremos el comando tab_stat_cpct()para indicarlo.

as.datatable_widget(data %>% 
  tab_cells(P31) %>% 
  tab_stat_cpct(total_row_position = "above", label = "% casos") %>% 
  tab_pivot())

Figura 3.5: Porcentajes de P31

3.2.1.4 Tablas de absolutos y realativos (juntos)

Cuando deseamos hacer combinaciones de frecuencias y porcentajes, la filosofía de trabajo es muy parecida. En nuestro caso vamos a hacer algo muy típico. Aunque creo que resulta más sencillo leer cada estadístico en su tabla, hay ocasiones en las que la comparativa es muy necesaria y por tanto es necesario unir los estadísticos en la misma tabla. Nótese la diferencia con el siguiente cuadro…

as.datatable_widget(data %>% 
  tab_cells(P31) %>% 
  tab_stat_cases(total_row_position = "above", label = "Casos") %>%
  tab_stat_cpct(label = "% casos") %>%
  tab_pivot(stat_position = "inside_columns"))

Figura 3.6: Frecuencias y porcentajes de P31

Nótese el efecto introducido por el modificador de posición del cálculo. También …

as.datatable_widget(data %>% 
  tab_cells(P31) %>% 
  tab_stat_cases(total_row_position = "above", label = "Casos") %>% 
  tab_stat_cpct(label = "% casos") %>% 
  tab_pivot(stat_position = "outside_rows"))

Figura 3.7: Tablas con propiedades diferentes a estándar

O también …

as.datatable_widget(data %>% 
  tab_cells(P31) %>% 
  tab_stat_cases(total_row_position = "below", label = "Casos") %>% 
  tab_stat_cpct(label = "% casos") %>% 
  tab_pivot(stat_position = "inside_columns"))

Figura 3.8: Propiedades diferentes al estándar

3.2.2 Variable de respuesta múltiple

Vamos a trabajar ahora con variables multi respuesta. Para trabajar con múltiples, debemos conocer en qué forma nos llegan en nuestro input. Por ejemplo, SPSS divide la variable múltiple en tantas variables simples (o dicotómicas binarias) como requiera para poder representar la multi respuesta. Por ejemplo, si tenemos una variable múltiple denominada P01, y el máximo número de respuestas (menciones) en el banco de datos es 3, al crear el _dataframe_ se crean las variables P01_1, P01_2 y P01_3; es con estas variables con las que trabajamos. Cada una de estas variables puede tomar cualquiera de los valores codificados.

Para expss, la forma de indicar que un conjunto de campos forman una multi respuesta es muy simple anteponer mrset_f() al nombre del campo que vamos a usar. Debemos tener la precaución de que no haya variables en el banco de datos que comiencen por la misma raíz. Así, el campo de ejemplo sería mrset_f(P01_) y con eso procesaría las tres variables de forma conjunta. Alternativamente, podríamos usar también:

  • mrset(P01_1 %to% P01_3) o también,
  • mrset(P01_1,P01_2,P01_3)

Cualquiera de ellas sería también válida, pero nótese que en estas últimas listadas, es necesario saber donde empieza y acaba la múltiple y esto puede variar sobretodo si creamos los script antes de acabar el campo. Al acabar el campo, pudiera haber algún nuevo caso que tuviera más menciones que 3 y por tanto existirían también _4, _5 o, _n.

Como hemos indicado, no olvides que existe otra forma de trabajar las múltiples, utilizando variables dicotómicas o binarias (así es como están en nuestro banco de datos del CIS). En este caso, serviría todo lo afirmado anteriormente, pero en lugar de mrset_f(), usaríamos mdset_f().

3.2.2.1 Tablas de frecuencias absolutas

Usaremos el campo P18C para procesar su información, que se localiza en el banco de datos desde P18C01 hasta P18C08.

as.datatable_widget(data %>% 
  tab_cells(mdset_f(P18C)) %>% 
  tab_stat_cases(total_row_position="above", label="Casos") %>% 
  tab_pivot(stat_position="inside_columns"))

Figura 3.9: Frecuencias de P18

3.2.2.2 Tablas de frecuencias relativas

También se pueden, como es obvio, obtener porcentajes en las tablas marginales múltiples. A diferencia de cuando la variables es simple que todos los porcentajes suman 100, en las variables múltiples cada alternativa tiene un rango de 0 a 100, desde no ser elegida una opción en ningún registro del _dataframe_, hasta ser elegida por todos los registros. Usaremos nuevamente el campo P18C para procesar su información, que se localiza en el banco de datos desde P18C01 hasta P18C08.

as.datatable_widget(data %>% 
  tab_cells(mdset_f(P18C)) %>%
  tab_stat_cpct(total_row_position="above", label="% casos") %>% 
  tab_pivot(stat_position="inside_columns"))

Figura 3.10: Frecuencias de P18

Pero vamos a introducir una nueva variación. En una múltiple, también pueden calcularse los resultados en lo que se llama base respuestas, donde sí suman 100% los porcentajes nuevamente, pero recuerda que el porcentaje hace referencia a las respuestas, no a los individuos. En este caso el script modifica el estadístico solicitado.

as.datatable_widget(data %>% 
  tab_cells(mdset_f(P18C)) %>%
  tab_stat_cpct_responses(total_row_position="above", label="% casos") %>% 
  tab_pivot(stat_position="inside_columns"))

Figura 3.11: Frecuencias de P18

3.2.3 Tablas combinadas

Con las múltiples también funciona el posicionamiento del estadístico casos -frecuencias- cuando combinamos los mismos (frecuencia y porcentaje) y podemos realizar las mismas variantes que antes.

Ubicar los cálculos dentro de las columnas …

as.datatable_widget(data %>% 
  tab_cells(mdset_f(P18C)) %>%  # o tab_cells(mdset(P18C01 %to% P18C08))
  tab_stat_cases(label ="Casos") %>% 
  tab_stat_cpct(label="% casos") %>% 
  tab_stat_cpct_responses(label="% respuestas") %>% 
  tab_pivot(stat_position="inside_columns"))

Figura 3.12: Frecuencias y porcentajes de P18 (1)

Préstese atención a las dos líneas de #Total, dado que las bases son diferentes (número de individuos y número de respuestas).

Podemos ubicar los cálculos dentro de las filas …

as.datatable_widget(data %>% 
  tab_cells(mdset_f(P18C)) %>%  # o tab_cells(mdset(P18C01 %to% P18C08))
  tab_stat_cases(label ="Casos") %>% 
  tab_stat_cpct(label="% casos") %>% 
  tab_stat_cpct_responses(label="% respuestas") %>% 
  tab_pivot(stat_position="inside_rows"))

Figura 3.13: Frecuencias y porcentajes de P18 (2)

Podemos ubicar los cálculos fuera de las columnas (igual a la anterior inside... porque no hay campo de columna) …

as.datatable_widget(data %>% 
  tab_cells(mdset_f(P18C)) %>%  # o tab_cells(mdset(P18C01 %to% P18C08))
  tab_stat_cases(label ="Casos") %>% 
  tab_stat_cpct(label="% casos") %>% 
  tab_stat_cpct_responses(label="% respuestas") %>% 
  tab_pivot(stat_position="outside_columns"))

Figura 3.14: Frecuencias y porcentajes de P18 (3)

Podemos ubicar los cálculos fuera de las filas … nótese que la agrupación es diferente a la anterior con inside_rows

as.datatable_widget(data %>% 
  tab_cells(mdset_f(P18C)) %>%  # o tab_cells(mdset(P18C01 %to% P18C08))
  tab_stat_cases(label ="Casos") %>% 
  tab_stat_cpct(label="% casos") %>% 
  tab_stat_cpct_responses(label="% respuestas") %>% 
  tab_pivot(stat_position="outside_rows"))

Figura 3.15: Frecuencias y porcentajes de P18 (4)

3.3 Estadísticos

Hasta ahora hemos trabajado sólo con casos, pero ya hemos anticipado que al igual que con los recuentos de casos o frecuencias se puede trabajar con otros estadísticos como la suma, máximo, mínimo, media, mediana, error estándar y desviación típica. Vamos a ir viendo cómo se desarrollan estos cuadros.

3.3.1 Estadísticos básicos

Recordemos que hasta ahora no hemos cruzado la información, solo estamos trabajando con lo que se denomina medidas marginales.Nuestro primer ejemplo es un caso típico, donde queremos obtener la media (tab_stat_mean), la desviación típica (tab_stat_sd()) y la base de cálculo, es decir el número de casos con valor (tab_stat_valid_n()) para el cálculo.

Así, siguiendo la misma estructra de las tablas anteriores, redactamos el siguiente script:

as.datatable_widget(data %>% 
  tab_cells(P3) %>% 
  tab_stat_mean() %>% 
  tab_stat_sd() %>% 
  tab_stat_valid_n() %>% 
  tab_pivot())

Figura 3.16: Estadísticos marginales de P3 (1)

No, no tienes por qué ver los nombres de los estadísticos en lengua inglesa. También aquí podemos jugar con la etiqueta (label).

as.datatable_widget(data %>% 
  tab_cells(P3) %>% 
  tab_stat_mean(label = "media") %>% 
  tab_stat_sd(label = "desviación") %>% 
  tab_stat_valid_n(label = "casos") %>% 
  tab_pivot())

Figura 3.17: Estadísticos marginales de P3 (2)

Hagamos una nueva tabla con una pequeña variación, ahora vamos a poner los estadísticos en columnas.

as.datatable_widget(data%>%
  tab_cells(P3) %>% 
  tab_stat_mean(label = "media") %>% 
  tab_stat_sd(label = "desviación") %>% 
  tab_stat_valid_n(label = "casos") %>% 
  tab_pivot(stat_position = "inside_columns"))

Figura 3.18: Estadísticos marginales de P3 (3)

expss tiene además la posibilidad de obtener estos tres cálculos, bastante habituales por cierto, con un solo comando: tab_stat_mean_sd_n() pudiendo añadir además etiquetas separadas.

as.datatable_widget(data %>% 
  tab_cells(P3) %>% 
  tab_stat_mean_sd_n(labels = c("media", "desviación", "casos")) %>% 
  tab_pivot())

Figura 3.19: Estadísticos marginales de P3 (4)

3.3.2 Otros estadísticos

Además de los estadísticos más básicos, otros que podemos añadir son el máximo, el mínimo, la mediana, el error estándar y la suma. Los unimos todos.

as.datatable_widget(data %>% 
  tab_cells(P3) %>% 
  tab_stat_mean(label = "Media") %>% 
  tab_stat_sd(label =  "Desviación") %>%  
  tab_stat_max(label = "Máximo") %>%  
  tab_stat_min(label = "Mínimo") %>%  
  tab_stat_median(label = "Mediana") %>%  
  tab_stat_se(label = "Error estándar") %>%  
  tab_stat_sum(label = "Suma") %>% 
  tab_pivot())

Figura 3.20: Estadísticos marginales de P3 (5)

Nótese que no se han definido ni filas, ni columnas. Es el modificador de la posición de los estadísticos (stat_position) el que habilita la posición en una fila.

Del mismo modo, estos estadísticos pueden ubicarse en las columnas.

as.datatable_widget(data %>% 
  tab_cells(P3) %>% 
  tab_stat_mean(label = "Media") %>% 
  tab_stat_sd(label =  "Desviación") %>%  
  tab_stat_max(label = "Máximo") %>%  
  tab_stat_min(label = "Mínimo") %>%  
  tab_stat_median(label = "Mediana") %>%  
  tab_stat_se(label = "Error estándar") %>%  
  tab_stat_sum(label = "Suma") %>% 
  tab_stat_cases(label = "casos") %>%  
  tab_pivot(stat_position = "inside_rows"))

Figura 3.21: Estadísticos marginales de P3 (6)

Hagamos finalmente una leve variación. Nótese que al utilizar "|" en la etiqueta del estadístico casos, hemos eliminado la columna intermedia y aparace todo como más compacto. Este será un recurso que utilizaremos en muchas ocasiones.

as.datatable_widget(data %>% 
  tab_cells(P3) %>% 
  tab_stat_mean(label = "Media") %>% 
  tab_stat_sd(label =  "Desviación") %>%  
  tab_stat_max(label = "Máximo") %>%  
  tab_stat_min(label = "Mínimo") %>%  
  tab_stat_median(label = "Mediana") %>%  
  tab_stat_se(label = "Error estándar") %>%  
  tab_stat_sum(label = "Suma") %>% 
  tab_stat_cases(label = "|") %>%  
  tab_pivot(stat_position = "inside_rows"))

Figura 3.22: Estadísticos marginales de P3 (7)

3.4 Conclusión

Creo que esta primera muestra de cómo procesar nuestra tabla de una única variable, es más que suficiente para colmar las expectativas más exigentes. Para aquellos que conozcan un poco más el funcionamiento de R, indicar que cada una de estas tablas, se puede almacenar como objeto sobre el que se puede trabajar. Este objeto es del tipo etable pero en el fondo es un objeto de tipo _dataframe_ que por tanto puedes ser trabajado con comandos R estándar. Es de esta posibilidad de ser un dataframe de donde deriva su capacidad de integración con otros paquetes como por ejemplo highcharter Kunst (2020) que será uno de nuestros paquetes de referencia para gráficos. Para una presentación completa, véase la sección 8 para una presentación de gráficos a partir de _dataframe_ o de tablas cruzadas - _crosstab_ -.

Hasta llegar ese momento, ahora en la siguiente sección 4 analizamos las tablas cruzadas.

Bibliografía

Demin, Gregory. 2020. Expss: Tables, Labels and Some Useful Functions from Spreadsheets and ’SPSS’ Statistics. https://CRAN.R-project.org/package=expss.
Kunst, Joshua. 2020. Highcharter: A Wrapper for the Highcharts Library. https://jkunst.com/highcharter/index.html.