Загрузим базу данных с баллами за контрольную работу:
# база -- csv-файл
df <- read.csv("cw1-data.csv")
В ней есть две переменные: score (балл) и group (номер группы).
# head -- просмотр нескольких первых строк в базе
head(df)
## score group
## 1 17.0 1
## 2 20.0 1
## 3 0.0 2
## 4 22.5 3
## 5 0.0 1
## 6 19.5 3
Можем посмотреть на описательные статистики для баллов за контрольную работу (все известные показатели, которые мы умеем считать вручную):
# через $ указывается интересующая нас переменная
summary(df$score)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.00 15.00 19.50 17.26 22.00 25.00
Внимание: если кто уже умеет работать в R и хочет сверять свои ответы, полученные вручную, с тем, что выдает R, имейте в виду, что функция summary()
считает квартили с помощью алгоритма, отличного от того, который мы используем на лекциях и семинарах, то есть результаты могут получаться разными! Для примера рассмотрим такой вариационный ряд:
v <- c(1, 3, 6, 8, 11, 15)
По используемому нами алгоритму (метод нахождения квартилей Дж.Тьюки) мы должны поделить упорядоченную выборку на две половины, и тогда медиана нижней половины – это нижний квартиль (Q1), а медиана верхней половины – верхний квартиль (Q3). Для данного вариационного ряда получаем Q1 = 3 и Q3 = 11. А что выдает R?
summary(v)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1.000 3.750 7.000 7.333 10.250 15.000
Видно, что посчитанные с помощью R квартили отличаются от тех значений, которые получили мы. Это не означает, что кто-то из нас ошибся, просто нахождение квартилей с помощью компьютера – нетривиальный вычислительный вопрос, который может решаться по-разному. Конечно, в R есть алгоритмы, привычные нам, но они реализуется с помощью разных команд в зависимости от числа наблюдений в выборке, поэтому чтобы не запутаться, углубляться в них не будем.
Лучше построим график “ящик с усами” (boxplot, box-and-whiskers plot):
# col -- цвет
# main -- название графика (основной заголовок)
boxplot(df$score, col = "yellow",
main = "Баллы за контрольную работу")
Чтобы было интереснее, можем построить “ящики с усами” для баллов в каждой группе. (Кстати, хорошая идея для предварительного анализа данных – посмотреть, насколько сильно отличается распределение баллов в разных группах).
# чтобы R воспринимал номер группы не как число (результат измерения), а как некоторое название ("группа 1")
df$group <- as.factor(df$group)
# data = df -- чтобы указывать переменные в этой базе просто, без $
# col -- уже список цветов (сколько групп, столько и цветов)
# xlab -- подпись по оси X
# ylab -- полпись по оси Y
boxplot(data = df, score ~ group,
col = c("yellow", "red", "green"),
main = "Баллы за контрольную работу",
xlab = "группа",
ylab = "баллы")
Видно, что медианный балл во всех группах примерно одинаковый, все написали работу достаточно хорошо. Но вот “стабильность” успеваемости везде разная: например, баллы в первой группе сильно разбросаны (большой межквартильный размах и широкие границы типичных значений), в то время как во второй и третьей группах баллы за контрольную варьируются не так сильно.
Также можно заметить, что в первой группе 0 баллов за контрольную работу формально считаются типичным значением, а во второй и третьей группах такие баллы считаются выбросами. Означает ли это, что первая группа написала контрольную сильно хуже? На самом деле нет. Нулевой балл ставился только в том случае, когда студент не писал работу. Поэтому в данном случае такая картинка учитывает не просто успешное написание контрольной работы, но и просто случаи ее не-написания.
Начинающим исследователям на заметку: прежде чем анализировать данные и делать выводы, всегда задумывайтесь, что вы хотите на самом деле оценить. Может, стоит выбросить некоторые наблюдения из выборки или сделать так, чтобы специфические случаи обозначались особым образом?
Теперь изобразим то же самое, но с помощью более сложного кода (для того, чтобы получить ровно те графики, которые демонстрировались на семинаре). Для этого нам потребуется библиотека для рисования красивых графиков ggplot2
(ее надо установить):
install.packages("ggplot2")
А теперь строим те же самые “ящики с усами”, но более красивые.
# сначала надо "включить" нужную библиотеку, иначе R не будет видеть команды,
# которые в нее зашиты
library(ggplot2)
# сначала указываем базу, с которой работаем
# в aes (от aesthetics) выставляем, что должно быть по осям графика
# geom_boxplot -- тип графика
# fill -- цвет заливки (просто col -- цвет контура графика)
# stat_boxplot(geom ="errorbar") -- чтобы были "настоящие усы" с горизонтальными линиями
# ggtitle -- заголовок, subtitle -- подзаголовок
# длинная строчка с theme -- чтобы выровнять заголовки по центру (необязательно)
ggplot(data = df, aes(x = "", y = score)) +
geom_boxplot(fill = "yellow") +
stat_boxplot(geom ="errorbar") +
xlab("") + ylab("баллы") +
ggtitle("Баллы за контрольную работу", subtitle = "(из 25)") +
theme(plot.title = element_text(hjust = 0.5), plot.subtitle = element_text(hjust = 0.5))
И графики по группам:
# fill = group -- чтобы заливка "ящика" отличалась для каждой группы
# в данном случае входит в aes, так как зависит от значения переменной
ggplot(df, aes(x = group, y = score, fill = group)) +
stat_boxplot(geom = "errorbar") +
geom_boxplot() +
xlab("группы") +
ylab("баллы") +
ggtitle("Баллы за контрольную работу", subtitle = "(из 25)") +
theme(plot.title = element_text(hjust = 0.5), plot.subtitle = element_text(hjust = 0.5))
Помимо “ящиков с усами” есть много способов визуализировать распределение данных. Например, есть симпатичные графики, которые на английском называются violin plots или bean plots (кто-то видит в графике скрипку, кто-то стручок фасоли, так бывает).
# аналогично, только вместо geom_boxplot стоит geom_violin
# trim = FALSE -- чтобы "скрипки" не обрезались
ggplot(df, aes(x = group, y = score, fill = group)) +
geom_violin(trim = FALSE) +
xlab("группы") +
ylab("баллы") +
ggtitle("Баллы за контрольную работу", subtitle = "(из 25)") +
theme(plot.title = element_text(hjust = 0.5), plot.subtitle = element_text(hjust = 0.5))
Логичный вопрос: ЧТО ЭТО БЫЛО?
Violin plot – это график, склеенный из двух половинок – графиков плотности распределения, расположенных вертикально. Посмотрим на привычные графики плотности распределения (только повернутые):
# теперь вместо geom_violin ставим geom_density
# facet_grid(~ group) -- чтобы график для каждой группы был в отдельном окошке
# coord_flip() -- разворачиваем горизонтально (flip coordinates)
# scale_x_continuous -- выставляю границы для значений, чтобы графики не обрезались по краям
# и были сравнимы с violin plots выше
ggplot(df, aes(score, fill = group)) +
geom_density() +
xlab("группы") +
ylab("баллы") +
ggtitle("Баллы за контрольную работу", subtitle = "(из 25)") +
theme(plot.title = element_text(hjust = 0.5), plot.subtitle = element_text(hjust = 0.5)) +
facet_grid(~ group) +
coord_flip() +
scale_x_continuous(limits = c(-10, 35))
Теперь violin plots стали понятнее, правда? Другой вопрос: а зачем такие графики нужны, есть у нас и так есть “ящики с усами”? Проблема в том, что “ящики с усами” хорошо изображают описательные статистики и разброс значений, но не очень наглядно отражают особенности распределения. В случае, когда распределение сильно отличается от нормального, сильно скошено или вообще выглядит странно, violin plot может быть полезнее, чем “ящик с усами”, потому что он будет более ярко показывать все “странности” распределения данных.
И в завершение, иллюстрация того, почему violin plot иногда называют vase plot.
# обрезанный график (нет trim = FALSE) для всех баллов за контрольную
ggplot(df, aes(x = "", y = score)) +
geom_violin() +
ylab("баллы") +
ggtitle("Баллы за контрольную работу", subtitle = "(из 25)") +
theme(plot.title = element_text(hjust = 0.5), plot.subtitle = element_text(hjust = 0.5))