Visualizando respuestas Likert usando R o SPSS

19

Tengo 82 encuestados en 2 grupos (43 en el Grupo A y 39 en el Grupo B) que completaron una encuesta de 65 preguntas Likert, cada una con un rango de 1 a 5 (totalmente de acuerdo - totalmente en desacuerdo). Por lo tanto, tengo un marco de datos con 66 columnas (1 para cada pregunta + 1 que indica la asignación de grupo) y 82 filas (1 para cada encuestado).

Al usar R o SPSS, ¿alguien conoce una buena manera de visualizar estos datos?

Necesito algo como esto: ingrese la descripción de la imagen aquí
(de Jason Bryer )

Pero no puedo hacer que funcione la sección inicial del código. Alternativamente, encontré muy buenos ejemplos de cómo visualizar datos Likert de una publicación cruzada validada anterior: Visualizar datos de respuesta de elementos Likert, pero no hay guías o instrucciones sobre cómo crear estos gráficos de conteo centrado o diagramas de barras apiladas usando R o SPSS.

Adán
fuente
1
Hola Adam, para aclarar más, ¿querías usar las visualizaciones para mostrar las diferencias entre los grupos? Si es así, ese no es un método recomendado.
Michelle
El paquete de Jason Bryer no solía funcionar para mí, pero creo que lo actualizó, y está funcionando muy bien en este momento. También agregué una solicitud de extracción con una función adicional para almacenar nombres de columnas como atributos y grupos. Utilizando esto, puedo visualizar fácilmente un cuestionario Likert de 45 preguntas dividido en grupos, incluso dividido en otra variable si lo elijo. (Realicé la salida con knitr, por lo que termina con muchos subtramas en un sitio web, no una trama gigantesca). Hice una reseña detallada aquí: reganmian.net/blog/2013/10/02/…
Stian Håklev
Solo para su información, para aquellos de ustedes que lean estas respuestas en el futuro, parece que algunas de las características y funcionalidades de irutils con respecto a los datos de likert se han trasladado al paquete Likert R ( vea CRAN aquí ).
firefly2442
El enlace bryer.org/2011/visualizing-likert-items parece estar roto. Una corrección o reemplazo sería bienvenida.
Nick Cox
1
Este tipo de pregunta, con su fuerte enfoque en un código específico, es menos bienvenida en 2018 que en 2012. Independientemente de eso, algunas referencias cruzadas para cualquier persona interesada en esto son stats.stackexchange.com/questions/56322/ … Y stats.stackexchange.com/questions/148554/…
Nick Cox

Respuestas:

30

Si realmente desea utilizar gráficos de barras apilados con una cantidad tan grande de elementos, aquí hay dos posibles soluciones.

Utilizando irutils

Encontré este paquete hace unos meses.

A partir de la confirmación 0573195c07 en Github , el código no funcionará con un grouping=argumento. Vayamos a la sesión de depuración del viernes.

Comience descargando una versión comprimida de Github. Tendrá que hackear el R/likert.Rarchivo, específicamente las funciones likerty plot.likert. Primero, se usa in likert, cast()pero el reshapepaquete nunca se carga (aunque hay una import(reshape)instrucción en el NAMESPACEarchivo). Puede cargar esto usted mismo de antemano. En segundo lugar, hay una instrucción incorrecta para buscar etiquetas de elementos, donde a iestá colgando alrededor de la línea 175. Esto también debe corregirse, por ejemplo, reemplazando todas las ocurrencias de likert$items[,i]con likert$items[,1]. Luego puede instalar el paquete de la forma en que está acostumbrado en su máquina. En mi Mac, lo hice

% tar -czf irutils.tar.gz jbryer-irutils-0573195
% R CMD INSTALL irutils.tar.gz

Luego, con R, intente lo siguiente:

library(irutils)
library(reshape)

