Visualizzazione delle risposte di Likert tramite R o SPSS


19

Ho 82 intervistati in 2 gruppi (43 nel gruppo A e 39 nel gruppo B) che hanno completato un sondaggio su 65 domande Likert che vanno da 1 a 5 (fortemente d'accordo - fortemente in disaccordo). Ho quindi un frame di dati con 66 colonne (1 per ogni domanda + 1 che indica l'allocazione di gruppo) e 82 righe (1 per ogni intervistato).

Utilizzando R o SPSS qualcuno conosce un bel modo per visualizzare questi dati.

Ho bisogno di qualcosa del genere: inserisci qui la descrizione dell'immagine
(da Jason Bryer )

Ma non riesco a far funzionare la sezione iniziale del codice. In alternativa, ho trovato esempi davvero validi su come visualizzare i dati Likert da un precedente post con convalida incrociata: Visualizzazione dei dati di risposta degli articoli Likert ma non ci sono guide o istruzioni su come creare questi grafici di conteggio centrati o grafici a barre impilati utilizzando R o SPSS.


1
Ciao Adam, per chiarire ulteriormente, volevi usare le visualizzazioni per mostrare le differenze tra i gruppi? In tal caso, questo non è un metodo consigliato.
Michelle,

Il pacchetto di Jason Bryer non funzionava con me, ma penso che l'abbia aggiornato, e ora funziona magnificamente. Ho anche aggiunto una richiesta pull con una funzione aggiuntiva per memorizzare i nomi delle colonne come attributi e gruppi. Usando questo, sono facilmente in grado di visualizzare un questionario di Likert a 45 domande diviso in gruppi, anche se diviso in un'altra variabile. (Ho prodotto usando knitr, quindi finisce con un sacco di sottotrame su un sito Web, non una trama gigantesca). Ho fatto una recensione dettagliata qui: reganmian.net/blog/2013/10/02/…
Stian Håklev

Cordiali saluti, per quelli di voi che leggono queste risposte in futuro, sembra che alcune delle caratteristiche e funzionalità di irutils riguardo ai dati likert siano state spostate nel pacchetto Likert R ( vedi CRAN qui ).
firefly2442,

Il link bryer.org/2011/visualizing-likert-items sembra essere rotto. Una correzione o sostituzione sarebbe il benvenuto.
Nick Cox,

1
Questo tipo di domanda - con la sua forte attenzione a un codice specifico - è meno gradita nel 2018 rispetto al 2012. A prescindere da ciò, alcuni riferimenti incrociati per chiunque sia interessato a questo sono stats.stackexchange.com/questions/56322/ … E stats.stackexchange.com/questions/148554/…
Nick Cox,

Risposte:


30

Se vuoi davvero usare i grafici a barre in pila con un numero così elevato di elementi, ecco due possibili soluzioni.

utilizzando irutils

Mi sono imbattuto in questo pacchetto alcuni mesi fa.

A partire dal commit 0573195c07 su Github , il codice non funzionerà con agrouping= argomento. Andiamo per la sessione di debug di venerdì.

Inizia scaricando una versione zippata da Github. Dovrai hackerare il R/likert.Rfile, in particolare le funzioni likerte plot.likert. Innanzitutto, viene utilizzato in likert, cast()ma il reshapepacchetto non viene mai caricato (anche se import(reshape)nel NAMESPACEfile è presente un'istruzione ). Puoi caricarlo tu stesso in anticipo. In secondo luogo, c'è un'istruzione errata per recuperare le etichette degli oggetti, dove a iè penzolante intorno alla linea 175. Anche questo deve essere corretto, ad esempio sostituendo tutte le occorrenze di likert$items[,i]con likert$items[,1]. Quindi puoi installare il pacchetto nel modo in cui sei abituato a fare sul tuo computer. Sul mio Mac, l'ho fatto

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

Quindi, con R, prova quanto segue:

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)

Dovrebbe funzionare, ma il rendering visivo sarà terribile a causa dell'elevato numero di elementi. Funziona senza raggruppamento (ad esempio, plot(likert(resp))), però.

inserisci qui la descrizione dell'immagine

Vorrei quindi suggerire di ridurre il set di dati a sottoinsiemi di elementi più piccoli. Ad esempio, utilizzando 12 articoli,

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

