Визуализация ответов Лайкерта с использованием R или SPSS


19

У меня есть 82 респондента в 2 группах (43 в группе A и 39 в группе B), которые завершили опрос по 65 вопросов Лайкерта, каждый в диапазоне от 1 до 5 (полностью согласен - категорически не согласен). Поэтому у меня есть фрейм данных с 66 столбцами (1 для каждого вопроса + 1, указывающий на распределение групп) и 82 строками (1 для каждого респондента).

Используя R или SPSS кто-нибудь знает хороший способ визуализации этих данных.

Мне нужно что-то вроде этого: введите описание изображения здесь
(от Джейсона Брайера )

Но я не могу заставить начальный раздел кода работать. Кроме того, я нашел действительно хорошие примеры того, как визуализировать данные Лайкерта из предыдущего поста с перекрестной проверкой: Визуализация данных отклика элемента Лайкерта, но нет руководств или инструкций о том, как создавать эти графики с центрированным счетчиком или составные столбцы с использованием R или SPSS.


1
Привет, Адам, чтобы уточнить, ты хотел использовать визуализации, чтобы показать различия между группами? Если так, то это не рекомендуемый метод.
Мишель

Пакет Джейсона Брайера не работал на меня, но я думаю, что он обновил его, и сейчас он работает прекрасно. Я также добавил pull-запрос с дополнительной функцией для хранения имен столбцов как атрибутов, так и групп. Используя это, я легко могу визуализировать вопросник Лайкерта из 45 вопросов, разбитый на группы, и даже разделить по другой переменной, если я решу. (Я выводлю, используя knitr, так что в итоге получается столько же сюжетов на сайте, а не один гигантский сюжет). Я сделал подробную запись здесь: reganmian.net/blog/2013/10/02/…
Stian Håklev

Просто к вашему сведению, для тех, кто читает эти ответы в будущем, похоже, что некоторые функции и функциональные возможности irutils в отношении данных likert были перенесены в пакет Likert R ( см. CRAN здесь ).
firefly2442

Ссылка bryer.org/2011/visualizing-likert-items не работает. Исправление или замена будет приветствоваться.
Ник Кокс

1
Этот тип вопроса - с его сильным акцентом на конкретный код - менее желателен в 2018 году, чем в 2012 году. Независимо от этого, некоторые перекрестные ссылки для всех, кто заинтересован в этом, являются stats.stackexchange.com/questions/56322/ … И stats.stackexchange.com/questions/148554/…
Ник Кокс

Ответы:


30

Если вы действительно хотите использовать составные столбцы с таким большим количеством элементов, вот два возможных решения.

С помощью irutils

Я столкнулся с этим пакетом несколько месяцев назад.

Начиная с комита 0573195c07 на Github , код не будет работать с grouping=аргументом. Давайте пойдем на сессию отладки в пятницу.

Начните с загрузки заархивированной версии с Github. Вам нужно взломать R/likert.Rфайл, в частности likertи plot.likertфункции. Сначала используется in likert, cast()но reshapeпакет никогда не загружается (хотя import(reshape)в NAMESPACEфайле есть инструкция ). Вы можете загрузить это самостоятельно заранее. Во- вторых, есть неправильная инструкция для получения элементов этикетки, где iболтается вокруг линии 175. Это должен быть закреплен , а также, например , путем замены всех вхождений likert$items[,i]с likert$items[,1]. Затем вы можете установить пакет так, как вы привыкли делать на вашем компьютере. На моем Mac я сделал

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

Затем с помощью R попробуйте следующее:

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)

Это должно сработать, но визуальный рендеринг будет ужасным из-за большого количества элементов. Это работает без группировки (например, plot(likert(resp))), хотя.

введите описание изображения здесь

Таким образом, я бы предложил сократить ваш набор данных до меньших подмножеств элементов. Например, используя 12 предметов,

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

