Практические инструменты для быстрого исследования данных с помощью визуализации в R

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

Год назад я выступил с докладом в Центре геномной регуляции (CRG) в Барселоне, где в настоящее время работаю над докторской диссертацией, под названием Практические инструменты для быстрой визуализации данных в R с целью распространение информации о существовании серии пакетов, которые значительно облегчили мою жизнь, когда дело доходит до исследовательского анализа данных (EDA).

В этой статье я кратко познакомлю вас с моим подходом к EDA. Все материалы доклада можно свободно найти на этой странице, а исходный код — в соответствующем репозитории. Я хотел бы подчеркнуть важность пакетов с открытым исходным кодом для облегчения жизни науки о данных. В частности, я лично считаю, что R-библиотека ggpubr — оболочка ggplot, — разработанная Alboukadel Kassambara, предлагает все функции, необходимые для быстрого перехода от однострочника к полностью настроенные сюжеты.

До начала

Я настоятельно рекомендую установить следующие пакеты:

Некоторое время назад я написал статью о том, как структурировать проект по науке о данных. Как правило, я сохраняю файлы, которые трудно получить каждый раз и из которых я могу задать много вопросов. tidyverse — это пакет, который позволяет вам задавать эти вопросы, а ggpubr позволяет визуализировать их так, чтобы для достижения качества публикации потребовался минимальный объем работы. Наконец, пакет здесь позволяет автоматически найти корень проекта на любом устройстве.

Визуализируйте ответы на свои вопросы

Наш набор игрушек: пингвины-пальмеры

Чтобы начать играть с функциями из этих пакетов, мы будем использовать набор данных palmerpenguins. Этот простой набор данных имеет как непрерывные, так и категориальные переменные, что делает его идеальным для демонстрации того, как работают различные функции.

require(tidyverse)
penguins_url = 'https://raw.githubusercontent.com/allisonhorst/palmerpenguins/master/inst/extdata/penguins.csv'
dat = read.csv(url(penguins_url), stringsAsFactors = TRUE)
dat = dat %>% drop_na()
head(dat)
##   species    island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
## 1  Adelie Torgersen           39.1          18.7               181        3750
## 2  Adelie Torgersen           39.5          17.4               186        3800
## 3  Adelie Torgersen           40.3          18.0               195        3250
## 4  Adelie Torgersen           36.7          19.3               193        3450
## 5  Adelie Torgersen           39.3          20.6               190        3650
## 6  Adelie Torgersen           38.9          17.8               181        3625
##      sex year
## 1   male 2007
## 2 female 2007
## 3 female 2007
## 4 female 2007
## 5   male 2007
## 6 female 2007

ggpubr позволяет быстро создавать подробные графики с большими возможностями для настройки благодаря тому, что он построен на основе ggplot2. При построении сюжета я всегда спрашиваю себя: «Какие отношения я хочу видеть?» и «Как бы я хотел, чтобы это было представлено мне?».

Категориальный против категорического

Например, нам может быть интересно узнать, «сколько всего пингвинов каждого вида наблюдалось?». Это означает подсчет пингвинов каждого вида, категориальную переменную. Для этого мы можем использовать круговую диаграмму:

ggpie(dat %>% count(species), x = 'n', fill = 'species')

Или мы можем копнуть глубже и объединить несколько категориальных переменных, задав вопрос: «Сколько пингвинов каждого вида и пола мы наблюдали на разных островах?» через барный график:

ggbarplot(dat %>% count(species, sex, island), x = 'species', y = 'n', fill = 'sex', label = TRUE, position = position_dodge(0.7), facet.by = 'island', palette = 'lancet')

Одна из самых крутых особенностей ggpubr заключается в том, что он использует цветовые палитры из научных журналов из пакета ggsci. В этом случае я использовал цветовую палитру Ланцета, просто установив palette="lancet". Также обратите внимание, как легко можно получить проницательные ответы на вопросы с несколькими переменными, сочетая аргументы x, facet.by и fill.

Категориальный против непрерывного

Теперь мы можем двигаться дальше, задав вопрос, как непрерывная переменная изменяется в нескольких категориях: «Каково распределение длин ласт среди видов пингвинов, пола и островов происхождения?». В этом случае мы можем визуализировать распределения с помощью графика гистограммы, но нам нужно создать по одному для каждой категории. Вот как вы можете сделать это в одной строке, используя несколько аспектов:

gghistogram(dat, x = 'flipper_length_mm', fill = 'sex', facet.by = c('species','island'))

В качестве альтернативы, если мы не хотим делать такую ​​большую цифру, мы можем использовать графики джиттера или ленточные диаграммы. Кроме того, мы можем визуализировать медиану и межквартильный диапазон параметра распределения add=’median_iqr’ и указать его параметры через add.params.