Ottengo un grafico a barre in pila "leggibile". Probabilmente puoi elaborarli in seguito. (Quelli sono ggplot2oggetti, ma non sarai in grado di disporli su un'unica pagina a gridExtra::grid.arrange()causa del problema di leggibilità!)

inserisci qui la descrizione dell'immagine

Soluzione alternativa

Vorrei attirare la vostra attenzione su un altro pacchetto, HH , che consente di tracciare le scale Likert come diagrammi a barre impilati divergenti. Potremmo riutilizzare il codice sopra come mostrato di seguito:

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

ma ciò complicherà un po 'le cose perché dobbiamo convertire le frequenze in conteggi, sottoinsiemare l' likertoggetto prodotto da irutils, staccare il pacchetto, ecc. Quindi ricominciamo con nuove statistiche (conteggi):

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

inserisci qui la descrizione dell'immagine

Per usare una variabile di raggruppamento, dovrai lavorare con uno arraydi valori numerici.

# 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="")

Ciò produrrà due pannelli separati, ma si adatta a una singola pagina.

inserisci qui la descrizione dell'immagine

Modifica 2016-6-3

  1. A partire da ora likert è disponibile come pacchetto separato.
  2. Non hai bisogno di rimodellare la libreria o staccare sia irutils che rimodellare

L'ultima trama mi ricorda le piramidi della popolazione. Dovremmo ottenere alcuni dati reali per vedere come funzionano "in natura", con alcuni dati che non sono così ordinati. Devo ammettere che sono accattivanti e belli però.
Andy W,

@Andy Questo è il caso, davvero. Vedere HH::as.pyramidLikert.
chl

1
+1, library (HH) è sicuramente la strada da percorrere. Ma qualcosa è andato storto nella tua ultima ultima trama nell'ordinamento di essere d'accordo / in disaccordo ecc.
Peter Ellis

@PeterEllis Sì, sembra che le categorie di risposta siano nell'ordine sbagliato, anzi. (L'ordine delle etichette è stato perso durante la tabulazione dei dati e i nomi delle tabelle sono disposti secondo l'ordine lessicografico.) Per un hack rapido, possiamo semplicemente sostituirlo t(apply(resp, 2, table))con t(apply(resp, 2, table))[,levels(resp[,1])]. E +1 anche a te!
chl

7

Ho iniziato a scrivere un post sul blog sulla ricostruzione di molti dei grafici nel post che menzioni ( Visualizzazione dei dati di risposta dell'articolo Likert ) in SPSS, quindi suppongo che questa sarà una buona motivazione per finirlo.

Come osserva Michelle, il fatto che tu abbia gruppi è una nuova svolta rispetto alle domande precedenti. E mentre i gruppi possono essere presi in considerazione usando i grafici a barre in pila, IMO sono molto più facilmente incorporati nell'esempio del diagramma a punti nel post originale di chl. Ho incluso il codice SPSS per generare questo alla fine del post, essenzialmente implica sapere come rimodellare i dati nel formato appropriato per generare tale trama (annotazione fornita nel codice per sperare di chiarire un po 'di quello). Qui ho usato una codifica ridondante (colore e forma) per distinguere i punti provenienti dai due gruppi e ho reso i punti semitrasparenti in modo da poter dire quando si sovrappongono (un'altra opzione sarebbe quella di schivare i punti quando si sovrappongono).

Figura 1: Dot Plots per gruppo

Perché è meglio dei grafici a barre in pila? I grafici a barre in pila codificano le informazioni nella lunghezza delle barre. Quando si tenta di effettuare confronti tra lunghezze di barre, all'interno della stessa categoria di assi o tra pannelli, l'impilamento impedisce alle barre di avere una scala comune. Per un esempio, ho fornito un'immagine in Figura 2 in cui due barre sono posizionate in un diagramma in cui la loro posizione iniziale è diversa, quale barra è quella più larga (lungo l'asse orizzontale)?

Figura 2: barre senza scala comune

Confrontalo con il diagramma nella Figura 3 in basso, in cui le due barre (della stessa lunghezza) sono tracciate dallo stesso punto iniziale. Ho intenzionalmente reso difficile il compito, ma dovresti essere in grado di dire quale è più lungo.

Figura 3: barre con una scala comune

I grafici a barre in pila stanno essenzialmente facendo ciò che è mostrato in Figura 2. I grafici a punti possono essere considerati più simili a quelli mostrati in Figura 3, basta sostituire la barra con un punto alla fine della barra.

Non dirò di non generare alcun grafico particolare per l'analisi dei dati esplorativi, ma suggerirei di evitare i grafici a barre in pila quando si utilizzano così tante categorie. Anche i grafici a punti non sono una panacea, ma credo che fare confronti tra pannelli con i grafici a punti sia molto più semplice che con i grafici a barre in pila. Considera alcuni dei consigli che fornisco qui sul mio post sul blog anche per le tabelle, prova a ordinare e / o separare i grafici in categorie significative e assicurati che gli elementi che vorresti guardare in tandem siano più vicini tra loro nei grafici. Mentre alcuni dei metodi di tracciamento possono adattarsi bene a molte domande (le mappe di calore categoriali sono un esempio), senza l'ordinamento sarà comunque difficile identificare eventuali schemi di significato (oltre a evidenti valori anomali).

Una nota sull'uso di SPSS. SPSS è in grado di generare uno qualsiasi dei precedenti collegati ai grafici, anche se spesso implica sapere come modellare i dati (lo stesso vale per ggplot, ma le persone hanno sviluppato pacchetti per fare essenzialmente il rimodellamento per te). Per capire come funziona meglio il linguaggio GPL di SPSS, suggerirei di leggere il libro di Hadley Wickham su ggplot2in Usa R! serie. Stabilisce la grammatica necessaria per capire come funziona la GPL di SPSS ed è molto più facile da leggere rispetto al manuale di programmazione GPL fornito con SPSS! In caso di domande sulla generazione di grafici specifici in SPSS, sarebbe meglio porre una domanda per un grafico (ne ho parlato abbastanza qui com'è!) Aggiornerò questa risposta con un link, tuttavia, se mai riesco a fare il mio post sul blog che replica alcuni degli altri grafici. Per una prova del concetto delle mappe di calore o dei grafici delle fluttuazioni puoi vedere un altro post sul mio blog, Alcuni esempi di corrgrammi in SPSS .