# Simulate some data (82 respondents x 66 items)
resp <- data.frame(replicate(66, sample(1:5, 82, replace=TRUE)))
resp <- data.frame(lapply(resp, factor, ordered=TRUE, 
                          levels=1:5, 
                          labels=c("Strongly disagree","Disagree",
                                   "Neutral","Agree","Strongly Agree")))
grp <- gl(2, 82/2, labels=LETTERS[1:2]) # say equal group size for simplicity

# Summarize responses by group
resp.likert <- likert(resp, grouping=grp)

Eso debería funcionar, pero la representación visual será horrible debido a la gran cantidad de elementos. Sin plot(likert(resp))embargo, funciona sin agrupación (por ejemplo, ).

ingrese la descripción de la imagen aquí

Por lo tanto, sugeriría reducir su conjunto de datos a subconjuntos más pequeños de elementos. Por ejemplo, usando 12 artículos,

plot(likert(resp[,1:12], grouping=grp))

Me sale un gráfico de barras "legible". Probablemente puedas procesarlos después. (Esos son ggplot2objetos, ¡pero no podrá organizarlos en una sola página gridExtra::grid.arrange()debido a un problema de legibilidad!)

ingrese la descripción de la imagen aquí

Solución alternativa

Me gustaría llamar su atención sobre otro paquete, HH , que permite trazar escalas Likert como gráficos de barras apiladas divergentes. Podríamos reutilizar el código anterior como se muestra a continuación:

resp.likert <- likert(resp)
detach(package:irutils)
library(HH)
plot.likert(resp.likert$results[,-6]*82/100, main="")

pero eso complicará un poco las cosas porque necesitamos convertir frecuencias a conteos, subconjunto del likertobjeto producido por irutils, separar paquete, etc. Así que comencemos nuevamente con estadísticas nuevas (conteos):

plot.likert(t(apply(resp, 2, table)), main="", as.percent=TRUE,
            rightAxisLabels=NULL, rightAxis=NULL, ylab.right="", 
            positive.order=TRUE)

ingrese la descripción de la imagen aquí

Para usar una variable de agrupación, deberá trabajar con arrayvalores numéricos.

# compute responses frequencies separately by grp
resp.array <- array(NA, dim=c(66, 5, 2))
resp.array[,,1] <- t(apply(subset(resp, grp=="A"), 2, table))
resp.array[,,2] <- t(apply(subset(resp, grp=="B"), 2, table))
dimnames(resp.array) <- list(NULL, NULL, group=levels(grp))
plot.likert(resp.array, layout=c(2,1), main="")

Esto producirá dos paneles separados, pero cabe en una sola página.

ingrese la descripción de la imagen aquí

Editar 2016-6-3

  1. A partir de ahora, likert está disponible como paquete separado.
  2. No necesita reformar la biblioteca ni desconectar irutils y remodelar
chl
fuente
La última trama me recuerda a las pirámides de población. Deberíamos obtener algunos datos reales para ver cómo funcionan "en la naturaleza", con algunos datos que no son tan ordenados. Sin embargo, admito que son llamativos y bonitos.
Andy W
@Andy Ese es el caso, de hecho. Ver HH::as.pyramidLikert.
chl
1
+1, la biblioteca (HH) es definitivamente el camino a seguir. Pero algo salió mal con tu segundo último complot en el orden de acuerdo / desacuerdo, etc.
Peter Ellis
@PeterEllis Sí, parece que las categorías de respuesta están en el orden incorrecto, de hecho. (El orden de las etiquetas se perdió al tabular los datos, y los nombres de las tablas se ordenan siguiendo el orden lexicográfico). Para un truco rápido, podemos reemplazarlo t(apply(resp, 2, table))por t(apply(resp, 2, table))[,levels(resp[,1])]. ¡Y +1 para ti también!
chl
7

Comencé a escribir una publicación de blog sobre la recreación de muchos de los cuadros en la publicación que menciona ( Visualizar datos de respuesta de elementos Likert ) en SPSS, así que supongo que esto será una buena motivación para terminarlo.