Я получаю «читабельную» составную диаграмму. Вы можете, вероятно, обработать их потом. (Это ggplot2объекты, но вы не сможете разместить их на одной странице gridExtra::grid.arrange()из-за проблем с читабельностью!)

введите описание изображения здесь

Альтернативное решение

Я хотел бы обратить ваше внимание на другой пакет, HH , который позволяет изображать шкалы Лайкерта как расходящиеся столбчатые диаграммы. Мы могли бы использовать вышеуказанный код, как показано ниже:

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

но это немного усложнит ситуацию, потому что нам нужно преобразовать частоты в счетчики, задать подмножество likertобъекта, созданного с помощью irutils, отсоединить пакет и т. д. Итак, давайте начнем снова со свежей статистики (счетчиков):

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

введите описание изображения здесь

Чтобы использовать группирующую переменную, вам нужно работать с arrayчисловыми значениями.

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

Это создаст две отдельные панели, но умещается на одной странице.

введите описание изображения здесь

Редактировать 2016-6-3

  1. На данный момент likert доступен в виде отдельного пакета.
  2. Вам не нужно изменить библиотеку или отсоединять как irutils и Reshape

Последний сюжет напоминает мне пирамиды населения. Мы должны получить некоторые реальные данные, чтобы увидеть, как они работают «в дикой природе», с некоторыми данными, которые не так упорядочены. Я признаю, что они бросаются в глаза и симпатичны все же.
Энди W

@Анди, это действительно так. См HH::as.pyramidLikert.
ЧЛ

1
+1, библиотека (HH) - определенно путь. Но что-то пошло не так с вашим вторым последним сюжетом в порядке «согласен / не согласен и т. Д.»
Питер Эллис,

@PeterEllis Да, похоже, категории ответов находятся в неправильном порядке. (Порядок меток был потерян при табулировании данных, а имена таблиц расположены в соответствии с лексикографическим порядком.) Для быстрого взлома мы можем просто заменить t(apply(resp, 2, table))на t(apply(resp, 2, table))[,levels(resp[,1])]. И +1 тебе тоже!
ЧЛ

7

Я начал писать пост в блоге о воссоздании многих диаграмм в посте, который вы упомянули ( Визуализация данных ответа Лайкерта ) в SPSS, поэтому я полагаю, что это будет хорошей мотивацией для его завершения.

Как отмечает Мишель, тот факт, что у вас есть группы, является новым поворотом по сравнению с предыдущими вопросами. И хотя группы могут учитываться с помощью гистограмм с накоплением, IMO их гораздо легче включить в пример точечного графика в исходном посте chl. Я включил код SPSS для генерации этого в конце поста, по сути, он подразумевает знание того, как изменить ваши данные в соответствующий формат для генерации указанного графика (аннотация, предоставленная в коде, надеюсь, прояснит некоторые из них). Здесь я использовал некоторую избыточную кодировку (цвет и форму), чтобы различать точки, приходящие от двух групп, и сделал точки полупрозрачными, чтобы вы могли определить, когда они перекрываются (другой вариант - уклоняться от точек, когда они перекрываются).

Рисунок 1: Точечные графики по группам

Почему это лучше, чем гистограммы с накоплением? Гистограммы с накоплением кодируют информацию в длину столбцов. Когда вы пытаетесь провести сравнение между длинами стержней, либо в пределах одной категории осей, либо между панелями, наложение препятствует тому, чтобы стержни имели общий масштаб. В качестве примера я привел изображение на рис. 2, на котором два графика расположены на графике, на котором их начальное расположение отличается, какой столбец является более широким (вдоль горизонтальной оси)?

Рисунок 2: Прутки без общего масштаба

Сравните это с графиком на рисунке 3 ниже, на котором два столбца (одинаковой длины) построены с одной и той же начальной точки. Я намеренно усложнил задачу, но вы должны сказать, какая из них длиннее.

Рисунок 3: Бары с общим масштабом