Codice SPSS utilizzato per generare 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.
****************************************.

Un grande vantaggio da parte mia per discutere educatamente ma penetrante delle carenze dei grafici a barre in pila, che sono facili da capire in linea di principio ma spesso molto meno facili da decodificare in pratica.
Nick Cox,

5

Oh bene, ho inventato il codice prima che tu chiarissi. Avrei dovuto aspettare, ma ho pensato di pubblicarlo in modo che chiunque venga qui possa riutilizzare questo codice.

Dati fittizi per la visualizzazione

# 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"

Codice per la mappa di calore

# 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) 

Questo è fondamentalmente un modello per visualizzare gli articoli Likert su una mappa di calore dal sito Web di Jason Bryon.


1
github.com/jbryer/irutils/blob/master/R/likert.R è la fonte per i grafici a barre in pila che desideri.
RJ

Per chiarire, non voglio confrontare tra i gruppi. Giusto per presentare le risposte di entrambi i gruppi in modo sofisticato. Questa è un'ottima risposta Lo apprezzo davvero. Grazie.
Adam

3

Il codice di @ RJ produce una trama come questa, che in realtà è una tabella con celle ombreggiate. È piuttosto occupato e un po 'difficile da decifrare. Una tabella semplice senza ombreggiatura potrebbe essere più efficace (e puoi anche mettere i dati in un ordine più significativo).

inserisci qui la descrizione dell'immagine

Ovviamente dipende dal messaggio principale che stai cercando di comunicare, ma penso che sia più semplice e un po 'più facile da capire. Ha anche le domande e le risposte in un ordine logico (principalmente!).

    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()

inserisci qui la descrizione dell'immagine


Concordato che il grafico sembra occupato. Sarebbe utile tuttavia se le domande fossero raggruppate in una sorta di ordine, ad esempio Q1 - 10 fa domande su una certa dimensione e così via. A colpo d'occhio se le tendenze sono evidenti, i colori lo direbbero.
RJ
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.