Como señala Michelle, el hecho de que tenga grupos es un nuevo giro en comparación con las preguntas anteriores. Y si bien los grupos se pueden tener en cuenta utilizando los gráficos de barras apiladas, IMO se incorporan mucho más fácilmente en el ejemplo de diagrama de puntos en la publicación original de chl. He incluido el código SPSS para generar esto al final de la publicación, esencialmente implica saber cómo reformar sus datos en el formato apropiado para generar dicho gráfico (anotación proporcionada en el código para aclarar algo de eso). Aquí utilicé una codificación redundante (color y forma) para distinguir los puntos que provienen de los dos grupos, e hice los puntos semitransparentes para que pueda saber cuándo se superponen (otra opción sería esquivar los puntos cuando se superponen).

Figura 1: Gráficos de puntos por grupo

¿Por qué es esto mejor que los gráficos de barras apiladas? Los gráficos de barras apiladas codifican información en la longitud de las barras. Cuando intenta hacer comparaciones entre longitudes de barras, ya sea dentro de la misma categoría de eje o entre paneles, el apilamiento impide que las barras tengan una escala común. Por ejemplo, proporcioné una imagen en la Figura 2 en la que dos barras se colocan en un gráfico en el que su ubicación inicial es diferente, ¿qué barra es la más ancha (a lo largo del eje horizontal)?

Figura 2: Barras sin una escala común

Compare eso con el gráfico de la Figura 3 a continuación, en el que las dos barras (de la misma longitud) se trazan desde el mismo punto inicial. Intencionalmente he hecho la tarea difícil, pero deberías poder decir cuál es más larga.

Figura 3: Barras con una escala común

Los gráficos de barras apiladas básicamente hacen lo que se muestra en la Figura 2. Los gráficos de puntos pueden considerarse más similares a lo que se muestra en la Figura 3, simplemente reemplace la barra con un punto al final de la barra.

No voy a decir que no genere ningún gráfico en particular para el análisis exploratorio de datos, pero sugeriría evitar los gráficos de barras apiladas cuando se usan tantas categorías. Las gráficas de puntos tampoco son una panacea, pero creo que hacer comparaciones entre paneles con las gráficas de puntos es mucho más fácil que con los gráficos de barras apiladas. Considere algunos de los consejos que proporciono en mi blog aquí para las tablas también, intente ordenar y / o separar los cuadros en categorías significativas, y asegúrese de que los elementos que desee ver en conjunto estén más juntos en los cuadros. Si bien algunos de los métodos de trazado pueden ajustarse bien a muchas preguntas (los mapas de calor categóricos son un ejemplo), sin clasificar aún será difícil identificar cualquier patrón significativo (además de valores atípicos obvios).

Una nota sobre el uso de SPSS. SPSS puede generar cualquiera de los enlaces anteriores a los gráficos, aunque a menudo implica saber cómo dar forma a sus datos (lo mismo ocurre con ggplot, pero la gente ha estado desarrollando paquetes para esencialmente hacer la remodelación por usted). Para entender cómo funciona mejor el lenguaje GPL de SPSS, sugiero leer el libro de Hadley Wickham sobre ggplot2en el uso R! serie. Presenta la gramática necesaria para comprender cómo funciona la GPL de SPSS, y es una lectura mucho más fácil que el manual de programación de GPL que viene con SPSS. Si tiene alguna pregunta sobre la generación de gráficos específicos en SPSS, sería mejor hacer una pregunta para un gráfico (¡ya he hablado lo suficiente aquí!) Actualizaré esta respuesta con un enlace si alguna vez llego a hacer mi publicación de blog que replica algunos de los otros gráficos. Para una prueba de concepto de los mapas de calor o gráficos de fluctuación, puede ver otra publicación mía del blog, algunos ejemplos de Corrgrams en SPSS .

Código SPSS utilizado para generar la Figura 1

