6 Otras utilidades y tablas especiales

Continuamos en esta sección aportando sentido y contenido al trabajo con tablas. En esta sección, introducimos la utilidad de disponer del plan de códigos y más en profundidad, trabajos la utilidad de otros elementos básicos: cuadros, recodificación, ponderación, subtotales y NETS.

6.1 Plan de códigos

De forma muy sencilla, podemos obtener de nuestro fichero de datos lo que se denomina el codeplan (Mohler, Pennell, and Hubbard 2008) o libro de códigos. expss tiene una orden directa para ello. Este libro de códigos nos permitirá de forma muy sencilla conocer de primera mano, con mayor o menor precisión, de forma exploratoria el contenido de nuestro banco de datos o en definitva la codificación que se ha utilizado.

Cuatro elementos de información son los más importantes en la creación de un plan de códigos (Mohler, Pennell, and Hubbard 2008):

  • Conocer los textos de etiquetado de las variables en el cuestionario (ítem, escala de respuesta,instrucción del entrevistador, etc.) y conocer su caracterización en el archivo de datos a partir de su posición, longitud, nombre de campo,etc.;
  • Propiedades del campo de datos numéricos (ancho, decimales, alfa (carácter),o numérico);
  • Definición de los valores de escala de respuesta, filtros, rechazos, no sabe, no contesta…;
  • Conocimiento de las variables de clasificación

La siguiente sintaxis nos permite alcanzar este objetivo con poco esfuerzo y como punto de partida para el siguiente punto de recodificación.

as.datatable_widget(info(data, frequencies = F, max_levels = 10))

Los modificadores de la función info(), permiten ir desde el listado más completo (el mostrado) hasta la supresión de elementos como las frecuencias o los descriptivos básicos, al tiempo que agilizan su cálculo.

as.datatable_widget(info(data, stats = FALSE, frequencies = FALSE))

Conociendo el libro de códigos, accedamos al apartado de recodificación. Si quieres más información sobre el comando info()usa la función help(topic = info) o también ?expss:info.

6.2 Recodificar

Aunque ya en la sección anterior anterior hicimos una breve incursión en el uso de la recodificación, el paquete expss dispone de una serie de opciones muy interesantes acerca de este funcionalidad que usamos mucho en nuestro trabajo diario. La función recode() cambia la codificación de una variable en el contexto que se utiliza. Puede ser usada también para reorganizar o consolidar los valores de una variable existente en función de las condiciones. El diseño de esta función está inspirada en la utilidad RECODE de SPSS. El usuario facilita una secuencia de recodificaciones proporcionadas en forma de fórmulas.

Por ejemplo, 1:2 ~ 1 significa que todos los valores 1 y 2 se reemplazarán con 1. Cada valor se recodificará solo una vez, es decir, sea realiza una única ‘pasada’ por el registro empezando por el 1 y acabando por el N.

Dos formas de uso:

  • Si recode() se usa como funcionalidad diferenciada, en este proceso de asignación aquellos valores que no cumplan ninguna condición permanecen sin cambios.
  • Si recode()se usa dentro de una tabla, los valores de recodificación (…) que no cumplen ninguna condición serán reemplazados por NA.

Se pueden usar valores o condiciones lógicas más sofisticadas y funciones como condición. Hay varias funciones especiales para su uso como criterios; para más detalles, consulte los criterios ?? en su sección 8.

El uso común se parece a este: recode(x, 1:2 ~ -1, 3 ~ 0, 4:5 ~ 1, 99 ~ NA). Se puede observar que a los valores originales 1 y 2 se les imputa un -1, al 3 un 0, y a los valores 4 y 5 se les imputa un 1, el 99 se convierte en NA (valor perdido).

Para más información, ver detalles y ejemplos a continuación. Te dejamos los ejemplos del autor que ilustran muy bien las posibilidades de esta funcionalidad. Se reproducen los ejemplos de recodificación extraídos del manual de SPSS. Se utilizan datos ficticios generados en línea.

