Для работы с группами наблюдений, которые отделяются друг от друга по значениям категориального признака, удобно использовать функции group_by() для создания группированного датасета и summarise() или mutate() для подсчета каких-то значений для групп. Группировать датафрейм можно как по значениям одного столбца, так и по нескольким столбцам.
Отбираем из датафрейма starwars только персонажей с планет Набу и Татуин.
2
Группируем датафрейм по комбинациям значений из столбцов eye_color и species.
3
Для каждой получившейся группы строк рассчитываем их число (записываем в новый столбец n) и максимальное значение по столбцу height (записываем в столбец max_height). Все остальные столбцы, не спользуемые при группировке, исчезают.
4
Добавлям столбец max_height_of_all, в который записываем максимальное значение из столбца max_height. Поскольку, к этому моменту осталась группировка датафрейма по столбцу eye_color, в новом столбце окажутся несколько значений - для каждого цвета глаз.
# A tibble: 7 × 5
# Groups: eye_color [5]
eye_color species n max_height max_height_of_all
<chr> <chr> <int> <int> <int>
1 blue Human 6 188 188
2 brown Human 5 185 185
3 brown <NA> 2 185 185
4 orange Gungan 3 224 224
5 red Droid 2 97 97
6 yellow Droid 1 167 202
7 yellow Human 2 202 202
Применив функцию group_by(), вы получаете группированный датафрейм. Обратите внимание, что функция summarise() по умолчанию снимает один уровень группировки (по одному столбцу), а mutate() не влияет на группировку совсем. Если вы группировали датафрейм, например, по двум столбцам, то после одного использования summarise() датафрейм все еще останется граппированным по первому из перечисленных в group_by() столбцов. Чтобы вручную избавиться от граппировки датафрейма, необходимо применить функцию ungroup().
Отбираем из датафрейма starwars только персонажей с планет Набу и Татуин.
2
Группируем датафрейм по комбинациям значений из столбцов eye_color и species.
3
Для каждой получившейся группы строк рассчитываем их число (записываем в новый столбец n) и максимальное значение по столбцу height (записываем в столбец max_height). Все остальные столбцы, не спользуемые при группировке, исчезают.
4
Снимаем все группировки с датафрейма.
5
Добавлям столбец max_height_of_all, в который записываем максимальное значение из столбца max_height. В этот раз группировок не осталось, поэтому будет посчитано одно значение по всему столбцу max_height.
# A tibble: 7 × 5
eye_color species n max_height max_height_of_all
<chr> <chr> <int> <int> <int>
1 blue Human 6 188 224
2 brown Human 5 185 224
3 brown <NA> 2 185 224
4 orange Gungan 3 224 224
5 red Droid 2 97 224
6 yellow Droid 1 167 224
7 yellow Human 2 202 224
Стоит отметить, что в новых версиях пакета {dplyr} у функций mutate() и summarise() появился параметр .by, которым можно заменить использование функции group_by(). Обратите внимание, что в данном случае при использовании функции summarise() с параметром .by в результате получится негруппированный датафрейм.
Отбираем из датафрейма starwars только персонажей с планет Набу и Татуин.
2
Задаем группировку по комбинациям значений из столбцов eye_color и species (параметр by). Для каждой получившейся группы строк рассчитываем их число (записываем в новый столбец n) и максимальное значение по столбцу height (записываем в столбец max_height).
3
Добавлям столбец max_height_of_all, в который записываем максимальное значение из столбца max_height. В этот раз группировок не осталось, поэтому будет посчитано одно значение по всему столбцу max_height.
# A tibble: 7 × 5
eye_color species n max_height max_height_of_all
<chr> <chr> <int> <int> <int>
1 blue Human 6 188 224
2 yellow Droid 1 167 224
3 red Droid 2 97 224
4 yellow Human 2 202 224
5 brown Human 5 185 224
6 orange Gungan 3 224 224
7 brown <NA> 2 185 224
Задача подсчета количества наблюдений по группам встречается достоточно часто, поэтому для комбинации функций group_by(groupping_var) %>% summarise(n = n()) есть более лаконичная замена - функция count(groupping_var).
Отбираем из датафрейма starwars только персонажей с планет Набу и Татуин.
2
Считаем количество персонажей с различными комбинациями значений из столбцов eye_color и species.
# A tibble: 7 × 3
eye_color species n
<chr> <chr> <int>
1 blue Human 6
2 brown Human 5
3 brown <NA> 2
4 orange Gungan 3
5 red Droid 2
6 yellow Droid 1
7 yellow Human 2
Длинный и широкий форматы датафреймов
Прежде чем начинать создавать график с помощью {ggplot2} важно убедиться в том, что данные, по которым планируется отрисовать график, содержатся в датафрейме в нужном формате. Для того, чтобы получилось корректно задать графические переменные с помощью функции aes(), необходимо, чтобы каждый признак, который будет “отложен” по какой-то из “осей” графика, был записан в свой отдельный столбец.
Широкий формат (wide format) датафрейма подразумевает, что несколько переменных, похожих по своей природе, разнесены по разным столбцам. Например, измерения по нескольким временным точкам записаны в разные столбцы.
Если такие данные нужно визуализировать с помощью {ggplot2}, то например, чтобы показать временной тренд с помощью линейной диаграммы, необходимо будет перевести датафрейм из широкого формата в длинный. В датафрейме в длинном формате (long format) названия переменных и их значения хранятся в двух столбцах: один для имен переменных, другой - для значений. Преобразование длинного формата в широкий производится с помощью функции pivot_longer() из пакета {tidyr} (входит в tidyverse). При использовании этой функции необходимо указать столбцы, которые будут переведены в “длинный” формат. Дополнительно удобно использовать параметр names_to и values_to, чтобы задать названия новых столбцов, в которые будут записаны названия переменных и их значения.
Используя “длинный” датафрейм, строим линейную диаграмму.
2
Добавляем идентификаторы пациентов в виде подписей у последней временной точки. На вход этой geom-функции даем фильтрованный датасет, в котором есть данные только по последней временной точке.
3
Для подписей задаем X-координату - поскольку по оси X отложен категориальный признак, то указываем просто номер нужной категории. С помощью hjust немного сдвигаем подписи вправо.
4
Преобразуем подписи по оси X - удаляем лишние символы перед указанием года обследования.
5
Задаем цветовую палитру и убираем легенду.
6
Меняем названия осей X и Y.
Перевести датафрейм из длинного формата в широкий можно с помощью функции pivot_wider(). Чтобы использовать эту функции нужно указать, из каких столбцов брать названия переменных (names_from), которые будут соответствовать названиям новых столбцов, и сами значения (values_from). При использовании этой функции важно, чтобы в датафрейме оставался столбец или несколько, значения в которых были бы уникальны для каждого наблюдения. Иначе не получится восстановить соответствие между значениями переменных внутри индивидуальных наблюдений.
Удаляем строки с пропущенными значениями в столбцах height, eye_color и sex.
2
Преобразуем цвета глаз (столбец eye_color) в факторы - записываем их в новый столбец fct_eye_color. Оставляем только 5 наиболее часто встречающихся цветов, остальные записываем в категорию Other.
3
Преобразуем информацию о поле персонажа (столбец sex) в факторы - записываем их в новый столбец fct_sex. Категории пола, встретившиеся в датасете менее 10 раз, записываем в категорию Other sex.
4
Сортируем уровни фактора, указывающего на пол персонажа, в зависимости от максимального значения роста персонажа в каждой категории пола.
5
Строим график плотности распределения роста персонажей с разделением на группы по цвету глаз. Записываем график в переменную.
6
Показываем график.
В такой ситуации разумно использовать фасеты (facets) - разбить график на несколько и собрать их в панель. Это можно сделать с помощью функции facet_wrap() из пакета {ggplot2}. Если вы хотите разбить график по двум или более категориальным переменным, то вам пригодится функция facet_grid(). У этих функций немного необычный синтаксис: столбец с категориальной переменной, по которой вы хотите разбить график на несколько, необходимо указывать через тильду ~ или задавать при помощи функции vars().
Разбиваем график на панель графиков с помощью facet_wrap() по категориям, соответствующим цвету глаз персонажа.
2
Убираем легенду - каждый график в панели будет подписан, поэтому диблирующая информацию легенда не нужна.
Заголовки графиков в панели настраиваются также необычным образом - с помощью объектов типа labeller. Кроме того, вам может пригодиться параметр scales, который определяет, будет ли для всех графиков использоваться единый масштаб или нет.
Разбиваем график на панель графиков с помощью facet_grid() по категориям, соответствующим цвету глаз и полу персонажа.
2
Корректируем названия категорий, отображаемые на графике.
3
Делаем шкалу по оси X индивидуальной для каждого столбца графиков.
4
Убираем легенду - каждый график в панели будет подписан, поэтому диблирующая информацию легенда не нужна.
5
Настраиваем отображение названий категорий - делаем текст жирным.
Объединение графиков в панели
Каждый график, нарисованный с помощью {ggplot2} или совместимых пакетов, представляет собой ggplot-объект. Несколько графиков можно собрать в панель, разместив графики на одной странице, согласно определенной схеме (layout). Существует несколько пакетов, которые позволяют создавать такие панели из графиков в R: {patchwork}, {cowplot} и др. Эти пакеты не входят к коллекцию tidyverse - их нужно устанавливать дополнительно.
Потренируйтесь создавать и сохранять графики. Готовые графики показаны для ориентира, не нужно пытаться их воспроизвести до мелочей.
Задание 1
Задание 1.1
Ваш коллега собрал данные о том, сколько людей появилось на своих рабочих местах в лаборатории за прошедшую неделю. Давайте изобразим эти данные в виде столбчатой диаграммы. Подпишите график, оси, добавьте цвета, поиграйте с дизайном. Обратите внимание, что дни недели на графике должны идти в правильном порядке (постарайтесь добиться этого самым кратким способом).
Соседней лаборатории понравился эксперимент вашего коллеги и они тоже решили собрать данные о количестве людей на рабочих местах в разные дни. Теперь у вас есть данные из двух лабораторий, давайте их визуализируем на одном графике с помощью столбчатой диаграммы. Подпишите график, оси, добавьте цвета, поиграйте с дизайном. Дни недели на графике должны быть указаны в правильном порядке.
Прочитайте датасет про исчезнувшие виды растений по ссылке https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2020/2020-08-18/plants.csv.
Изучите датасет!
Что в нем есть:
binomial_name - название вида растения,
country - страна произрастания,
continent - континент произрастания,
group - таксономическая группа (Цветковое растение - Flowering plant, и т.д.),
year_last_seen - период, когда было замечено в природе последний раз,
threat_ и action_ - виды угроз и действий по сохранению вида,
red_list_category - категория в Красной книге: Extinct или Extinct in the Wild.
Больше информации о датасете по ссылке: https://github.com/rfordatascience/tidytuesday/blob/master/data/2020/2020-08-18/readme.md.
Постройте столбчатую диаграмму числа исчезнувших видов цветковых растений и не-цветковых растений на каждом континенте. Сохраните график в файл.
Пояснения:
В колонке group оставьте группу Flowering plants (цветковые растения), остальные группы растений объедините в группу Non-flowering plants (не-цветковые растения). Используйте возможности пакета forcats.
Посчитайте число исчезнувших видов (Extinct) по каждому континенту, в каждой таксономической группе (Flowering plants и Non-flowering plants).
Нарисуйте группированную столбчатую диаграмму (2 отдельных столбца, для Flowering plants и Non-flowering plants, расположенные рядом). По горизонтали расположите континенты.
Пусть континенты будут расположены в порядке убывания количества стран на них.
Осмысленно подпишите оси.
Перенесите легенду наверх, уберите название легенды.
Обозначьте Flowering plants желтым и Non-flowering plants зеленым.
Задание 3
Загрузите датасет, содержащий динамику использования сои в пищевой и непищевой промышленности за несколько последних десятков лет. Ссылка для скачивания: https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2021/2021-04-06/soybean_use.csv.
Изучите датасет! Про него можно прочитать дополнительно, например, здесь: https://github.com/rfordatascience/tidytuesday/blob/master/data/2021/2021-04-06/readme.md.
Информация про датасет:
entity - континент, часть континента или страна,
code - код страны,
year - год,
human_food - сколько сои было использованно в пищевой промышленности (в тоннах),
animal_feed - сколько сои было использовано в производстве кормов для животных (в тоннах),
processed - сколько сои было использовано в непищевой промышленности (производство биотоплива и т.д.) (в тоннах).
Отберите для анализа данные только по 6 континентам: c("Africa", "Europe", "Asia", "Northern America", "South America", "Australia & New Zealand"), за 33 года - 1981-2013. Нарисуйте столбчатую диаграмму, которая бы изображала среднее количество сои по трем типам промышленности, использованной за 33 года на всех 6 обитаемых континентах. Изобразите разброс 3/4 SD (чтобы линии разброса выровнялись со столбцами, возможно, вам понадобится параметр position = position_dodge(width = 0.9)). Отсортируйте континенты по среднему количеству сои, использованной во всех областях промышленности за исследуемый период. Логарифмируйте ось Y с помощью подходящей функции scale_y_*. Измените формат числовых подписей по оси Y.
Добавьте осознанные названия осей. Поверните названия континентов, чтобы они отображались целиком, на 45 градусов. Уберите название легенды и поменяйте цвета (например, на c("#ffb4a2", "#e5989b", "#b5838d")) и названия категорий промышленности в легенде (чтобы было более приятно читать).
Сохраните график в файл.
Задание 4
Задание 4.1
Напишите функцию, которая бы рассчитывала ядерно-цитоплазматическое соотношение (“N:C” или “karyoplasmic” ratio) по формуле \(\frac{NucleusVol}{CellVol}\), где NucleusVol - объем ядра (мкм3), CellVol - объем клетки (мкм3).
На небольшом примере продемонстрируйте работу этой функции.
Задание 4.2
Прочитайте данные по размерам ядер и клеток разных организмов из разнообразных таксономических групп, они находятся по ссылке https://raw.githubusercontent.com/kirushka/datasets/main/NC_ratio.csv. Эти данные взяты из статьи Malerba et al. 2021.
В прочитанном датафрейме 4 столбца:
SpeciesGroup - название таксономической группы,
Species - видовое название организма,
NucleusVol - объем ядра (мкм3),
CellVol - объем клетки (мкм3).
Используя функцию, которую вы создали в предыдущем задании, посчитайте ядерно-цитоплазматическое соотношение (“N:C” или “karyoplasmic” ratio) для каждого организма - запишите результат в новый столбец.
Также преобразуйте строковый столбец SpeciesGroup в столбец с факторами. Отсортируйте уровни фактора по убыванию медианного значения NC ratio.
Задание 4.3
По модифицированному датафрейму постройте точковую диаграмму, на которой по оси X отложен объем клеток, по оси Y - NC ratio, цветом показана таксономическая группа.
Добавьте на график линии тренда, построенные с помощью линейной регрессии, для каждой таксономической группы с помощью geom_smooth(method = "lm").
Чтобы использовать на графиках “математические” обозначения, греческие буквы и т.п., например, в подписях осей, можно использовать функцию expression, которой подать на вход все выражение без кавычек. Например, так: ggplot(...) + labs(x = expression(Cell~volume~(mu*m^3))).
Для настройки “tick labels”, т.е. подписей интервалов на осях, можно использовать пакет scales. Например, scale_x_log10(labels = scales::label_math(format = log10)) преобразит подписи по оси X в формат вида \(10^{log10(x)}\). Поэкспериментируйте и с другими вариантами отображения этих подписей.
Поменяйте цветовую палитру графика.
Сохраните график в файл.
Задание 4.4
Разделите график из задания 4.3 на “панельки” с помощью facet_wrap, так чтобы каждая таксономическая группа оказалась на своем графике. Сохраните график в файл.
Задание 5
Задание 5.1
Зугрузите набор данных по сериалу “Тед Лассо”. Ссылка для скачивания: https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2023/2023-09-26/richmondway.csv.
Посмотрите на этот датасет и изучите, какая информация в нем есть! Прочитать о том, что это за данные можно по ссылке.
Информация про датасет:
Character - персонаж (только Roy Kent),
Episode_order, Season, Episode, Season_Episode - номера сезонов и эпизодов сериала,
F_count_RK - число матерных слов (F-ck), произнесенных Роем Кентом в данном эпизоде,
F_count_total - число матерных слов (F-ck), произнесенных всеми персонажами в данном эпизоде,
cum_rk_season, cum_total_season, cum_rk_overall, cum_total_overall - кумулятивное число матерных слов (F-ck) в отдельном сезоне или суммарно за 3 сезона,
F_score, F_perc - отношение F_count_RK к F_count_total, то же выраженное в процентах,
Dating_flag - встречается ли Рой Кент в этом эпизоде с девушкой Кили,
Coaching_flag - работает ли Рой Кент в этом эпизоде тренером,
Imdb_rating - рейтинг эпизода на IMDB.
Постройте столбчатую диаграмму, которая бы отражала число произнесенных F-ck слов Роем Кентом и всеми героями сериала. Столбцы должны быть расположены рядом (группированная диаграмма). С помощью фасетов разделите график по сезонам сериала. Явным образом подпишите каждый график в панели (например, “Season 1” вместо “1”). Задайте свою цветовую палитру. Понятным образом подпишите оси. Сохраните график в файл.
Задание 5.2
Работайте с тем же набором данных и с помощью подходящих графиков попробуйте ответить на вопросы:
Как соотносится между собой число серий, в которых Рой Кент встречается или не встречается с Кили?
Как соотносится между собой число серий, в которых Рой Кент работает или не работает тренером?
Изобразите на одном графике и информацию про отношения с Кили, и информацию про тренерство. Поработайте над читаемостью графика. Сохраните график в файл.
Задание 5.3
Отрисуйте в виде ящика с усами распределение процента F-ck слов, произнесенных Роем Кентом, в течение каждого из трех сезонов. Как зависит этот процент от того, встречается ли Рой с Кили или нет?
Корректно ли ящик с усами показывает распределение? Как в действительности выглядят эти данные? Модифицируйте ваш график таким образом, чтобы он более наглядно отображал особенности распределения визуализируемых данных.