Что такое dplyr
dplyr — самый популярный пакет R для манипуляции данными, «грамматика данных», построенная из горстки глаголов. Каждый глагол — это функция, которая принимает датафрейм, делает ровно одну работу (оставить часть строк, добавить столбец, посчитать сводку по группам) и возвращает новый датафрейм. Поскольку у каждого глагола одинаковая форма — датафрейм на входе, датафрейм на выходе, — они соединяются пайпом в конвейеры, которые читаются сверху вниз, как рецепт. dplyr — ядро tidyverse, семейства пакетов (tidyr, ggplot2, readr) с общим дизайном.
Всё, что делает dplyr, умеет и базовый R. Вот небольшой анализ на чистом базовом R — отфильтровать встроенные данные mtcars до 4-цилиндровых машин, вычислить новый столбец и усреднить его по числу передач. Этот код можно запустить:
Это работает, и это хороший R. Но обратите внимание, как история размазана по индексации скобками, присваиванию через $ и формуле. Версия того же анализа на dplyr:
library(dplyr)
mtcars |>
filter(cyl == 4) |>
mutate(kml = mpg * 0.425) |>
group_by(gear) |>
summarize(avg_kml = round(mean(kml), 1))
Четыре глагола, в том порядке, в каком вы объяснили бы их вслух. Эта читаемость — весь смысл dplyr, и на конвейере из двадцати шагов она решает всё.
Сниппеты dplyr на этой странице статичны, потому что этот редактор выполняет только базовый R — чтобы запустить их, установите dplyr на своей машине, как показано ниже.
Установка и загрузка
Установка один раз, затем загрузка в каждом скрипте, который его использует:
install.packages("dplyr") # once, per machine
library(dplyr) # every script
Установка install.packages("tidyverse") вместо этого подтянет dplyr вместе с родственными пакетами. При загрузке dplyr предупреждает, что маскирует stats::filter и stats::lag, — это нормально, а не ошибка.
Шесть основных глаголов
Каждый глагол принимает датафрейм первым аргументом, а имена столбцов — голыми, без кавычек и префиксов df$.
filter() оставляет строки, подходящие под условие:
mtcars |> filter(mpg > 25)
mtcars |> filter(cyl == 4, hp < 70) # comma = AND
select() оставляет столбцы по имени, диапазону или хелперу:
mtcars |> select(mpg, cyl, hp)
mtcars |> select(mpg:hp) # a range of adjacent columns
mtcars |> select(starts_with("d")) # disp, drat
mutate() добавляет или преобразует столбцы:
mtcars |> mutate(kml = mpg * 0.425, heavy = wt > 3.5)
arrange() сортирует строки — оберните столбец в desc() для сортировки по убыванию:
mtcars |> arrange(desc(mpg))
summarize() схлопывает строки в одну сводную строку, а group_by() заставляет его схлопывать по группам:
mtcars |>
group_by(cyl) |>
summarize(n = n(), avg_mpg = mean(mpg))
Сам по себе group_by() не делает ничего видимого — он лишь помечает датафрейм, чтобы следующий summarize() (или mutate()) работал группа за группой. У каждого глагола есть подробная статья в этой главе: фильтрация строк, добавление столбцов, сортировка и сводки по группам.
Соединение глаголов пайпом
Пайп |> берёт значение слева и передаёт его первым аргументом в функцию справа — x |> f(y) означает f(x, y). Поскольку каждый глагол dplyr принимает и возвращает датафрейм, глаголы можно сцеплять бесконечно:
mtcars |>
filter(hp > 100) |>
mutate(kml = mpg * 0.425) |>
group_by(cyl) |>
summarize(cars = n(), avg_kml = round(mean(kml), 1)) |>
arrange(desc(avg_kml))
Прочитайте вслух: взять mtcars, оставить машины мощнее 100 лошадиных сил, добавить столбец километров на литр, сгруппировать по цилиндрам, посчитать и усреднить каждую группу, отсортировать по среднему. Ни промежуточных переменных, ни вложенности. В старом коде вместо |> используется %>% из пакета magrittr — для работы с dplyr они взаимозаменяемы, а |> (встроенный в R 4.1+) разобран в статье про пайпы.
count() и n(): помощники для подсчёта
Подсчёт настолько частая задача, что в dplyr для него есть сокращения. n() возвращает число строк в текущей группе (работает только внутри summarize() или mutate()), а count() сворачивает всю связку group_by() + summarize(n = n()) в один вызов:
mtcars |> count(cyl) # rows per cyl value
mtcars |> count(cyl, gear, sort = TRUE) # two groupers, biggest first
Если вы поймали себя на том, что пишете group_by(x) |> summarize(n = n()), замените это на count(x).
Замечание о тибблах
Глаголы dplyr часто возвращают тиббл — вариант датафрейма из tidyverse. Это и есть датафрейм (всё, что принимает датафрейм, принимает и тиббл), но с более дружелюбной печатью: только первые 10 строк, только помещающиеся столбцы, с типами под каждым именем. Два отличия, о которых стоит знать: тибблы никогда не используют имена строк (поэтому mtcars |> as_tibble() теряет названия машин — tidyverse ожидает, что идентификаторы живут в настоящем столбце), а индексация одинарными скобками всегда возвращает тиббл, а не иногда сваливается в вектор. Ни то ни другое не должно удивлять вас в повседневной работе; просто не пугайтесь, когда str() покажет tbl_df.
Что вы уносите с собой
- dplyr — это грамматика: шесть глаголов, каждый делает одну работу над датафреймом, сцепляются пайпом.
filter()выбирает строки,select()— столбцы,mutate()добавляет столбцы,arrange()сортирует,group_by() + summarize()агрегирует.x |> f(y)— этоf(x, y): конвейеры читаются сверху вниз в порядке происходящего.count()иn()закрывают большинство задач подсчёта.- Базовый R умеет всё то же; dplyr выигрывает в читаемости, когда конвейеры растут.
Дальше: фильтрация и выборка подробно — идиомы скобок базового R и место filter() из dplyr.
Часто задаваемые вопросы
Что такое dplyr в R?
dplyr — самый популярный пакет R для работы с датафреймами. Он даёт небольшой набор глаголов — filter(), select(), mutate(), arrange(), summarize(), group_by(), — каждый из которых делает одну операцию над датафреймом, и они соединяются пайпом в читаемые конвейеры. dplyr входит в tidyverse.
Как установить dplyr?
Выполните install.packages("dplyr") один раз, а затем пишите library(dplyr) в начале каждого скрипта, который его использует. Если вместо этого установить tidyverse, вы получите dplyr вместе с родственными пакетами (tidyr, ggplot2, readr) за один раз.
Нужен ли мне dplyr, или достаточно базового R?
Базовый R умеет всё то же, что и dplyr, — выборку по индексам, aggregate(), order(), — и знать его стоит, потому что он работает везде и без зависимостей. dplyr окупает установку, когда конвейеры становятся длинными: пять сцепленных глаголов читаются как предложение, тогда как базовый эквивалент — как головоломка из вложенных скобок.
В чём разница между summarize и summarise в dplyr?
Ни в чём. Это одна и та же функция в американском и британском написании; dplyr экспортирует обе. Используйте то написание, которое принято в вашей команде, и будьте последовательны.