# RECODE V1 TO V3 (0=1) (1=0) (2, 3=-1) (9=9) (ELSE=SYSMIS)
v1  = c(0, 1, 2, 3, 9, 10) # se crea la variable
v1
## [1]  0  1  2  3  9 10
recode(v1) = c(0 ~ 1, 1 ~ 0, 2:3 ~ -1, 9 ~ 9, TRUE ~ NA)
v1
## [1]  1  0 -1 -1  9 NA
# RECODE QVAR(1 THRU 5=1)(6 THRU 10=2)(11 THRU HI=3)(ELSE=0).
qvar = c(1:20, 97, NA, NA)
recode(qvar, 1 %thru% 5 ~ 1, 6 %thru% 10 ~ 2, 11 %thru% hi ~ 3, TRUE ~ 0)
##  [1] 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 0 0
# the same result
recode(qvar, 1 %thru% 5 ~ 1, 6 %thru% 10 ~ 2, ge(11) ~ 3, TRUE ~ 0)
##  [1] 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 0 0
# RECODE STRNGVAR ("A", "B", "C"="A")("D", "E", "F"="B")(ELSE=" ").
strngvar = LETTERS
recode(strngvar, c("A", "B", "C") ~ "A", c("D", "E", "F") ~ "B", TRUE ~ " ")
##  [1] "A" "A" "A" "B" "B" "B" " " " " " " " " " " " " " " " " " " " " " " " " " "
## [20] " " " " " " " " " " " " " "
# recode in place. Note that we recode only first six letters
recode(strngvar) = c(c("A", "B", "C") ~ "A", c("D", "E", "F") ~ "B")
strngvar
##  [1] "A" "A" "A" "B" "B" "B" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S"
## [20] "T" "U" "V" "W" "X" "Y" "Z"
# RECODE AGE (MISSING=9) (18 THRU HI=1) (0 THRU 18=0) INTO VOTER.
age = c(NA, 2:40, NA)
voter = recode(age, NA ~ 9, 18 %thru% hi ~ 1, 0 %thru% 18 ~ 0)
voter
##  [1] 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## [39] 1 1 9
# the same result with "%into%"
recode(age, NA ~ 9, 18 %thru% hi ~ 1, 0 %thru% 18 ~ 0) %into% voter2
voter2
##  [1] 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## [39] 1 1 9
# recode with adding labels
voter = recode(
    age,
    "Refuse to answer" = NA ~ 9,
    "Vote" = 18 %thru% hi ~ 1,
    "Don't vote" = 0 %thru% 18 ~ 0
)
voter
## VALUES:
## 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9
## VALUE LABELS:                   
##  0 Don't vote      
##  1 Vote            
##  9 Refuse to answer
# recoding with labels
ol = c(1:7, 99)
var_lab(ol) = "Liking" #texto extra
val_lab(ol)  = c(
    "Disgusting" = 1,
    "Very Poor" = 2,
    "Poor" = 3,
    "So-so" = 4,
    "Good" = 5,
    "Very good" = 6,
    "Excellent" = 7,
    "Hard to say" = 99
) #etiquetas códigos
recode(ol, 1:3 ~ 1, 5:7 ~ 7, TRUE ~ copy, with_labels = TRUE)
## LABEL: Liking 
## VALUES:
## 1, 1, 1, 4, 7, 7, 7, 99
## VALUE LABELS:                             
##   1 Disgusting/Very Poor/Poor
##   4 So-so                    
##   7 Good/Very good/Excellent 
##  99 Hard to say
# "rec" is a shortcut for recoding with labels. Same result:
rec(ol, 1:3 ~ 1, 5:7 ~ 7, TRUE ~ copy)
## LABEL: Liking 
## VALUES:
## 1, 1, 1, 4, 7, 7, 7, 99
## VALUE LABELS:                             
##   1 Disgusting/Very Poor/Poor
##   4 So-so                    
##   7 Good/Very good/Excellent 
##  99 Hard to say
# another method of combining labels
recode(ol,
       1:3 ~ 1,
       5:7 ~ 7,
       TRUE ~ copy,
       with_labels = TRUE,
       new_label = "range")