****************************************.
input program. */making fake data similar to yours.
loop #i = 1 to 82.
compute case_num = #i.
end case.
end loop.
end file.
end input program.
execute.
dataset name likert.

*making number in groups.
compute group = 1.
if case_num > 43 group = 2.
value labels group
1 'A'
2 'B'.

*this makes 5 variables with categories between 0 and 5 (similar to Likert data with 5 categories plus missing data).
vector V(5).
do repeat V = V1 to V5.
compute V = TRUNC(RV.UNIFORM(0,6)).
end repeat.
execute.

value labels V1 to V5
0 'missing'
1 'very disagree'
2 'disagree'
3 'neutral'
4 'agree'
5 'very agree'.
formats case_num group V1 to V5 (F1.0).
*****************************************.

*Because I want to panel by variable, I am going to reshape my data so all of the "V" variables are in one column (stacking them in long format).
varstocases
/make V from V1 to V5
/index orig (V).

*I am going to plot the points, so I aggregate that information (you could aggregate total counts as well if you wanted to plot percentages.
DATASET DECLARE agg_lik.
AGGREGATE
  /OUTFILE='agg_lik'
  /BREAK=orig V group
  /count_lik=N.
dataset activate agg_lik.


*now the fun part, generating the chart.
*The X axis, dim(1) is the count of likert responses within each category for each original question.
*The Y axis, dim(2) is the likert responses, and the third axis is used to panel the observations by the original questions, dim(4) here beacause I want to panel
by rows instead of columns.
DATASET ACTIVATE agg_lik.
* Chart Builder.
GGRAPH
  /GRAPHDATASET NAME="graphdataset" VARIABLES=count_lik V group orig 
    MISSING=LISTWISE REPORTMISSING=NO
  /GRAPHSPEC SOURCE=INLINE.
BEGIN GPL
  SOURCE: s=userSource(id("graphdataset"))
  DATA: count_lik=col(source(s), name("count_lik"))
  DATA: V=col(source(s), name("V"), unit.category())
  DATA: group=col(source(s), name("group"), unit.category())
  DATA: orig=col(source(s), name("orig"), unit.category())
  GUIDE: axis(dim(1), label("Count"))
  GUIDE: axis(dim(2))
  GUIDE: axis(dim(4))
  GUIDE: legend(aesthetic(aesthetic.color.exterior), label("group"))
  GUIDE: text.title(label("Figure 1: Dot Plots by Group"))
  SCALE: cat(aesthetic(aesthetic.color.exterior), include("1", "2"))
  SCALE: cat(aesthetic(aesthetic.shape), map(("1", shape.circle), ("2", shape.square)))
  ELEMENT: point(position(count_lik*V*1*orig), color.exterior(group), color.interior(group), transparency.interior(transparency."0.7"), size(size."8px"), shape(group))
END GPL.
*The "SCALE: cat" statements map different shapes which I use to assign to the two groups in the plot, and I plot the interior of the points as partially transparent.
*With some post hoc editing you should be able to make the chart look like what I have in the stats post.
****************************************.
Andy W
fuente
Una gran ventaja de mi parte por discutir cortés pero penetrantemente las deficiencias de los gráficos de barras apiladas, que son fáciles de entender en principio pero a menudo mucho menos fáciles de descifrar en la práctica.
Nick Cox
5

Bueno, se me ocurrió el código antes de que lo aclararas. Debería haber esperado pero pensé que debería publicarlo para que cualquiera que venga aquí pueda reutilizar este código.

Datos ficticios para visualizar

# Response for http://stats.stackexchange.com/questions/25109/visualizing-likert-responses-using-r-or-spss
# Load libraries
library(reshape2)
library(ggplot2)

# Functions
CreateRowsColumns <- function(noofrows, noofcolumns) {
createcolumnnames <- paste("Q", 1:noofcolumns, sep ="")
df <- sapply(1:noofcolumns, function(i) assign(createcolumnnames[i], matrix(sample(1:5, noofrows, replace = TRUE))))
df <- sapply(1:noofcolumns, function(i) df[,i] <- as.factor(df[,i]))
colnames(df) <- createcolumnnames
return(df)}

# Generate dummy dataframe
LikertResponse <- CreateRowsColumns(82, 65)
LikertResponse[LikertResponse == 1] <- "Strongly agree"
LikertResponse[LikertResponse == 2] <- "Agree"
LikertResponse[LikertResponse == 3] <- "Neutral"
LikertResponse[LikertResponse == 4] <- "Disagree"
LikertResponse[LikertResponse == 5] <- "Strongly disagree"

Código para mapa de calor

# Prepare data
LikertResponseSummary <- do.call(rbind, lapply(data.frame(LikertResponse), table))
LikertResponseSummaryPercent <- prop.table(LikertResponseSummary,1)

# Melt data
LikertResponseSummary <- melt(LikertResponseSummary)
LikertResponseSummaryPercent <- melt(LikertResponseSummaryPercent)

# Merge counts with proportions
LikertResponsePlotData <- merge(LikertResponseSummary, LikertResponseSummaryPercent, by = c("Var1","Var2"))

# Plot heatmap!
# Use the "geom_tile(aes(fill = value.y*100), colour = "white")" to control how you want the heatmap colours to map to.
ggplot(LikertResponsePlotData, aes(x = Var2, y = Var1)) +
    geom_tile(aes(fill = value.y*100), colour = "white") +
    scale_fill_gradient(low = "white", high = "steelblue", name = "% of Respondents") +
    scale_x_discrete(name = 'Response') +
    scale_y_discrete(name = 'Questions') +
    geom_text(aes(label = paste(format(round(value.y*100), width = 3), '% (', format(round(value.x), width = 3), ')')), size = 3) 

Esto es básicamente una plantilla para visualizar los elementos de Likert en un mapa de calor del sitio web de Jason Bryon.

RJ-
fuente
1
github.com/jbryer/irutils/blob/master/R/likert.R es la fuente de los gráficos de barras apiladas que desea.
RJ-
Para aclarar, no quiero comparar entre grupos. Solo para presentar las respuestas de ambos grupos de una manera sofisticada. Esta es una gran respuesta. Realmente lo aprecio. Gracias.
Adam
3

El código de @ RJ produce un gráfico como este, que en realidad es una tabla con celdas sombreadas. Es bastante ocupado y un poco difícil de descifrar. Una tabla simple sin sombreado podría ser más efectiva (y también puede poner los datos en un orden más significativo).

ingrese la descripción de la imagen aquí

Por supuesto, depende del mensaje principal que intentes comunicar, pero creo que es más simple y fácil de entender. También tiene las preguntas y respuestas en un orden lógico (¡sobre todo!).

    library(stringr)
    LikertResponseSummary$Var1num <- 
      as.numeric(str_extract(LikertResponseSummary$Var1, "[0-9]+"))
    LikertResponseSummary$Var2 <- 
      factor(LikertResponseSummary$Var2, 
      levels =  c("Strongly disagree", "Disagree", "Neutral", "Agree", "Strongly agree"))

ggplot(LikertResponseSummary, 
       aes(factor(Var1num), value, fill = factor(Var2))) + 
       geom_bar(position="fill") +
       scale_x_discrete(name = 'Question', breaks=LikertResponseSummary$Var1num,
                        labels=LikertResponseSummary$Var1) +
       scale_y_continuous(name = 'Proportion') +
       scale_fill_discrete(name = 'Response') +
       coord_flip()

ingrese la descripción de la imagen aquí

Ben
fuente
Acordó que el gráfico parece ocupado. Sin embargo, sería útil si las preguntas se agrupan en algún tipo de orden, por ejemplo, P1-10 pregunta sobre una determinada dimensión y así sucesivamente. De un vistazo, si las tendencias son obvias, los colores lo dirían.
RJ-