Сложенные столбчатые диаграммы по сути делают то, что показано на рисунке 2. Точечные графики можно считать более похожими на те, что показаны на рисунке 3, просто замените столбец точкой на конец столбца.

Я не собираюсь говорить, не генерируйте какую-либо конкретную диаграмму для анализа поисковых данных, но я бы предложил избегать гистограмм с накоплением при использовании такого количества категорий. Точечные графики также не являются панацеей, но я считаю, что сравнивать панели с точечными графиками гораздо проще, чем с помощью гистограмм с накоплением. Подумайте над некоторыми советами, которые я даю в своем блоге здесь, для таблиц, попробуйте упорядочить и / или разделить диаграммы на значимые категории, и убедитесь, что элементы, которые вы хотите просмотреть в тандеме, находятся ближе друг к другу в диаграммах. Хотя некоторые из методов построения графика могут хорошо масштабироваться на многие вопросы (например, категориальные тепловые карты), без сортировки все равно будет трудно определить какие-либо значимые закономерности (помимо очевидных выбросов).

Примечание по использованию SPSS. SPSS может генерировать любую из предыдущих ссылок, связанных с диаграммами, хотя это часто подразумевает знание того, как формировать ваши данные (то же самое верно и для ggplot, но люди разрабатывают пакеты, чтобы по сути сделать изменение формы за вас). Чтобы понять, как лучше работает язык GPL в SPSS, я бы предложил почитать книгу Хэдли Уикхема на ggplot2.в использовании R! серии. В нем изложена грамматика, необходимая для понимания работы GPL в SPSS, и ее гораздо легче прочитать, чем руководство по программированию GPL, поставляемое с SPSS! Если у вас есть какие-либо вопросы о создании конкретных диаграмм в SPSS, было бы лучше задать один вопрос для одной диаграммы (я уже достаточно обговорил здесь!), Я обновлю этот ответ ссылкой, хотя, если когда-нибудь смогу сделать свой сообщение в блоге, копирующее некоторые другие диаграммы. Для доказательства концепции тепловых карт или графиков колебаний вы можете увидеть еще одну мою запись в блоге, Некоторые примеры Corrgrams в SPSS .

Код SPSS, использованный для генерации рисунка 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.
****************************************.

Сильный плюс от меня за вежливое, но проницательное обсуждение недостатков гистограмм с накоплением, которые в принципе просты для понимания, а на практике зачастую гораздо проще.
Ник Кокс

5

О, хорошо, я придумал код, прежде чем вы пояснили. Должен был подождать, но подумал, что я должен опубликовать это, чтобы любой, кто приходит сюда, мог повторно использовать этот код

Фиктивные данные для визуализации

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

Код для тепловой карты

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

Это в основном шаблон для визуализации предметов Лайкерта на тепловой карте с сайта Джейсона Брайона.


1
github.com/jbryer/irutils/blob/master/R/likert.R - это источник нужных вам гистограмм с накоплением.
RJ-

Чтобы уточнить, я не хочу сравнивать между группами. Просто представить ответы обеих групп в изощренной форме. Это отличный ответ. Действительно ценю это. Благодарю.
Адам

3

Код @ RJ создает такой график, который на самом деле представляет собой таблицу с затененными ячейками. Это довольно занят и немного сложно расшифровать. Простая таблица без затенения может быть более эффективной (и вы также можете разместить данные в более значимом порядке).

введите описание изображения здесь

Конечно, это зависит от того, какое главное сообщение вы пытаетесь передать, но я думаю, что это проще и немного легче понять. Он также содержит вопросы и ответы в (в основном!) Логическом порядке.

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

введите описание изображения здесь


Договорились, что график выглядит занятым. Однако было бы полезно, если бы вопросы были сгруппированы в некотором порядке, например, Q1 - 10 задает вопрос об определенном измерении и так далее. С первого взгляда, если тенденции очевидны, цвета скажут.
RJ-
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.