## LABEL: Liking 
## VALUES:
## 1, 1, 1, 4, 7, 7, 7, 99
## VALUE LABELS:                     
##   1 Disgusting - Poor
##   4 So-so            
##   7 Good - Excellent 
##  99 Hard to say
# example with from/to notation

# RECODE QVAR(1 THRU 5=1)(6 THRU 10=2)(11 THRU HI=3)(ELSE=0).
list_from = list(1 %thru% 5, 6 %thru% 10, ge(11), TRUE)
list_to = list(1, 2, 3, 0)
recode(qvar, from_to(list_from, list_to))
##  [1] 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 0 0
list_from = list(NA, 18 %thru% hi, 0 %thru% 18)
list_to = list("Refuse to answer" = 9,
               "Vote" = 1,
               "Don't vote" = 0)
voter = recode(age, from_to(list_from, list_to))
voter
## VALUES:
## 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9
## VALUE LABELS:                   
##  0 Don't vote      
##  1 Vote            
##  9 Refuse to answer
# "ifs" examples
a = 1:5
b = 5:1
a
## [1] 1 2 3 4 5
b
## [1] 5 4 3 2 1
ifs(b > 3 ~ 1)                       # c(1, 1, NA, NA, NA)
## [1]  1  1 NA NA NA
ifs(b > 3 ~ 1, TRUE ~ 3)             # c(1, 1, 3, 3, 3)
## [1] 1 1 3 3 3
ifs(b > 3 ~ 1, a > 4 ~ 7, TRUE ~ 3)    # c(1, 1, 3, 3, 7)
## [1] 1 1 3 3 7
ifs(b > 3 ~ a, TRUE ~ 42)            # c(1, 2, 42, 42, 42)
## [1]  1  2 42 42 42

El recode() puede ser utilizado como funcionalidad separada y con asignación o dentro de la definición de una variable. Por ejemplo:

v1 <- c(1, 2, 3, 2, 1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1)
v2 <- v1
v1
##  [1] 1 2 3 2 1 2 3 4 5 6 5 4 3 2 1
v2
##  [1] 1 2 3 2 1 2 3 4 5 6 5 4 3 2 1
v1 <- recode(v1, 1:5 ~ 1, 6:10 ~ 2)
mean(v1, na.rm = TRUE)
## [1] 1.066667
mean(recode(v2, 1:5 ~ 1, 6:10 ~ 2), na.rm = TRUE)
## [1] 1.066667
v1
##  [1] 1 1 1 1 1 1 1 1 1 2 1 1 1 1 1
v2
##  [1] 1 2 3 2 1 2 3 4 5 6 5 4 3 2 1

Nótese que la diferencia estriba en que mientras que al finalizar el proceso v1 tiene solo valores 1 y 2 recodificados, v2 (copia de v1) mantiene los valores originales.

6.3 Cuadros

En ocasiones es interesante reproducir algún tipo de cuadro que se ha presentado al entrevistado (baterías de ítems, cuadros, rejillas o grids, grillas o tablas de ítems, son sinónimos). Por ejemplo la pregunta P9 del cuestionario nos presenta un cuadro en el que hay hasta 7 ítems valorados de 1 a 10, con los valores 98 y 99 como NS y NC respectivamente. Así que vamos a procesar esas tablas como cuadros.

Nuestro script es el siguiente …

as.datatable_widget(data %>%
                        tab_cells(P901 %to% P907) %>%
                        tab_stat_cpct() %>%
                        tab_pivot())

Figura 6.1: Cuadros de baterías

Esta sería la salida lógica que damos a la tabla. Sin embargo utilizando algunos pequeños trucos, podemos presentarlo así. Seguro nuestro cliente final está más contento …

val_lab(data$P901) <-
     c(
          "1" = 1,
          "2" = 2,
          "3" = 3,
          "4" = 4,
          "5" = 5,
          "6" = 6,
          "7" = 7,
          "8" = 8,
          "9" = 9,
          "10" = 10,
          "N.S." = 98,
          "N.C." = 99
     )