ggstripchart(dat, x = 'island', y = 'flipper_length_mm', color = 'sex', facet.by = 'species', alpha = 0.5, position = position_jitterdodge(), add = 'median_iqr', add.params = list(color='black', group='sex', size=0.2))

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

ggstripchart(dat, x = 'island', y = 'body_mass_g', color = 'sex', facet.by = 'species', alpha = 0.5, position = position_jitterdodge(), add = 'median_iqr', add.params = list(color='black', group='sex', size=0.2)) + stat_compare_means(aes(color = sex), label = "p.signif", method = 'wilcox.test')

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

Непрерывный против непрерывного (против категорического)

Вы могли заметить, что распределение массы тела и длины ласт у пингвинов очень похоже. Но «сколько?» и «как они соотносятся с длиной клюва?». Это тип вопроса «непрерывный-против-непрерывного», для которого очень удобны диаграммы рассеяния:

ggscatter(dat, x = 'flipper_length_mm', y = 'body_mass_g', color = 'bill_length_mm', alpha = 0.5)

При установке color='bill_length_mm' переменная отображается в виде цветового градиента и позволяет нам видеть, помимо четкой линейной зависимости между длиной ласта и массой тела, что длина клюва также имеет тенденцию к увеличению с увеличением длины ласта. два других.

Теперь, как это уже случалось раньше, вам может быть интересно, могут ли быть другие переменные, также известные как вмешивающиеся факторы, которые создают ложную связь: «Можем ли мы увидеть систематическую ошибку выборки или эффект партии по годам? сбора данных?». Мы можем легко проверить это, используя аргумент color:

ggscatter(dat %>% mutate(year=factor(year)), x = 'flipper_length_mm', y = 'body_mass_g', alpha = 0.5, color = 'year', ellipse = TRUE)

К счастью, это не так. Мы можем подтвердить, что ученые собирали образцы распределений в каждый момент времени.

В этот момент вы, должно быть, задаетесь вопросом: «Какова корреляция между длиной ласт и массой тела?». Мы можем очень легко добавить его с помощью аргументов cor.coef и cor.coeff.args.

ggscatter(dat %>% mutate(year=factor(year)), x='flipper_length_mm', y = 'body_mass_g', alpha = 0.5, color = 'year', add = 'reg.line', conf.int = TRUE, cor.coef = TRUE, cor.coeff.args = list(method = 'spearman', label.sep = '\n')) + theme(aspect.ratio = 1)

Объединить графики в фигуру

Наконец, когда мы хотим включить в отчет разные рисунки, мы можем, например, сохранить их в виде файлов .pdf и отредактировать, объединить в таких программах, как Inkscape. Или мы также можем запрограммировать их с помощью ggarrange! Вот пример:

fontsize = 6
labsize = 2
# overview number of observations of every sex across islands and species
p1 = ggbarplot(dat %>% count(species, sex, island), x = 'species', y = 'n', fill = 'sex', label = TRUE, lab.size = labsize, position = position_dodge(0.7), facet.by = 'island', palette = 'lancet') + ylim(NA, 68)
# sex-related body mass distributions across islands and species
p2 = ggstripchart(dat, x = 'island', y = 'body_mass_g', color = 'sex', facet.by = 'species', alpha = 0.5, position = position_jitterdodge(), add = 'median_iqr', add.params = list(color='black', group='sex', size=0.2), palette = 'lancet') + stat_compare_means(aes(color = sex), label = "p.signif", method = 'wilcox.test', size = labsize)
# association of flipper length and body mass
p3 = ggscatter(dat %>% mutate(year=factor(year)), x = 'flipper_length_mm', y = 'body_mass_g', alpha = 0.5, color = 'year', add = 'reg.line', conf.int = TRUE, cor.coef = TRUE, cor.coeff.args = list(method = 'spearman', label.sep = '\n', size = labsize)) + theme(aspect.ratio = 1)
p1p2 = ggarrange(p1 + theme_pubr(base_size = fontsize), p2 + theme_pubr(base_size = fontsize), ncol = 1, common.legend = TRUE)
fig = ggarrange(p1p2, p3 + theme_pubr(base_size = fontsize), widths = c(2,1), heights = c(2, 1), labels = 'AUTO')
# save
ggsave('images/myfig.png', fig, width = 15, height = 10, unit = 'cm')

Заключение

Доступ и изучение данных для ответа на наши вопросы еще никогда не были такими простыми благодаря пакетам с открытым исходным кодом, таким как ggpubr (и платформе, на которой они построены). Для меня EDA — самая важная часть науки о данных, поскольку она позволяет генерировать новые гипотезы и, что важно, находить и исправлять нежелательные помехи. Эта статья представляет собой небольшую часть более тщательного ускоренного курса, в котором я показываю свой способ изучения наборов геномных данных (бесплатно доступен здесь). Если вам понравилась эта статья, возможно, вам будет интересно прочитать другие:

Пожалуйста, не стесняйтесь обращаться, если вы хотите узнать больше или что-то было неясно!