Using Jason Bryer’s likert
package, amended to summarise and plot using a summary of results
, without requiring the underlying data.
The results
object is akin to many summaries of data published for ordinal responses, where the underlying data is inaccessible (e.g. polling results), and also to many wide format summaries for ordinal outcomes generated from raw data (e.g. examination grades).
Changes to likert.R
and summary.likert.r
allow much of the same functionality using results
alone, without underlying data items
. It also allows for many smaller likert objects to be held in memory, without necessarily copying the underlying items in each object.
Install and load the amended package from github:
library("devtools")
install_github("m-dev-/likert")
library("likert")
## Loading required package: ggplot2
## Loading required package: xtable
data("pisaitems")
Using l29
from the likert
demo to make a complete object, including a copy of the underlying data held as items
:
##### Item 29: How often do you read these materials because you want to?
title <- "How often do you read these materials because you want to?"
items29 <- pisaitems[,substr(names(pisaitems), 1,5) == 'ST25Q']
head(items29); ncol(items29)
## ST25Q01 ST25Q02 ST25Q03
## 68038 A few times a year Several times a week Several times a month
## 68039 About once a month A few times a year Never or almost never
## 68040 About once a month Never or almost never A few times a year
## 68041 Several times a month A few times a year About once a month
## 68042 About once a month A few times a year About once a month
## 68043 A few times a year Never or almost never Never or almost never
## ST25Q04 ST25Q05
## 68038 A few times a year A few times a year
## 68039 Never or almost never Several times a week
## 68040 Never or almost never A few times a year
## 68041 A few times a year Several times a week
## 68042 Never or almost never Several times a month
## 68043 Never or almost never A few times a year
## [1] 5
names(items29) = c("Magazines", "Comic books", "Fiction", "Non-fiction books", "Newspapers")
l29 <- likert(items29)
str(l29)
## List of 6
## $ results :'data.frame': 5 obs. of 6 variables:
## ..$ Item : Factor w/ 5 levels "Comic books",..: 3 1 2 5 4
## ..$ Never or almost never: num [1:5] 10.2 36.7 17 30.9 18.8
## ..$ A few times a year : num [1:5] 20 25.7 24.7 30.6 18.5
## ..$ About once a month : num [1:5] 21.3 15.8 19.6 19.6 15.7
## ..$ Several times a month: num [1:5] 31 14.5 22.3 13.5 23.9
## ..$ Several times a week : num [1:5] 17.43 7.27 16.31 5.55 23.12
## $ items :'data.frame': 66690 obs. of 5 variables:
## ..$ Magazines : Factor w/ 5 levels "Never or almost never",..: 2 3 3 4 3 2 4 3 3 1 ...
## ..$ Comic books : Factor w/ 5 levels "Never or almost never",..: 5 2 1 2 2 1 1 1 3 3 ...
## ..$ Fiction : Factor w/ 5 levels "Never or almost never",..: 4 1 2 3 3 1 2 2 3 4 ...
## ..$ Non-fiction books: Factor w/ 5 levels "Never or almost never",..: 2 1 1 2 1 1 2 1 3 1 ...
## ..$ Newspapers : Factor w/ 5 levels "Never or almost never",..: 2 5 2 5 4 2 3 2 3 1 ...
## $ grouping: NULL
## $ factors : NULL
## $ nlevels : int 5
## $ levels : chr [1:5] "Never or almost never" "A few times a year" "About once a month" "Several times a month" ...
## - attr(*, "class")= chr "likert"
Create a likert object from results
, rather than from the underlying data:
l29s <- likert(summary = l29$results)
str(l29s)
## List of 5
## $ results :'data.frame': 5 obs. of 6 variables:
## ..$ Item : Factor w/ 5 levels "Comic books",..: 3 1 2 5 4
## ..$ Never or almost never: num [1:5] 10.2 36.7 17 30.9 18.8
## ..$ A few times a year : num [1:5] 20 25.7 24.7 30.6 18.5
## ..$ About once a month : num [1:5] 21.3 15.8 19.6 19.6 15.7
## ..$ Several times a month: num [1:5] 31 14.5 22.3 13.5 23.9
## ..$ Several times a week : num [1:5] 17.43 7.27 16.31 5.55 23.12
## $ items : NULL
## $ grouping: NULL
## $ nlevels : num 5
## $ levels : chr [1:5] "Never or almost never" "A few times a year" "About once a month" "Several times a month" ...
## - attr(*, "class")= chr "likert"
The items
are not present, but the likert
object can still be summarised:
summary(l29s)
## Item low neutral high mean sd
## 1 Magazines 30.21689 21.33091 48.45219 3.252525 1.248210
## 2 Comic books 62.43096 15.78368 21.78536 2.288660 1.298707
## 3 Fiction 41.77380 19.61739 38.60882 2.959184 1.354019
## 4 Non-fiction books 61.42466 19.55493 19.02042 2.309278 1.193392
## 5 Newspapers 37.29377 15.72688 46.97935 3.154639 1.453016
Scale figure height and width, and reduce size of legend.text
for plots:
scale_height = knitr::opts_chunk$get('fig.height')*0.5
scale_width = knitr::opts_chunk$get('fig.width')*1.25
knitr::opts_chunk$set(fig.height = scale_height, fig.width = scale_width)
theme_update(legend.text = element_text(size = rel(0.7)))
# Plots
plot(l29s) + ggtitle(title)
plot(l29s, centered=FALSE) + ggtitle(title)
plot(l29s, include.center=FALSE) + ggtitle(title)
plot(l29s, center=2) + ggtitle(title)
plot(l29s, center=2.5) + ggtitle(title)
# ideally, if center%%0.5 == 0, plot.percent.neutral=FALSE
plot(l29s, center=2.5, plot.percent.neutral=FALSE) + ggtitle(title)
plot(l29s, type = 'heat') + ggtitle(title) +
theme(legend.position = 'none')
# scale_y_discrete(labels = function(x) stringer::str_wrap(x, width = 15))
# to wrap labels would sort `Mean (SD)` column out of order.
# given values, legend is removed to make space for axes labels
# Density plots on likert summary results are not supported.
# plot(l29s, type='density') + ggtitle(title)
# plot(l29s, type='density', facet=FALSE, legend='Material') + ggtitle(title)
Grouped by country, using l29g
from the likert
demo:
l29g <- likert(items29, grouping=pisaitems$CNT)
str(l29g$results)
## 'data.frame': 15 obs. of 7 variables:
## $ Group : Factor w/ 3 levels "Canada","Mexico",..: 1 1 1 1 1 2 2 2 2 2 ...
## $ Item : Factor w/ 5 levels "Magazines","Comic books",..: 1 2 3 4 5 1 2 3 4 5 ...
## $ Never or almost never: num 11.1 48.2 15 27.9 18.6 ...
## $ A few times a year : num 16.1 24.8 23.4 31.8 17.4 ...
## $ About once a month : num 24.9 13.2 20.3 20.8 18.6 ...
## $ Several times a month: num 31.04 8.58 21.11 13.34 24.88 ...
## $ Several times a week : num 16.86 5.2 20.21 6.13 20.48 ...
Make a summary from results
, grouped by the variable in column 1 of results:
l29gs <- likert(summary = l29g$results, grouping = l29g$results[,1])
str(l29gs)
## List of 5
## $ results :'data.frame': 15 obs. of 7 variables:
## ..$ Group : Factor w/ 3 levels "Canada","Mexico",..: 1 1 1 1 1 2 2 2 2 2 ...
## ..$ Item : Factor w/ 5 levels "Magazines","Comic books",..: 1 2 3 4 5 1 2 3 4 5 ...
## ..$ Never or almost never: num [1:15] 11.1 48.2 15 27.9 18.6 ...
## ..$ A few times a year : num [1:15] 16.1 24.8 23.4 31.8 17.4 ...
## ..$ About once a month : num [1:15] 24.9 13.2 20.3 20.8 18.6 ...
## ..$ Several times a month: num [1:15] 31.04 8.58 21.11 13.34 24.88 ...
## ..$ Several times a week : num [1:15] 16.86 5.2 20.21 6.13 20.48 ...
## $ items : NULL
## $ grouping: Factor w/ 3 levels "Canada","Mexico",..: 1 1 1 1 1 2 2 2 2 2 ...
## $ nlevels : num 5
## $ levels : chr [1:5] "Never or almost never" "A few times a year" "About once a month" "Several times a month" ...
## - attr(*, "class")= chr "likert"
Rescale figures to full height:
knitr::opts_chunk$set(fig.height = knitr::opts_chunk$get('fig.height')*2)
plot(l29gs) + ggtitle(title)
plot(l29gs, centered=FALSE) + ggtitle(title)
plot(l29gs, include.center=FALSE) + ggtitle(title)
plot(l29gs, center=2) + ggtitle(title)
plot(l29gs, center=2.5, include.center=FALSE) + ggtitle(title)
# heat plots on likert summary results with grouping are not supported.
# plot(l29gs, type = 'heat') + ggtitle(title)