val_lab(data$P902) <-
     c(
          "1" = 1,
          "2" = 2,
          "3" = 3,
          "4" = 4,
          "5" = 5,
          "6" = 6,
          "7" = 7,
          "8" = 8,
          "9" = 9,
          "10" = 10,
          "N.S." = 98,
          "N.C." = 99
     )
val_lab(data$P903) <-
     c(
          "1" = 1,
          "2" = 2,
          "3" = 3,
          "4" = 4,
          "5" = 5,
          "6" = 6,
          "7" = 7,
          "8" = 8,
          "9" = 9,
          "10" = 10,
          "N.S." = 98,
          "N.C." = 99
     )
val_lab(data$P904) <-
     c(
          "1" = 1,
          "2" = 2,
          "3" = 3,
          "4" = 4,
          "5" = 5,
          "6" = 6,
          "7" = 7,
          "8" = 8,
          "9" = 9,
          "10" = 10,
          "N.S." = 98,
          "N.C." = 99
     )
val_lab(data$P905) <-
     c(
          "1" = 1,
          "2" = 2,
          "3" = 3,
          "4" = 4,
          "5" = 5,
          "6" = 6,
          "7" = 7,
          "8" = 8,
          "9" = 9,
          "10" = 10,
          "N.S." = 98,
          "N.C." = 99
     )
val_lab(data$P906) <-
     c(
          "1" = 1,
          "2" = 2,
          "3" = 3,
          "4" = 4,
          "5" = 5,
          "6" = 6,
          "7" = 7,
          "8" = 8,
          "9" = 9,
          "10" = 10,
          "N.S." = 98,
          "N.C." = 99
     )
val_lab(data$P907) <-
     c(
          "1" = 1,
          "2" = 2,
          "3" = 3,
          "4" = 4,
          "5" = 5,
          "6" = 6,
          "7" = 7,
          "8" = 8,
          "9" = 9,
          "10" = 10,
          "N.S." = 98,
          "N.C." = 99
     )

as.datatable_widget(
     data %>%
          tab_cells("|" = unvr(P901)) %>%
          tab_stat_cpct(label = var_lab(P901), total_row_position = "none") %>%
          tab_stat_mean_sd_n(label = "P901") %>%
          tab_cells("|" = unvr(P902)) %>%
          tab_stat_cpct(label = var_lab(P902), total_row_position = "none") %>%
          tab_stat_mean_sd_n(label = "P901") %>%
          tab_cells("|" = unvr(P903)) %>%
          tab_stat_cpct(label = var_lab(P903), total_row_position = "none") %>%
          tab_stat_mean_sd_n(label = "P901") %>%
          tab_cells("|" = unvr(P904)) %>%
          tab_stat_cpct(label = var_lab(P904), total_row_position = "none") %>%
          tab_stat_mean_sd_n(label = "P901") %>%
          tab_cells("|" = unvr(P905)) %>%
          tab_stat_cpct(label = var_lab(P905), total_row_position = "none") %>%
          tab_stat_mean_sd_n() %>%
          tab_cells("|" = unvr(P906)) %>%
          tab_stat_cpct(label = var_lab(P906), total_row_position = "none") %>%
          tab_stat_mean_sd_n() %>%
          tab_cells("|" = unvr(P907)) %>%
          tab_stat_cpct(label = var_lab(P907), total_row_position = "none") %>%
          tab_stat_mean_sd_n() %>%
          tab_pivot(stat_position = "inside_columns") %>%
          t()
)

Figura 6.2: Cuadros de baterías modificado

¿Qué hemos hecho?, hemos limpiado el texto de la variable utilizando la función "|"=unvr() y ese mismo texto extra de la variable var_lab() se lo hemos asignado al estadístico con label. De esta forma el resultado es el que ves. Desafortunadamente, hay un pequeño bug del que está informado el autor, de no poder situar la media y/o la desviación típica en la misma fila. Para hacerlo hay que unir dos tablas. Como esperamos esté resuelto en breve, no damos la solución por no complicar más la salida.

6.4 Ponderación

Otro de los aspectos fundamentales en la investigación de mercados es la ponderación. Lo primero que debemos entender es el propio concepto de ponderación. En definitiva, es hacer que cada registro (% de casos o casos o estadísticos) en lugar de contar como un caso (frecuencia 1), cuente como n casos, siendo n el valor de otro campo (indicado en weight() -peso-) del marco de datos. Este peso ha sido obtenido por un procedimiento llamado equilibraje o raking (Biemer and Christ 2008).

Aquí muestro la tabla, sin ponderar …

as.datatable_widget(data %>% 
    tab_cols(total(),P3 ) %>%
    tab_cells(mdset(P21A01 %to% P21A03)) %>% 
    tab_stat_cpct() %>% 
    tab_pivot())

Figura 6.3: Uso de ponderación

El estudio del CIS que estamos trabajando tiene una variable denominada PESO que contiene el coeficiente de ponderación para adaptarse a la población real española. Aquí dejamos la anterior tabla, pero ponderada. Véase las diferencias entre todos los valores.

as.datatable_widget(data %>% 
    tab_cols(total(),P3 ) %>%
    tab_weight(PESO) %>%
    tab_cells(mdset(P21A01 %to% P21A03)) %>% 
    tab_stat_cpct() %>% 
    tab_pivot())

Figura 6.4: Uso de ponderación con multi respuesta

Aunque este manual se refiere únicamente a tablas, es bastante habitual obtener en toda ponderación la denominada eficiencia de la misma. Este análisis lo realizamos utilizando R como calculadora. Podemos hacer una análisis de la variable PESO y de su eficiencia.

mean.peso <- mean(data$PESO, na.rm=TRUE)
sd.peso <- sd(data$PESO, na.rm=TRUE)
ratio <- sd.peso/mean.peso
eficiencia <- (1/(1+(ratio^2)))*100
eficiencia <- round(eficiencia,2)

Puede observarse como la eficiencia de la ponderación es del 76.79 %.

6.5 Subtotales y NETS

Otra de las funcionalidades básicas en nuestro trabajo de análisis es el uso de subtotales y/o netos. El objetivo de ambas funciones es reagrupar los códigos de una determinada variable, permitiendo observar acumulados de frecuencia. El paquete expss hace una diferenciación entre ambos que mostraremos seguidamente.

6.5.1 Subtotales

El uso de tab_subtotal_rows() o tab_subtotal_cols() o tab_subtotal_cells() añade subtotales a un conjunto de categorías de la variable sobre la que se aplique. Si se introduce un texto se utilizará el mismo, pero si no, se añade la palabra TOTAL. Debes tener en cuenta que si las agrupaciones de categorías que realizas se solapan, también se solaparán los recuentos en el cálculo de subtotales. Estos subtotales pueden ser aplicados a las variables del banco de datos.

val_lab(data$P901) <-
    c(
        "1" = 1,
        "2" = 2,
        "3" = 3,
        "4" = 4,
        "5" = 5,
        "6" = 6,
        "7" = 7,
        "8" = 8,
        "9" = 9,
        "10" = 10,
        "N.S." = 98,
        "N.C." = 99
    )
as.datatable_widget(
    data %>%
        tab_cols(total(), P31) %>%
        tab_cells(P901) %>%
        tab_subtotal_cells(
            "NO SATISFACTORIO" = 1:5,
            6:8,
            "SATISFACTORIO" = 9:10
        ) %>%
        tab_stat_cpct() %>%
        tab_pivot()
)

Figura 6.5: Uso de subtotales 1

Nótese que en el ejemplo han sido utilizados textos en solo dos de los tres subtotales que se han calculado. Si no se introduce texto, es cuando se usa la palabra TOTAL. Nótese también que por defecto los subtotales aparecen detrás del último valor del grupo, detrás del 5, detrás del 8 y detrás del 10. Existe la posibilidad de determinar mediante una instrucción como deben aparecer. El modificador o parámetro position con posibles valores "below", "above", "top" o "bottom" indicarán el lugar donde se deben imprimir. Del mismo modo, se puede forzar a que sea el propio sistema quien determine las etiquetas del subtotal generado. Así el modificador prefix puede determinar un prefijo para todas las etiquetas siendo TOTAL el valor por defecto, y también el modificador new_labelque permite indicar si la etiqueta se construye usando las etiquetas originales respondiendo a all que la usa todas, range la primera y la última, first la primera del grupo y last la última del grupo.

Con todo ello, podríamos modificar nuestro ejemplo a:

val_lab(data$P901) <-
    c(
        "1" = 1,
        "2" = 2,
        "3" = 3,
        "4" = 4,
        "5" = 5,
        "6" = 6,
        "7" = 7,
        "8" = 8,
        "9" = 9,
        "10" = 10,
        "N.S." = 98,
        "N.C." = 99
    )
as.datatable_widget(
    data %>%
        tab_cols(total(), P31) %>%
        tab_cells(P901) %>%
        tab_subtotal_cells(
            1:5,
            6:8,
            9:10,
            position = "bottom",
            prefix = "SUBT",
            new_label = "range"
        ) %>%
        tab_stat_cpct() %>%
        tab_pivot()
)

Figura 6.6: Uso de subtotales 2

6.5.2 NETS

El uso de tab_net_rows() o tab_net_cols() o tab_net_cells() sustituye por netos (subtotales) a un conjunto de categorías de la variable sobre la que se aplique. Si se introduce un texto se utilizará el mismo, pero si no es así, se añade la palabra TOTAL.

Debes tener en cuenta que si las agrupaciones de categorías que realizas se solapan, también se solaparán los recuentos en el cálculo de netos. Estos netos pueden ser aplicados a las variables del banco de datos. La terminología de NET suele ser muy aplicada en las variables de tipo múltiple, para agrupar conceptos similares. En nuestro ejemplo por mantener la coherencia con el uso de subtotal() lo aplicaremos sin embargo con una variable numérica de valoración.

val_lab(data$P901) <-
    c(
        "1" = 1,
        "2" = 2,
        "3" = 3,
        "4" = 4,
        "5" = 5,
        "6" = 6,
        "7" = 7,
        "8" = 8,
        "9" = 9,
        "10" = 10,
        "N.S." = 98,
        "N.C." = 99
    )
as.datatable_widget(
    data %>%
        tab_cols(total(), P31) %>%
        tab_cells(P901) %>%
        tab_net_cells(
            "NO SATISFACTORIO" = 1:5,
            6:8,
            "SATISFACTORIO" = 9:10
        ) %>%
        tab_stat_cpct() %>%
        tab_pivot()
)

Figura 6.7: Uso de nets 1

Nótese que en el ejemplo han sido utilizados textos en solo dos de los tres nets que se han calculado. Si no se introduce texto, es cuando se usa la palabra TOTAL. Nótese también que por defecto los subtotales aparecen detrás del último valor del grupo, detrás del 5, detrás del 8 y detrás del 10. Existe la posibilidad de determinar mediante una instrucción como deben aparecer. El modificador o parámetro position con posibles valores "below", "above", "top" o "bottom" indicarán el lugar donde se deben imprimir.

Del mismo modo, se puede forzar a que sea el propio sistema quien determine las etiquetas del subtotal generado. Así el modificador prefix puede determinar un prefijo para todas las etiquetas siendo TOTAL el valor por defecto, y también el modificador new_labelque permite indicar si la etiqueta se construye usando las etiquetas originales respondiendo a allque la usa todas, range la primera y la última, first la primera del grupo y last la última del grupo. Podríamos modificar nuestro ejemplo a:

val_lab(data$P901) <-
    c(
        "1" = 1,
        "2" = 2,
        "3" = 3,
        "4" = 4,
        "5" = 5,
        "6" = 6,
        "7" = 7,
        "8" = 8,
        "9" = 9,
        "10" = 10,
        "N.S." = 98,
        "N.C." = 99
    )
as.datatable_widget(
    data %>%
        tab_cols(total(), P31) %>%
        tab_cells(P901) %>%
        tab_net_cells(
            1:5,
            6:8,
            9:10,
            position = "top",
            prefix = "NET",
            new_label = "range"
        ) %>%
        tab_stat_cpct() %>%
        tab_pivot()
)

Figura 6.8: Uso de nets 2

Puedes preguntarte el porqué del position si en un NET realmente se eliminan los códigos originales, pero esto no tiene por qué ser así. Tanto el subtotal como el net tienen la posibilidad de variar este hecho utilizando el modificador add con valores TRUE o FALSE que mantendría o no los códigos originales. No obstante, en nuestro ejemplo como hay valores no agrupados (NS y NC) aquí la posición sí es relevante.

6.6 Top y Bottom

Por último, otra utilidad no menos importante que las anterior y no menos utilizada. El cálculo del top y el bottom de una escala. Para ello, vamos a basarnos en algo que ya hemos visto en las tablas anteriores, la recodificación y el cómo reutilizamos la posibilidad de las variables múltiples.

Planteemos una situación en la que deseamos que la variable P901 se muestre de forma segmentada y conjuntamente cada uno de sus valores. Llamamos TOP a la agrupación en una columna o fila de tabla de aquellas categorías con las valoraciones más altas (por ejemplo 9 y 10) y BOTTOM a las más bajas (por ejemplo 1,2,3,4,5 y 6 o 1:6 como sabemos). Queremos que en la tabla se muestre ambas categorías. ¿Como la hacemos? Este es script.

val_lab(data$P901) <-
    c(
        "1" = 1,
        "2" = 2,
        "3" = 3,
        "4" = 4,
        "5" = 5,
        "6" = 6,
        "7" = 7,
        "8" = 8,
        "9" = 9,
        "10" = 10,
        "N.S." = 98,
        "N.C." = 99
    )
as.datatable_widget(
    data %>%
        tab_cols(total(), P31) %>%
        tab_cells(P901) %>%
        tab_subtotal_cells("Bottom" = 1:6, "Top" = 9:10) %>%
        tab_stat_cpct() %>%
        tab_pivot()
)

Figura 6.9: Uso de top y bottom

Controlando más algunos aspectos de la publicación de la tabla …

val_lab(data$P901) <-
    c(
        "1" = 1,
        "2" = 2,
        "3" = 3,
        "4" = 4,
        "5" = 5,
        "6" = 6,
        "7" = 7,
        "8" = 8,
        "9" = 9,
        "10" = 10,
        "N.S." = 98,
        "N.C." = 99
    )
as.datatable_widget(
    data %>%
        tab_cols(total(), P31) %>%
        tab_cells(P901) %>%
        tab_subtotal_cells(
            "Bottom" = 1:6,
            "Top" = 9:10,
            position = "bottom"
        ) %>%
        tab_stat_cpct(total_row_position = "below") %>%
        tab_cells(na_if(P901, gt(10))) %>%
        tab_stat_mean() %>%
        tab_pivot()
)

Figura 6.10: Uso de top y bottom arriba

Con subtotales abajo…

val_lab(data$P901) <-
    c(
        "1" = 1,
        "2" = 2,
        "3" = 3,
        "4" = 4,
        "5" = 5,
        "6" = 6,
        "7" = 7,
        "8" = 8,
        "9" = 9,
        "10" = 10,
        "N.S." = 98,
        "N.C." = 99
    )
as.datatable_widget(
    data %>%
        tab_cols(total(), P31) %>%
        tab_cells(P901) %>%
        tab_subtotal_cells(
            "Bottom" = 1:6,
            "Top" = 9:10,
            position = "below"
        ) %>%
        tab_stat_cpct(total_row_position = "below") %>%
        tab_cells(na_if(P901, gt(10))) %>%
        tab_stat_mean() %>%
        tab_pivot()
)

Figura 6.11: Uso de top y bottom abajo

O también …

val_lab(data$P901) <-
    c(
        "1" = 1,
        "2" = 2,
        "3" = 3,
        "4" = 4,
        "5" = 5,
        "6" = 6,
        "7" = 7,
        "8" = 8,
        "9" = 9,
        "10" = 10,
        "N.S." = 98,
        "N.C." = 99
    )
as.datatable_widget(
    data %>%
        tab_cols(total(), P31) %>%
        tab_cells(P901) %>%
        tab_net_cells("Top" = 9:10, "Bottom" = 1:6) %>%
        tab_stat_cpct(total_row_position = "below") %>%
        tab_cells(na_if(P901, gt(10))) %>%
        tab_stat_mean() %>%
        tab_pivot()
)

Figura 6.12: Uso de top y bottom sin los valores agrupados

Así pues en esta última tabla, hemos combinado algunas de las funcionalidades especiales y avanzadas de expss de forma conjunta y trabajando en la misma dirección.

6.6.1 Gráficos base

Dejamos además aquí esta pildora adictiva adelantándonos a la sección 8. Vamos a crear el primer gráfico en este libro. Vamos a repetir la tabla anterior, pero la guardamos en un objeto llamado tab. Limpiamos además aquello que no nos interesa, lo convertimos y lo publicamos en su formato bruto o estándar, es decir como dataframe.

tab <- data %>%
    tab_cols("|" = unvr(P31)) %>%
    tab_cells("|" = unvr(P901)) %>%
    tab_net_cells(
        "Detractores" = 1:6,
        "Neutrales" = 7:8,
        "Promotores" = 9:10
    ) %>%
    tab_stat_cpct(total_row_position = "none") %>%
    tab_pivot()
tab <- as.data.frame(tab)
tab
##    row_labels     Hombre      Mujer
## 1 Detractores 19.1878981 21.9062260
## 2   Neutrales 48.4076433 40.3535742
## 3  Promotores 30.7324841 36.3566487
## 4        N.S.  1.5127389  1.0760953
## 5        N.C.  0.1592357  0.3074558

Fíjate como hemos limpiado la tabla. Hemos usado un recurso que para gráficos será muy válido, el uso de unvr() que elimina del uso de la variable los textos extra. Del mismo modo con el "|"= hemos anulado cualquier tipo de texto suplementario que se pudiera añadir. Cuando hacemos una tabla y la guardamos, es un objeto etable que ya describimos anteriormente. Como la mayoría de los paquetes gráficos usan _dataframe_, lo transformamos a eso.

Una vez hecho esto, hacemos el gráfico. Podemos elegir diferentes sistemas de gráficos, pero los más habituales e interactivos son highcharter(paquete escrito sobre Highcharts) y/o plotly. Como paquete estático, ggplot sería la mejor solución.

suppressMessages(library(highcharter, quietly = TRUE))
highchart() %>%
    hc_xAxis(categories = tab$row_labels) %>%
    hc_add_series(
        data = tab,
        type = "column",
        hcaes(x = row_labels, y = Hombre),
        name = "hombre"
    ) %>%
    hc_add_series(
        data = tab,
        type = "column",
        hcaes(x = row_labels, y = Mujer),
        name = "mujer"
    )

Figura 6.13: Uso de gráfico highcharter 2

Alternativamente, si queremos utilizar el paquete plotly

Grupo <- factor(tab$row_labels, levels = tab$row_labels)
plot_ly(
    tab,
    x = ~ Grupo,
    y = ~ Hombre,
    type = "bar",
    name = "Hombre"
) %>%
    add_trace(y = ~ Mujer, name = "Mujer") %>%
    layout(yaxis = list(title = "frecuencia"))

Figura 6.14: Uso de gráfico con plotly

Y esto es todo en cuanto a tablas básicas. La siguiente sección (7), con una carácter más estadístico, se introduce en las pruebas de significación que se usan en las tablas de contingencia. Si no te resultan de interés o si ya estás con ganas de gráficos, puedes saltar a la sección (8) y sumergirte en el mundo gráfico.

Bibliografía

Biemer, Paul P, and Sharon L Christ. 2008. “Weighting Survey Data.” International Handbook of Survey Methodology 2008: 317–41.
Mohler, Peter Ph, Beth-Ellen Pennell, and Frost Hubbard. 2008. “Survey Documentation: Toward Professional Knowledge Management in Sample Surveys.” International Handbook of Survey Methodology, 403–20.