install.packages("tidyverse")10 Введение в tidyverse
10.1 Вселенная tidyverse
Тайдиверс (tidyverse) - это не один, а целое множество пакетов, объединенных общей философией, грамматикой и структурами данных. Пакеты tidyverse можно разделить на две группы: основные пакеты, составляющие ядро tidyverse, и дополнительные пакеты.
- Основные пакеты, которые составляют ядро tidyverse. Сам по себе пакет tidyverse – это пакет для подключения и обновления основных пакетов tidyverse. Короче говоря, tidyverse – это такой пакет с пакетами.
Давайте сначала установим пакет tidyverse, если он у вас еще не установлен.
Установка может занять довольно большое время: у вас установятся как основные пакеты tidyverse, так и огромное количество зависимостей – других пакетов, которые используются основными пакетами tidyverse. Зато при работе с новыми для себя пакетами вы приятно удивитесь тому, как много нужных вам пакетов уже установлено!
Все пакеты tidyverse, включая, конечно, основные пакеты, объединены tidy философией и взаимосовместимым синтаксисом. Это означает, что во многих случаях даже не нужно думать о том, из какого именно пакета tidyverse пришла функция. Можно просто подключить один пакет – пакет tidyverse.
Warning: package 'ggplot2' was built under R version 4.4.3
Warning: package 'tibble' was built under R version 4.4.3
Warning: package 'tidyr' was built under R version 4.4.3
Warning: package 'readr' was built under R version 4.4.3
Warning: package 'purrr' was built under R version 4.4.3
Warning: package 'dplyr' was built under R version 4.4.3
Warning: package 'lubridate' was built under R version 4.4.3
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.2.0 ✔ readr 2.2.0
✔ forcats 1.0.1 ✔ stringr 1.6.0
✔ ggplot2 4.0.2 ✔ tibble 3.3.1
✔ lubridate 1.9.5 ✔ tidyr 1.3.2
✔ purrr 1.2.1
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
Подключение пакета tidyverse автоматически приводит к подключению основных пакетов tidyverse, дополнительные пакеты нужно подключать дополнительно при необходимости.
Все эти пакеты написаны Хэдли Уикхэмом — пожалуй, самым значимым человеком в мире R на сегодняшний день. Вот эти пакеты:
- dplyr – для преобразования данных, основной пакет всего тайдиверс,
- tidyr – для приведения данных к чистому виду (tidy data),
- tibble – для работы с тибблами, продвинутый вариант датафрейма,
-
purrr – для функционального программирования (замена семейства функций
apply(); см. Глава 8.5.1), -
readr – для чтения таблиц в текстовом виде, замена стандартным функциям семейства
read.table(), - ggplot2 – для визуализации данных с использованием Grammar of Graphics (Глава 14),
- stringr – для работы со строковыми переменными,
- forcats – для работы с переменными-факторами.

В 2023 году в ядро tidyverse добавили ещё один пакет, который, правда, является одним из самых старых пакетов Хэдли Уикхэма:
-
lubridate – для работы с датами и временем.
-
Дополнительные пакеты tidyverse: они не подключаются при вызове
library(tidyverse), но они также разделяют подход tidyverse, дополняя и развивая его. Определить границы “расширенного” tidyverse очень сложно. Во-первых, есть еще много других небольших пакетов от команды tidyverse, которые тоже считаются частью tidyverse. Во-вторых, кроме официальных пакетов от команды tidyverse есть множество пакетов от других разработчиков, которые пытаются соответствовать принципам tidyverse и дополняют их.
-
Дополнительные пакеты tidyverse: они не подключаются при вызове
10.2 Загрузка данных с помощью {readr}
Стандартной функцией для чтения .csv файлов в R является функция read.csv(), но мы будем использовать функцию read_csv() из пакета readr. Синтаксис функции read_csv() очень похож на read.csv(): первым аргументом является путь к файлу (в том числе можно использовать URL), некоторые остальные параметры тоже совпадают.
heroes <- read_csv("https://raw.githubusercontent.com/Pozdniakov/tidy_stats/master/data/heroes_information.csv",
na = c("-", "-99", "NA", " "))New names:
• `` -> `...1`
Warning: One or more parsing issues, call `problems()` on your data frame for details,
e.g.:
dat <- vroom(...)
problems(dat)
Rows: 734 Columns: 11
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (8): name, Gender, Eye color, Race, Hair color, Publisher, Skin color, A...
dbl (3): ...1, Height, Weight
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Подробнее про импорт данных, в том числе в tidyverse, смотри в Глава 6.
10.3 tibble
Когда мы загрузили данные с помощью read_csv(), то мы получили объект класса tibble, а не data.frame:
class(heroes)[1] "spec_tbl_df" "tbl_df" "tbl" "data.frame"
Тиббл (tibble) - это такой “усовершенствованный” data.frame. Почти все, что работает с data.frame, работает и с тибблами. Однако у тибблов есть свои дополнительные фишки. Самая очевидная из них - более аккуратный вывод в консоль:
heroes# A tibble: 734 × 11
...1 name Gender `Eye color` Race `Hair color` Height Publisher
<dbl> <chr> <chr> <chr> <chr> <chr> <dbl> <chr>
1 0 A-Bomb Male yellow Human No Hair 203 Marvel C…
2 1 Abe Sapien Male blue Icthyo … No Hair 191 Dark Hor…
3 2 Abin Sur Male blue Ungaran No Hair 185 DC Comics
4 3 Abomination Male green Human /… No Hair 203 Marvel C…
5 4 Abraxas Male blue Cosmic … Black NA Marvel C…
6 5 Absorbing Man Male blue Human No Hair 193 Marvel C…
7 6 Adam Monroe Male blue <NA> Blond NA NBC - He…
8 7 Adam Strange Male blue Human Blond 185 DC Comics
9 8 Agent 13 Female blue <NA> Blond 173 Marvel C…
10 9 Agent Bob Male brown Human Brown 178 Marvel C…
# ℹ 724 more rows
# ℹ 3 more variables: `Skin color` <chr>, Alignment <chr>, Weight <dbl>
Выводятся только первые 10 строк, если какие-то колонки не влезают на экран, то они просто перечислены внизу. Ну а тип данных написан прямо под названием колонки.
Функции различных пакетов tidyverse сами конвертируют в тиббл при необходимости. Если же нужно это сделать самостоятельно, то можно это сделать так:
heroes_df <- as.data.frame(heroes) #создаем простой датафрейм
class(heroes_df)[1] "data.frame"
as_tibble(heroes_df) #превращаем обратно в тиббл# A tibble: 734 × 11
...1 name Gender `Eye color` Race `Hair color` Height Publisher
<dbl> <chr> <chr> <chr> <chr> <chr> <dbl> <chr>
1 0 A-Bomb Male yellow Human No Hair 203 Marvel C…
2 1 Abe Sapien Male blue Icthyo … No Hair 191 Dark Hor…
3 2 Abin Sur Male blue Ungaran No Hair 185 DC Comics
4 3 Abomination Male green Human /… No Hair 203 Marvel C…
5 4 Abraxas Male blue Cosmic … Black NA Marvel C…
6 5 Absorbing Man Male blue Human No Hair 193 Marvel C…
7 6 Adam Monroe Male blue <NA> Blond NA NBC - He…
8 7 Adam Strange Male blue Human Blond 185 DC Comics
9 8 Agent 13 Female blue <NA> Blond 173 Marvel C…
10 9 Agent Bob Male brown Human Brown 178 Marvel C…
# ℹ 724 more rows
# ℹ 3 more variables: `Skin color` <chr>, Alignment <chr>, Weight <dbl>
В дальнейшем мы будем работать только с tidyverse, а это значит, что только с тибблами, а не обычными датафреймами. Тем не менее, тибблы и датафреймы будут в дальнейшем использоваться как синонимы.
Можно создавать тибблы вручную с помощью функции tibble(), которая работает аналогично функции data.frame():
tibble(
a = 1:3,
b = letters[1:3]
)# A tibble: 3 × 2
a b
<int> <chr>
1 1 a
2 2 b
3 3 c
10.4 Пайпы: magrittr::%>% и встроенный |>
Мы уже привыкли к использованию векторизованных функций, работая в базовом R. Они позволяют нам делать сложные операции с целыми векторами без каких-либо циклов, просто передавая результат выполнения функций в качестве аргумента для других функций:
С одной стороны, это довольно лаконично и элегантно, с другой стороны, читается такой код с некоторым трудом: нам нужно найти где-то внутри начало операции (создание числового вектора 1:20), а затем читать изнутри наружу, чтобы понять порядок действий.
Оператор %>% из пакета magrittr1 позволяет переписать этот же код в более естественном для чтения порядке:
Здесь код читается последовательно слева направо. Или же даже можно сделать порядок “сверху вниз”:
Оператор %>% называется “пайпом” (pipe), т.е. “трубой”. Он означает, что следующая функция (справа от пайпа) принимает на вход в качестве первого аргумента результат выполнения предыдущей функции (той, что слева). Фактически, это примерно то же самое, что и вставлять результат выполнения функции в качестве первого аргумента в другую функцию. Просто выглядит это красивее и читабельнее. Как будто данные пропускаются через трубы функций или конвейерную ленту на заводе, если хотите. А то, что первый параметр функции — это почти всегда данные, работает нам здесь на руку.
В редких случаях нам нужно передать результат выполнения команды слева от пайпа не на первую позицию внутри функции. В этих случаях используется “плейсхолдер” (placeholder), который выглядит как простая точка: ., которую вы ставите туда, куда хотите передать результат выполнения команды слева от пайпа:
В этом случае логарифм будет посчитан для числа 2 с различными основаниями, которые были посчитаны до соответствующего пайпа.
10.4.1 Пайпы и tidyverse
Пайпы оказались невероятно удобным дополнением для функций tidyverse. Основные функции tidyverse предполагают работу с тибблами: первый аргумент — тиббл, последующие аргументы настраивают функции, на выходе из функции мы получаем изменённый тиббл. Этот тиббл “пробрасывается” по функциям, а написание кода превращается в итеративное и интерактивное “дописывание” пайпов с новой функцией снизу.
Впрочем, пайпы могут встретиться и внутри функций tidyverse, а не только между ними, так как пайпы удачно встраиваются в работу с векторами, матрицами и списками. Неудивительно, что пайпы стали популярны и за пределами tidyverse тоже.
10.4.2 Нативный пайп |>
В R 4.1.0 (май 2021) появились встроенные пайпы, которые уже не требуют подключения никаких дополнительных пакетов. Смысл этих пайпов тот же самый, но выглядят они немного по-другому: сам нативный пайп пишется |> (вместо %>% из magrittr), а плейсхолдер — _ (вместо . в magrittr):
Пока что в этой книге используются старые пайпы из magrittr (%>%): код с новыми пайпами (|>) не будет работать в более старых версиях R. В какой-то момент нативные пайпы (|>), скорее всего, полностью вытеснят пайпы из magrittr (%>%), в том числе и в самом tidyverse (A personal history of the tidyverse). Более подробную историю появления и развития пайпов в R можно прочитать в статье Адольфо Альвареза (Plumbers, chains, and famous painters: The (updated) history of the pipe operator in R).
Важно понимать, что пайп не даёт какой-то дополнительной функциональности или дополнительной скорости работы2. Он создан исключительно для читабельности и комфорта.
10.5 Главные пакеты tidyverse: dplyr и tidyr
dplyr3 — это самая основа всего tidyverse. Этот пакет предоставляет основные функции для манипуляции с тибблами. Пакет dplyr является наследником и более усовершенствованной версией plyr, так что если увидите использование пакета plyr, то, скорее всего, скрипт был написан очень давно.
Пакет tidyr дополняет dplyr, предоставляя полезные функции для тайдификации тибблов. Тайдификация (“аккуратизация”) данных означает приведение табличных данных к такому формату, в котором:
- Каждая переменная имеет собственный столбец
- Каждое наблюдение имеет собственную строку
- Каждое значение имеет свою собственную ячейку
Впрочем, многие функции dplyr часто используются при тайдификации, так же, как и многие функции tidyr имеют применение вне тайдификации. В общем, функционал этих двух пакетов несколько смешался, поэтому мы будем рассматривать их вместе. А чтобы представлять, какая функция относится к какому пакету (хотя запоминать это необязательно), я буду использовать запись с двумя двоеточиями ::, которая обычно применяется для вызова функции без подгрузки всего пакета, при первом упоминании функции.
Пакет tidyr — это более усовершенствованная версия пакета reshape2, который в свою очередь является усовершенствованной версией reshape. По аналогии с plyr, если вы видите использование этих пакетов, то это указывает на то, что перед вами морально устаревший код.
Код с использованием dplyr и tidyr сильно непохож на то, что мы видели раньше. Большинство функций dplyr и tidyr работают с целым тибблом сразу, принимая его в качестве первого аргумента и возвращая измененный тиббл. Это позволяет превратить весь код в последовательный набор применяемых функций, соединенный пайпами. На практике это выглядит очень элегантно, и вы в этом скоро убедитесь.
10.6 Работа с колонками тиббла
10.6.1 Выбор колонок: dplyr::select()
Функция dplyr::select() позволяет выбирать колонки по номеру или имени (кавычки не нужны).
# A tibble: 734 × 2
...1 Race
<dbl> <chr>
1 0 Human
2 1 Icthyo Sapien
3 2 Ungaran
4 3 Human / Radiation
5 4 Cosmic Entity
6 5 Human
7 6 <NA>
8 7 Human
9 8 <NA>
10 9 Human
# ℹ 724 more rows
# A tibble: 734 × 4
name Race Publisher `Hair color`
<chr> <chr> <chr> <chr>
1 A-Bomb Human Marvel Comics No Hair
2 Abe Sapien Icthyo Sapien Dark Horse Comics No Hair
3 Abin Sur Ungaran DC Comics No Hair
4 Abomination Human / Radiation Marvel Comics No Hair
5 Abraxas Cosmic Entity Marvel Comics Black
6 Absorbing Man Human Marvel Comics No Hair
7 Adam Monroe <NA> NBC - Heroes Blond
8 Adam Strange Human DC Comics Blond
9 Agent 13 <NA> Marvel Comics Blond
10 Agent Bob Human Marvel Comics Brown
# ℹ 724 more rows
Обратите внимание, если в названии колонки присутствует пробел или, например, колонка начинается с цифры или точки и цифры, то это синтаксически невалидное имя (Глава 2.6). Это не значит, что такие названия колонок недопустимы. Но такие названия колонок нужно обособлять ` грависом (правый штрих, на клавиатуре находится там же где и буква ё и ~).
Еще обратите внимание на то, что функции tidyverse не изменяют сами изначальные тибблы/датафреймы. Это означает, что если вы хотите полученный результат сохранить, то нужно добавить присвоение:
# A tibble: 734 × 4
name Race Publisher `Hair color`
<chr> <chr> <chr> <chr>
1 A-Bomb Human Marvel Comics No Hair
2 Abe Sapien Icthyo Sapien Dark Horse Comics No Hair
3 Abin Sur Ungaran DC Comics No Hair
4 Abomination Human / Radiation Marvel Comics No Hair
5 Abraxas Cosmic Entity Marvel Comics Black
6 Absorbing Man Human Marvel Comics No Hair
7 Adam Monroe <NA> NBC - Heroes Blond
8 Adam Strange Human DC Comics Blond
9 Agent 13 <NA> Marvel Comics Blond
10 Agent Bob Human Marvel Comics Brown
# ℹ 724 more rows
10.6.2 Мини-язык tidy selection для выбора колонок
Для выбора столбцов (не только в select(), но и для других функций tidyverse) используется специальный мини-язык tidy selection из пакета tidyselect4. Tidy selection даёт очень широкие возможности для выбора колонок.
Можно использовать оператор : для выбора нескольких соседних колонок (по аналогии с созданием числового вектора с шагом 1).
# A tibble: 734 × 7
name Gender `Eye color` Race `Hair color` Height Publisher
<chr> <chr> <chr> <chr> <chr> <dbl> <chr>
1 A-Bomb Male yellow Human No Hair 203 Marvel C…
2 Abe Sapien Male blue Icthyo Sapien No Hair 191 Dark Hor…
3 Abin Sur Male blue Ungaran No Hair 185 DC Comics
4 Abomination Male green Human / Radia… No Hair 203 Marvel C…
5 Abraxas Male blue Cosmic Entity Black NA Marvel C…
6 Absorbing Man Male blue Human No Hair 193 Marvel C…
7 Adam Monroe Male blue <NA> Blond NA NBC - He…
8 Adam Strange Male blue Human Blond 185 DC Comics
9 Agent 13 Female blue <NA> Blond 173 Marvel C…
10 Agent Bob Male brown Human Brown 178 Marvel C…
# ℹ 724 more rows
# A tibble: 734 × 7
name Gender `Eye color` Publisher `Skin color` Alignment Weight
<chr> <chr> <chr> <chr> <chr> <chr> <dbl>
1 A-Bomb Male yellow Marvel Comics <NA> good 441
2 Abe Sapien Male blue Dark Horse Co… blue good 65
3 Abin Sur Male blue DC Comics red good 90
4 Abomination Male green Marvel Comics <NA> bad 441
5 Abraxas Male blue Marvel Comics <NA> bad NA
6 Absorbing Man Male blue Marvel Comics <NA> bad 122
7 Adam Monroe Male blue NBC - Heroes <NA> good NA
8 Adam Strange Male blue DC Comics <NA> good 88
9 Agent 13 Female blue Marvel Comics <NA> good 61
10 Agent Bob Male brown Marvel Comics <NA> good 81
# ℹ 724 more rows
Используя ! можно вырезать ненужные колонки.
# A tibble: 734 × 10
name Gender `Eye color` Race `Hair color` Height Publisher `Skin color`
<chr> <chr> <chr> <chr> <chr> <dbl> <chr> <chr>
1 A-Bomb Male yellow Human No Hair 203 Marvel C… <NA>
2 Abe Sapi… Male blue Icth… No Hair 191 Dark Hor… blue
3 Abin Sur Male blue Unga… No Hair 185 DC Comics red
4 Abominat… Male green Huma… No Hair 203 Marvel C… <NA>
5 Abraxas Male blue Cosm… Black NA Marvel C… <NA>
6 Absorbin… Male blue Human No Hair 193 Marvel C… <NA>
7 Adam Mon… Male blue <NA> Blond NA NBC - He… <NA>
8 Adam Str… Male blue Human Blond 185 DC Comics <NA>
9 Agent 13 Female blue <NA> Blond 173 Marvel C… <NA>
10 Agent Bob Male brown Human Brown 178 Marvel C… <NA>
# ℹ 724 more rows
# ℹ 2 more variables: Alignment <chr>, Weight <dbl>
# A tibble: 734 × 6
...1 name Publisher `Skin color` Alignment Weight
<dbl> <chr> <chr> <chr> <chr> <dbl>
1 0 A-Bomb Marvel Comics <NA> good 441
2 1 Abe Sapien Dark Horse Comics blue good 65
3 2 Abin Sur DC Comics red good 90
4 3 Abomination Marvel Comics <NA> bad 441
5 4 Abraxas Marvel Comics <NA> bad NA
6 5 Absorbing Man Marvel Comics <NA> bad 122
7 6 Adam Monroe NBC - Heroes <NA> good NA
8 7 Adam Strange DC Comics <NA> good 88
9 8 Agent 13 Marvel Comics <NA> good 61
10 9 Agent Bob Marvel Comics <NA> good 81
# ℹ 724 more rows
Другие известные нам логические операторы (& и |) тоже работают в tidy selection.
В дополнение к логическим операторам и :, в tidy selection есть набор вспомогательных функций, работающих исключительно в контексте выбора колонок.
Вспомогательная функция last_col() позволит обратиться к последней колонке тиббла:
# A tibble: 734 × 10
name Gender `Eye color` Race `Hair color` Height Publisher `Skin color`
<chr> <chr> <chr> <chr> <chr> <dbl> <chr> <chr>
1 A-Bomb Male yellow Human No Hair 203 Marvel C… <NA>
2 Abe Sapi… Male blue Icth… No Hair 191 Dark Hor… blue
3 Abin Sur Male blue Unga… No Hair 185 DC Comics red
4 Abominat… Male green Huma… No Hair 203 Marvel C… <NA>
5 Abraxas Male blue Cosm… Black NA Marvel C… <NA>
6 Absorbin… Male blue Human No Hair 193 Marvel C… <NA>
7 Adam Mon… Male blue <NA> Blond NA NBC - He… <NA>
8 Adam Str… Male blue Human Blond 185 DC Comics <NA>
9 Agent 13 Female blue <NA> Blond 173 Marvel C… <NA>
10 Agent Bob Male brown Human Brown 178 Marvel C… <NA>
# ℹ 724 more rows
# ℹ 2 more variables: Alignment <chr>, Weight <dbl>
А функция everything() позволяет выбрать все колонки.
heroes %>%
select(everything())# A tibble: 734 × 11
...1 name Gender `Eye color` Race `Hair color` Height Publisher
<dbl> <chr> <chr> <chr> <chr> <chr> <dbl> <chr>
1 0 A-Bomb Male yellow Human No Hair 203 Marvel C…
2 1 Abe Sapien Male blue Icthyo … No Hair 191 Dark Hor…
3 2 Abin Sur Male blue Ungaran No Hair 185 DC Comics
4 3 Abomination Male green Human /… No Hair 203 Marvel C…
5 4 Abraxas Male blue Cosmic … Black NA Marvel C…
6 5 Absorbing Man Male blue Human No Hair 193 Marvel C…
7 6 Adam Monroe Male blue <NA> Blond NA NBC - He…
8 7 Adam Strange Male blue Human Blond 185 DC Comics
9 8 Agent 13 Female blue <NA> Blond 173 Marvel C…
10 9 Agent Bob Male brown Human Brown 178 Marvel C…
# ℹ 724 more rows
# ℹ 3 more variables: `Skin color` <chr>, Alignment <chr>, Weight <dbl>
При этом everything() не будет дублировать выбранные колонки, поэтому можно использовать everything() для перестановки колонок в тиббле:
heroes %>%
select(name, Publisher, everything())# A tibble: 734 × 11
name Publisher ...1 Gender `Eye color` Race `Hair color` Height
<chr> <chr> <dbl> <chr> <chr> <chr> <chr> <dbl>
1 A-Bomb Marvel Comi… 0 Male yellow Human No Hair 203
2 Abe Sapien Dark Horse … 1 Male blue Icth… No Hair 191
3 Abin Sur DC Comics 2 Male blue Unga… No Hair 185
4 Abomination Marvel Comi… 3 Male green Huma… No Hair 203
5 Abraxas Marvel Comi… 4 Male blue Cosm… Black NA
6 Absorbing Man Marvel Comi… 5 Male blue Human No Hair 193
7 Adam Monroe NBC - Heroes 6 Male blue <NA> Blond NA
8 Adam Strange DC Comics 7 Male blue Human Blond 185
9 Agent 13 Marvel Comi… 8 Female blue <NA> Blond 173
10 Agent Bob Marvel Comi… 9 Male brown Human Brown 178
# ℹ 724 more rows
# ℹ 3 more variables: `Skin color` <chr>, Alignment <chr>, Weight <dbl>
Впрочем, для перестановки колонок удобнее использовать специальную функцию relocate() (Глава 10.6.4). Можно даже выбирать колонки по паттернам в названиях. Например, с помощью ends_with() можно выбрать все колонки, заканчивающиеся одинаковым суффиксом:
# A tibble: 734 × 3
`Eye color` `Hair color` `Skin color`
<chr> <chr> <chr>
1 yellow No Hair <NA>
2 blue No Hair blue
3 blue No Hair red
4 green No Hair <NA>
5 blue Black <NA>
6 blue No Hair <NA>
7 blue Blond <NA>
8 blue Blond <NA>
9 blue Blond <NA>
10 brown Brown <NA>
# ℹ 724 more rows
Аналогично, с помощью функции starts_with() можно найти колонки с одинаковым префиксом, с помощью contains() — все колонки с выбранным паттерном в любой части названия колонки5.
heroes %>%
select(starts_with("Eye") & ends_with("color"))# A tibble: 734 × 1
`Eye color`
<chr>
1 yellow
2 blue
3 blue
4 green
5 blue
6 blue
7 blue
8 blue
9 blue
10 brown
# ℹ 724 more rows
# A tibble: 734 × 2
Height Weight
<dbl> <dbl>
1 203 441
2 191 65
3 185 90
4 203 441
5 NA NA
6 193 122
7 NA NA
8 185 88
9 173 61
10 178 81
# ℹ 724 more rows
Ну и наконец, можно выбирать по содержимому колонок с помощью where(). Это напоминает применение sapply()(Глава 8.5.3) на датафрейме для индексирования колонок: в качестве аргумента для where принимается функция, которая применяется для каждой из колонок, после чего выбираются только те колонки, для которых было получено TRUE.
# A tibble: 734 × 3
...1 Height Weight
<dbl> <dbl> <dbl>
1 0 203 441
2 1 191 65
3 2 185 90
4 3 203 441
5 4 NA NA
6 5 193 122
7 6 NA NA
8 7 185 88
9 8 173 61
10 9 178 81
# ℹ 724 more rows
Функция where() даёт невиданную мощь: можно использовать как встроенные или созданные функции, так и анонимные функции. Например, можно выбрать все колонки без NA:
# A tibble: 734 × 3
...1 name Publisher
<dbl> <chr> <chr>
1 0 A-Bomb Marvel Comics
2 1 Abe Sapien Dark Horse Comics
3 2 Abin Sur DC Comics
4 3 Abomination Marvel Comics
5 4 Abraxas Marvel Comics
6 5 Absorbing Man Marvel Comics
7 6 Adam Monroe NBC - Heroes
8 7 Adam Strange DC Comics
9 8 Agent 13 Marvel Comics
10 9 Agent Bob Marvel Comics
# ℹ 724 more rows
10.6.3 Переименование колонок: dplyr::rename()
Внутри select() можно не только выбирать колонки, но и переименовывать их:
# A tibble: 734 × 1
id
<dbl>
1 0
2 1
3 2
4 3
5 4
6 5
7 6
8 7
9 8
10 9
# ℹ 724 more rows
Однако удобнее для этого использовать специальную функцию dplyr::rename(). Синтаксис у нее такой же, как и у select(), но rename() не выбрасывает колонки, которые не были упомянуты.
# A tibble: 734 × 11
id name Gender `Eye color` Race `Hair color` Height Publisher
<dbl> <chr> <chr> <chr> <chr> <chr> <dbl> <chr>
1 0 A-Bomb Male yellow Human No Hair 203 Marvel C…
2 1 Abe Sapien Male blue Icthyo … No Hair 191 Dark Hor…
3 2 Abin Sur Male blue Ungaran No Hair 185 DC Comics
4 3 Abomination Male green Human /… No Hair 203 Marvel C…
5 4 Abraxas Male blue Cosmic … Black NA Marvel C…
6 5 Absorbing Man Male blue Human No Hair 193 Marvel C…
7 6 Adam Monroe Male blue <NA> Blond NA NBC - He…
8 7 Adam Strange Male blue Human Blond 185 DC Comics
9 8 Agent 13 Female blue <NA> Blond 173 Marvel C…
10 9 Agent Bob Male brown Human Brown 178 Marvel C…
# ℹ 724 more rows
# ℹ 3 more variables: `Skin color` <chr>, Alignment <chr>, Weight <dbl>
Для массового переименования колонок можно использовать функцию rename_with(). Эта функция также использует синтаксис tidy selection для выбора колонок (по умолчанию выбираются все колонки) и применяет функцию-аргумент к названиям выбранных колонок:
heroes %>%
rename_with(make.names)# A tibble: 734 × 11
...1 name Gender Eye.color Race Hair.color Height Publisher Skin.color
<dbl> <chr> <chr> <chr> <chr> <chr> <dbl> <chr> <chr>
1 0 A-Bomb Male yellow Human No Hair 203 Marvel C… <NA>
2 1 Abe Sapi… Male blue Icth… No Hair 191 Dark Hor… blue
3 2 Abin Sur Male blue Unga… No Hair 185 DC Comics red
4 3 Abominat… Male green Huma… No Hair 203 Marvel C… <NA>
5 4 Abraxas Male blue Cosm… Black NA Marvel C… <NA>
6 5 Absorbin… Male blue Human No Hair 193 Marvel C… <NA>
7 6 Adam Mon… Male blue <NA> Blond NA NBC - He… <NA>
8 7 Adam Str… Male blue Human Blond 185 DC Comics <NA>
9 8 Agent 13 Female blue <NA> Blond 173 Marvel C… <NA>
10 9 Agent Bob Male brown Human Brown 178 Marvel C… <NA>
# ℹ 724 more rows
# ℹ 2 more variables: Alignment <chr>, Weight <dbl>
10.6.4 Перестановка колонок: dplyr::relocate()
Для изменения порядка колонок можно использовать функцию relocate(). Она тоже работает похожим образом на select() и rename()6. Как и rename(), функция relocate() не выкидывает неиспользованные колонки:
# A tibble: 734 × 11
Publisher ...1 name Gender `Eye color` Race `Hair color` Height
<chr> <dbl> <chr> <chr> <chr> <chr> <chr> <dbl>
1 Marvel Comics 0 A-Bomb Male yellow Human No Hair 203
2 Dark Horse Comics 1 Abe Sap… Male blue Icth… No Hair 191
3 DC Comics 2 Abin Sur Male blue Unga… No Hair 185
4 Marvel Comics 3 Abomina… Male green Huma… No Hair 203
5 Marvel Comics 4 Abraxas Male blue Cosm… Black NA
6 Marvel Comics 5 Absorbi… Male blue Human No Hair 193
7 NBC - Heroes 6 Adam Mo… Male blue <NA> Blond NA
8 DC Comics 7 Adam St… Male blue Human Blond 185
9 Marvel Comics 8 Agent 13 Female blue <NA> Blond 173
10 Marvel Comics 9 Agent B… Male brown Human Brown 178
# ℹ 724 more rows
# ℹ 3 more variables: `Skin color` <chr>, Alignment <chr>, Weight <dbl>
При этом relocate() имеет дополнительные параметры .after = и .before =, которые позволяют выбирать, куда поместить выбранные колонки.
# A tibble: 734 × 11
...1 name Publisher Gender `Eye color` Race `Hair color` Height
<dbl> <chr> <chr> <chr> <chr> <chr> <chr> <dbl>
1 0 A-Bomb Marvel Comi… Male yellow Human No Hair 203
2 1 Abe Sapien Dark Horse … Male blue Icth… No Hair 191
3 2 Abin Sur DC Comics Male blue Unga… No Hair 185
4 3 Abomination Marvel Comi… Male green Huma… No Hair 203
5 4 Abraxas Marvel Comi… Male blue Cosm… Black NA
6 5 Absorbing Man Marvel Comi… Male blue Human No Hair 193
7 6 Adam Monroe NBC - Heroes Male blue <NA> Blond NA
8 7 Adam Strange DC Comics Male blue Human Blond 185
9 8 Agent 13 Marvel Comi… Female blue <NA> Blond 173
10 9 Agent Bob Marvel Comi… Male brown Human Brown 178
# ℹ 724 more rows
# ℹ 3 more variables: `Skin color` <chr>, Alignment <chr>, Weight <dbl>
relocate() очень хорошо работает в сочетании с выбором колонок с помощью tidy selection. Например, можно передвинуть в одно место все колонки с одним типом данных:
# A tibble: 734 × 11
name Publisher ...1 Height Weight Gender `Eye color` Race `Hair color`
<chr> <chr> <dbl> <dbl> <dbl> <chr> <chr> <chr> <chr>
1 A-Bomb Marvel C… 0 203 441 Male yellow Human No Hair
2 Abe Sapi… Dark Hor… 1 191 65 Male blue Icth… No Hair
3 Abin Sur DC Comics 2 185 90 Male blue Unga… No Hair
4 Abominat… Marvel C… 3 203 441 Male green Huma… No Hair
5 Abraxas Marvel C… 4 NA NA Male blue Cosm… Black
6 Absorbin… Marvel C… 5 193 122 Male blue Human No Hair
7 Adam Mon… NBC - He… 6 NA NA Male blue <NA> Blond
8 Adam Str… DC Comics 7 185 88 Male blue Human Blond
9 Agent 13 Marvel C… 8 173 61 Female blue <NA> Blond
10 Agent Bob Marvel C… 9 178 81 Male brown Human Brown
# ℹ 724 more rows
# ℹ 2 more variables: `Skin color` <chr>, Alignment <chr>
10.6.5 Извлечение колонки как вектора: dplyr::pull()
Последняя важная функция для выбора колонок — pull(). Эта функция делает то же самое, что и индексирование с помощью $, т.е. вытаскивает из тиббла вектор с выбранным названием. Это лучше вписывается в логику tidyverse, поскольку позволяет извлечь колонку из тиббла с использованием пайпа:
[1] 203 191 185 203 NA 193
[1] 203 191 185 203 NA 193
У функции pull() есть аргумент name =, который позволяет создать проименованный вектор:
A-Bomb Abe Sapien Abin Sur Abomination Abraxas
203 191 185 203 NA
Absorbing Man
193
В отличие от базового R, tidyverse нигде не сокращает имплицитно результат вычислений до вектора, поэтому функция pull() - это основной способ извлечения колонки из тиббла как вектора.
10.7 Работа со строками тиббла
10.7.1 Выбор строк по номеру: dplyr::slice()
Начнем с выбора строк. Функция dplyr::slice() выбирает строчки по их числовому индексу.
# A tibble: 3 × 11
...1 name Gender `Eye color` Race `Hair color` Height Publisher
<dbl> <chr> <chr> <chr> <chr> <chr> <dbl> <chr>
1 0 A-Bomb Male yellow Human No Hair 203 Marvel C…
2 1 Abe Sapien Male blue Icthyo Sapi… No Hair 191 Dark Hor…
3 2 Abin Sur Male blue Ungaran No Hair 185 DC Comics
# ℹ 3 more variables: `Skin color` <chr>, Alignment <chr>, Weight <dbl>
10.7.2 Выбор строк по условию: dplyr::filter()
Функция dplyr::filter() делает то же самое, что и slice(), но уже по условию. Причем для условий нужно использовать не векторы из тиббла, а название колонок (без кавычек) как будто бы они были переменными в окружении.
# A tibble: 215 × 11
...1 name Gender `Eye color` Race `Hair color` Height Publisher
<dbl> <chr> <chr> <chr> <chr> <chr> <dbl> <chr>
1 2 Abin Sur Male blue Unga… No Hair 185 DC Comics
2 7 Adam Strange Male blue Human Blond 185 DC Comics
3 13 Alan Scott Male blue <NA> Blond 180 DC Comics
4 16 Alfred Pennywor… Male blue Human Black 178 DC Comics
5 19 Amazo Male red Andr… <NA> 257 DC Comics
6 27 Animal Man Male blue Human Blond 183 DC Comics
7 31 Anti-Monitor Male yellow God … No Hair 61 DC Comics
8 35 Aquababy Male blue <NA> Blond NA DC Comics
9 36 Aqualad Male blue Atla… Black 178 DC Comics
10 37 Aquaman Male blue Atla… Blond 185 DC Comics
# ℹ 205 more rows
# ℹ 3 more variables: `Skin color` <chr>, Alignment <chr>, Weight <dbl>
10.7.3 Семейство функций slice()
У функции slice() есть множество родственников, которые объединяют функционал обычного slice() и filter(). Например, с помощью функций dplyr::slice_max() и dplyr::slice_min() можно выбрать заданное количество строк, содержащих наибольшие или наименьшие значения по колонке соответственно:
# A tibble: 3 × 11
...1 name Gender `Eye color` Race `Hair color` Height Publisher
<dbl> <chr> <chr> <chr> <chr> <chr> <dbl> <chr>
1 575 Sasquatch Male red <NA> Orange 305 Marvel Comics
2 373 Juggernaut Male blue Human Red 287 Marvel Comics
3 203 Darkseid Male red New God No Hair 267 DC Comics
# ℹ 3 more variables: `Skin color` <chr>, Alignment <chr>, Weight <dbl>
# A tibble: 3 × 11
...1 name Gender `Eye color` Race `Hair color` Height Publisher
<dbl> <chr> <chr> <chr> <chr> <chr> <dbl> <chr>
1 346 Iron Monger Male blue <NA> No Hair NA Marvel C…
2 302 Groot Male yellow Flora Colo… <NA> 701 Marvel C…
3 350 Jack-Jack Male blue Human Brown 71 Dark Hor…
# ℹ 3 more variables: `Skin color` <chr>, Alignment <chr>, Weight <dbl>
Функция slice_sample() позволяет выбирать заданное количество случайных строчек:
heroes %>%
slice_sample(n = 3)# A tibble: 3 × 11
...1 name Gender `Eye color` Race `Hair color` Height Publisher
<dbl> <chr> <chr> <chr> <chr> <chr> <dbl> <chr>
1 400 Lady Deathstrike Female brown Cyborg Black 175 Marvel C…
2 309 Harry Potter Male green Human Black NA J. K. Ro…
3 514 Penguin Male blue Human Black 157 DC Comics
# ℹ 3 more variables: `Skin color` <chr>, Alignment <chr>, Weight <dbl>
Или же долю строчек:
heroes %>%
slice_sample(prop = .01)# A tibble: 7 × 11
...1 name Gender `Eye color` Race `Hair color` Height Publisher
<dbl> <chr> <chr> <chr> <chr> <chr> <dbl> <chr>
1 497 Nova Female white Human / C… Red 163 Marvel C…
2 591 She-Hulk Female green Human Green 201 Marvel C…
3 338 Iceman Male brown Mutant Brown 173 Marvel C…
4 525 Power Girl Female blue Kryptonian blond 180 DC Comics
5 458 Mister Knife Male blue Spartoi Brown NA Marvel C…
6 71 Battlestar Male brown <NA> Black 198 Marvel C…
7 713 White Canary Female brown Human Black NA DC Comics
# ℹ 3 more variables: `Skin color` <chr>, Alignment <chr>, Weight <dbl>
Если поставить значение параметра prop = равным 1, то таким образом можно перемешать порядок строчек в тиббле:
heroes %>%
slice_sample(prop = 1)# A tibble: 734 × 11
...1 name Gender `Eye color` Race `Hair color` Height Publisher
<dbl> <chr> <chr> <chr> <chr> <chr> <dbl> <chr>
1 593 Shocker Male brown Human Brown 175 Marvel C…
2 454 Misfit Female blue <NA> Red NA DC Comics
3 578 Scarecrow Male blue Human Brown 183 DC Comics
4 344 Iron Fist Male blue Human Blond 180 Marvel C…
5 604 Siren Female blue Atlant… Purple 175 DC Comics
6 492 Niki Sanders Female blue <NA> Blond NA NBC - He…
7 14 Alex Mercer Male <NA> Human <NA> NA Wildstorm
8 662 Thor Girl Female blue Asgard… Blond 175 Marvel C…
9 282 Giant-Man II Male <NA> <NA> <NA> NA Marvel C…
10 269 Franklin Storm <NA> blue <NA> Grey 188 Marvel C…
# ℹ 724 more rows
# ℹ 3 more variables: `Skin color` <chr>, Alignment <chr>, Weight <dbl>
10.7.4 Удаление строчек с NA: tidyr::drop_na()
Если нужно выбрать только строчки без пропущенных значений, то можно воспользоваться удобной функцией tidyr::drop_na().
# A tibble: 50 × 11
...1 name Gender `Eye color` Race `Hair color` Height Publisher
<dbl> <chr> <chr> <chr> <chr> <chr> <dbl> <chr>
1 1 Abe Sapien Male blue Icthyo Sap… No Hair 191 Dark Hor…
2 2 Abin Sur Male blue Ungaran No Hair 185 DC Comics
3 34 Apocalypse Male red Mutant Black 213 Marvel C…
4 39 Archangel Male blue Mutant Blond 183 Marvel C…
5 41 Ardina Female white Alien Orange 193 Marvel C…
6 56 Azazel Male yellow Neyaphem Black 183 Marvel C…
7 74 Beast Male blue Mutant Blue 180 Marvel C…
8 75 Beast Boy Male green Human Green 173 DC Comics
9 92 Bizarro Male black Bizarro Black 191 DC Comics
10 108 Blackout Male red Demon White 191 Marvel C…
# ℹ 40 more rows
# ℹ 3 more variables: `Skin color` <chr>, Alignment <chr>, Weight <dbl>
Можно выбрать колонки, наличие NA в которых будет приводить к удалению соответствующих строчек (не затрагивая другие строчки, в которых есть NA в остальных столбцах).
# A tibble: 495 × 11
...1 name Gender `Eye color` Race `Hair color` Height Publisher
<dbl> <chr> <chr> <chr> <chr> <chr> <dbl> <chr>
1 0 A-Bomb Male yellow Human No Hair 203 Marvel C…
2 1 Abe Sapien Male blue Icthyo … No Hair 191 Dark Hor…
3 2 Abin Sur Male blue Ungaran No Hair 185 DC Comics
4 3 Abomination Male green Human /… No Hair 203 Marvel C…
5 5 Absorbing Man Male blue Human No Hair 193 Marvel C…
6 7 Adam Strange Male blue Human Blond 185 DC Comics
7 8 Agent 13 Female blue <NA> Blond 173 Marvel C…
8 9 Agent Bob Male brown Human Brown 178 Marvel C…
9 10 Agent Zero Male <NA> <NA> <NA> 191 Marvel C…
10 11 Air-Walker Male blue <NA> White 188 Marvel C…
# ℹ 485 more rows
# ℹ 3 more variables: `Skin color` <chr>, Alignment <chr>, Weight <dbl>
Для выбора колонок в drop_na() используется tidy selection, с которым мы недавно познакомились (Глава 10.6.2).
10.7.5 Сортировка строк: dplyr::arrange()
Функция dplyr::arrange() сортирует строчки от меньшего к большему (или по алфавиту - для текстовых значений) по выбранной колонке.
# A tibble: 734 × 11
...1 name Gender `Eye color` Race `Hair color` Height Publisher
<dbl> <chr> <chr> <chr> <chr> <chr> <dbl> <chr>
1 346 Iron Monger Male blue <NA> No Hair NA Marvel C…
2 302 Groot Male yellow Flora… <NA> 701 Marvel C…
3 350 Jack-Jack Male blue Human Brown 71 Dark Hor…
4 272 Galactus Male black Cosmi… Black 876 Marvel C…
5 731 Yoda Male brown Yoda'… White 66 George L…
6 255 Fin Fang Foom Male red Kakar… No Hair 975 Marvel C…
7 330 Howard the Duck Male brown <NA> Yellow 79 Marvel C…
8 396 Krypto Male blue Krypt… White 64 DC Comics
9 568 Rocket Raccoon Male brown Animal Brown 122 Marvel C…
10 208 Dash Male blue Human Blond 122 Dark Hor…
# ℹ 724 more rows
# ℹ 3 more variables: `Skin color` <chr>, Alignment <chr>, Weight <dbl>
Чтобы отсортировать в обратном порядке, воспользуйтесь функцией desc().
# A tibble: 734 × 11
...1 name Gender `Eye color` Race `Hair color` Height Publisher
<dbl> <chr> <chr> <chr> <chr> <chr> <dbl> <chr>
1 575 Sasquatch Male red <NA> Orange 305 Marvel C…
2 373 Juggernaut Male blue Human Red 287 Marvel C…
3 203 Darkseid Male red New God No Hair 267 DC Comics
4 283 Giganta Female green <NA> Red 62.5 DC Comics
5 331 Hulk Male green Human / Ra… Green 244 Marvel C…
6 549 Red Hulk Male yellow Human / Ra… Black 213 Marvel C…
7 119 Bloodaxe Female blue Human Brown 218 Marvel C…
8 718 Wolfsbane Female green <NA> Auburn 366 Marvel C…
9 657 Thanos Male red Eternal No Hair 201 Marvel C…
10 0 A-Bomb Male yellow Human No Hair 203 Marvel C…
# ℹ 724 more rows
# ℹ 3 more variables: `Skin color` <chr>, Alignment <chr>, Weight <dbl>
Можно сортировать по нескольким колонкам сразу. В таких случаях удобно в качестве первой переменной выбирать переменную, обозначающую принадлежность к группе, а в качестве второй — континуальную числовую переменную:
# A tibble: 734 × 11
...1 name Gender `Eye color` Race `Hair color` Height Publisher
<dbl> <chr> <chr> <chr> <chr> <chr> <dbl> <chr>
1 283 Giganta Female green <NA> Red 62.5 DC Comics
2 119 Bloodaxe Female blue Human Brown 218 Marvel C…
3 718 Wolfsbane Female green <NA> Auburn 366 Marvel C…
4 591 She-Hulk Female green Human Green 201 Marvel C…
5 320 Hela Female green Asgardian Black 213 Marvel C…
6 686 Valkyrie Female blue <NA> Blond 191 Marvel C…
7 596 Sif Female blue Asgardian Black 188 Marvel C…
8 271 Frigga Female blue <NA> White 180 Marvel C…
9 667 Thundra Female green <NA> Red 218 Marvel C…
10 592 She-Thing Female blue Human / Rad… No Hair 183 Marvel C…
# ℹ 724 more rows
# ℹ 3 more variables: `Skin color` <chr>, Alignment <chr>, Weight <dbl>
10.8 Создание колонок: dplyr::mutate() и dplyr::transmute()
Функция dplyr::mutate() позволяет создавать новые колонки в тиббле.
# A tibble: 734 × 2
name imt
<chr> <dbl>
1 Utgard-Loki 2510.
2 Giganta 1613.
3 Red Hulk 139.
4 Darkseid 115.
5 Machine Man 114.
6 Thanos 110.
7 Destroyer 108.
8 A-Bomb 107.
9 Abomination 107.
10 Hulk 106.
# ℹ 724 more rows
dplyr::transmute() - это аналог mutate(), который не только создает новые колонки, но и сразу же выкидывает все старые:
# A tibble: 734 × 1
imt
<dbl>
1 107.
2 17.8
3 26.3
4 107.
5 NA
6 32.8
7 NA
8 25.7
9 20.4
10 25.6
# ℹ 724 more rows
Внутри mutate() и transmute() мы можем использовать либо векторизованные операции (длина новой колонки должна равняться длине датафрейма), либо операции, которые возвращают одно значение. В последнем случае значение будет одинаковым на всю колонку, т.е. будет работать правило ресайклинга (Глава 3.4):
# A tibble: 734 × 2
name weight_mean
<chr> <dbl>
1 A-Bomb 112.
2 Abe Sapien 112.
3 Abin Sur 112.
4 Abomination 112.
5 Abraxas 112.
6 Absorbing Man 112.
7 Adam Monroe 112.
8 Adam Strange 112.
9 Agent 13 112.
10 Agent Bob 112.
# ℹ 724 more rows
Однако в функциях mutate() и transmute() правило ресайклинга не будет работать в остальных случаях: если полученный вектор будет не равен 1 или длине датафрейма, то мы получим ошибку.
Error in `mutate()`:
ℹ In argument: `one_and_two = 1:2`.
Caused by error:
! `one_and_two` must be size 734 or 1, not 2.
Это не баг, а фича: авторы пакета dplyr считают, что ресайклинг кратных друг другу векторов — это слишком удобное место для выстрелов себе в ногу. Поэтому в таких случаях разработчики dplyr рекомендуют использовать функцию rep(), знакомую нам уже очень давно (Глава 3.1).
# A tibble: 734 × 12
...1 name Gender `Eye color` Race `Hair color` Height Publisher
<dbl> <chr> <chr> <chr> <chr> <chr> <dbl> <chr>
1 0 A-Bomb Male yellow Human No Hair 203 Marvel C…
2 1 Abe Sapien Male blue Icthyo … No Hair 191 Dark Hor…
3 2 Abin Sur Male blue Ungaran No Hair 185 DC Comics
4 3 Abomination Male green Human /… No Hair 203 Marvel C…
5 4 Abraxas Male blue Cosmic … Black NA Marvel C…
6 5 Absorbing Man Male blue Human No Hair 193 Marvel C…
7 6 Adam Monroe Male blue <NA> Blond NA NBC - He…
8 7 Adam Strange Male blue Human Blond 185 DC Comics
9 8 Agent 13 Female blue <NA> Blond 173 Marvel C…
10 9 Agent Bob Male brown Human Brown 178 Marvel C…
# ℹ 724 more rows
# ℹ 4 more variables: `Skin color` <chr>, Alignment <chr>, Weight <dbl>,
# one_and_two <int>
10.9 Агрегация данных в тиббле
10.9.1 Подытоживание: summarise()
Агрегация по группам - это очень часто возникающая задача, например, это может использоваться для усреднения данных по испытуемым или условиям. Сделать агрегацию в датафрейме удобной Хэдли Уикхэм пытался еще в предшественнике dplyr, пакете plyr. dplyr позволяет делать агрегацию очень симпатичным и понятным способом. Агрегация в dplyr состоит из двух этапов: группировки (group_by()) и подытоживания (summarise()). Начнем с последнего.
Функция dplyr::summarise()7 позволяет агрегировать данные в тиббле. Работает она очень похоже на mutate(), но если внутри mutate() используются векторизованные функции, возвращающие вектор такой же длины, что и колонки, использовавшиеся для расчетов, то в summarise() используются функции, которые возвращают вектор длиной 1. Например, min(), mean(), max() и т.д. Можно создавать несколько колонок через запятую (это работает и для mutate()).
heroes %>%
mutate(imt = Weight/(Height/100)^2) %>%
summarise(min(imt, na.rm = TRUE),
max(imt, na.rm = TRUE))# A tibble: 1 × 2
`min(imt, na.rm = TRUE)` `max(imt, na.rm = TRUE)`
<dbl> <dbl>
1 0.0814 2510.
В dplyr есть дополнительные суммирующие функции для более удобного индексирования в стиле tidyverse. Например, функции dplyr::nth(), dplyr::first() и dplyr::last(), которые позволяют вытаскивать значения из вектора по индексу (что-то вроде slice(), но для векторов)
heroes %>%
mutate(imt = Weight/(Height/100)^2) %>%
arrange(imt) %>%
summarise(first = first(imt),
tenth = nth(imt, 10),
last = last(imt))# A tibble: 1 × 3
first tenth last
<dbl> <dbl> <dbl>
1 0.0814 16.7 NA
В отличие от mutate(), иногда мы хотим, чтобы функция внутри агрегации возвращала вектор из нескольких значений. Для этого вместо summarise() можно использовать reframe():
10.9.2 Группировка: group_by()
dplyr::group_by() - это функция для группировки данных в тиббле по дискретной переменной для дальнейшей агрегации с помощью summarise(). После применения group_by() тиббл будет выглядеть так же, но у него появятся атрибут groups8:
# A tibble: 734 × 11
# Groups: Gender [3]
...1 name Gender `Eye color` Race `Hair color` Height Publisher
<dbl> <chr> <chr> <chr> <chr> <chr> <dbl> <chr>
1 0 A-Bomb Male yellow Human No Hair 203 Marvel C…
2 1 Abe Sapien Male blue Icthyo … No Hair 191 Dark Hor…
3 2 Abin Sur Male blue Ungaran No Hair 185 DC Comics
4 3 Abomination Male green Human /… No Hair 203 Marvel C…
5 4 Abraxas Male blue Cosmic … Black NA Marvel C…
6 5 Absorbing Man Male blue Human No Hair 193 Marvel C…
7 6 Adam Monroe Male blue <NA> Blond NA NBC - He…
8 7 Adam Strange Male blue Human Blond 185 DC Comics
9 8 Agent 13 Female blue <NA> Blond 173 Marvel C…
10 9 Agent Bob Male brown Human Brown 178 Marvel C…
# ℹ 724 more rows
# ℹ 3 more variables: `Skin color` <chr>, Alignment <chr>, Weight <dbl>
Если после этого применить на тиббле функцию summarise(), то мы получим не тиббл длиной один, а тиббл со значением для каждой из групп.
heroes %>%
mutate(imt = Weight/(Height/100)^2) %>%
group_by(Gender) %>%
summarise(min(imt, na.rm = TRUE),
max(imt, na.rm = TRUE))# A tibble: 3 × 3
Gender `min(imt, na.rm = TRUE)` `max(imt, na.rm = TRUE)`
<chr> <dbl> <dbl>
1 Female 15.5 1613.
2 Male 0.0814 2510.
3 <NA> 16.3 114.
Схематически это выглядит вот так:

10.9.3 Подсчет строк: dplyr::n(), dplyr::count()
Для подсчёта количества значений можно воспользоваться функцией n().
# A tibble: 3 × 2
Gender n
<chr> <int>
1 Female 200
2 Male 505
3 <NA> 29
Функция n() вместе с group_by() внутри filter() позволяет удобным образом “отрезать” от тиббла редкие группы…
# A tibble: 611 × 2
# Groups: Race [6]
name Race
<chr> <chr>
1 A-Bomb Human
2 Abomination Human / Radiation
3 Absorbing Man Human
4 Adam Monroe <NA>
5 Adam Strange Human
6 Agent 13 <NA>
7 Agent Bob Human
8 Agent Zero <NA>
9 Air-Walker <NA>
10 Ajax Cyborg
# ℹ 601 more rows
или же наоборот, выделить только маленькие группы:
# A tibble: 34 × 2
# Groups: Race [34]
name Race
<chr> <chr>
1 Abe Sapien Icthyo Sapien
2 Abin Sur Ungaran
3 Alien Xenomorph XX121
4 Azazel Neyaphem
5 Bizarro Bizarro
6 Boba Fett Human / Clone
7 Darth Maul Dathomirian Zabrak
8 Fin Fang Foom Kakarantharaian
9 Gamora Zen-Whoberian
10 Gladiator Strontian
# ℹ 24 more rows
Таблицу частот можно создать без group_by() и summarise(n = n()). Функция count() заменяет эту конструкцию:
Эту таблицу частот удобно сразу проранжировать, указав в параметре sort = значение TRUE.
# A tibble: 3 × 2
Gender n
<chr> <int>
1 Male 505
2 Female 200
3 <NA> 29
Функция
count(), несмотря на свою простоту, является одной из наиболее используемых в tidyverse.
10.9.4 Уникальные значения: dplyr::distinct()
dplyr::distinct() - это более быстрый аналог unique(), позволяет извлекать уникальные значения для одной или нескольких колонок.
# A tibble: 81 × 2
Gender Race
<chr> <chr>
1 Male Human
2 Male Icthyo Sapien
3 Male Ungaran
4 Male Human / Radiation
5 Male Cosmic Entity
6 Male <NA>
7 Female <NA>
8 Male Cyborg
9 Male Xenomorph XX121
10 Male Android
# ℹ 71 more rows
Иногда нужно агрегировать данные, но при этом сохранить исходную структуру тиббла. Например, нужно посчитать размер групп или посчитать средние значения по группе для последующего сравнения с индивидуальными значениями.
10.9.5 Создание колонок с группировкой
В tidyverse это можно сделать с помощью сочетания group_by() и mutate() (вместо summarise()):
# A tibble: 734 × 4
# Groups: Race [62]
Race name Gender Race_n
<chr> <chr> <chr> <int>
1 Human A-Bomb Male 208
2 Icthyo Sapien Abe Sapien Male 1
3 Ungaran Abin Sur Male 1
4 Human / Radiation Abomination Male 11
5 Cosmic Entity Abraxas Male 4
6 Human Absorbing Man Male 208
7 <NA> Adam Monroe Male 304
8 Human Adam Strange Male 208
9 <NA> Agent 13 Female 304
10 Human Agent Bob Male 208
# ℹ 724 more rows
Результаты агрегации были записаны в отдельную колонку, при этом значения этой колонки внутри одной группы повторяются:

10.10 Заключение
Мы познакомились с основными принципами и функциями tidyverse. Этих функций, как можно заметить, очень, очень много, каждая из которых посвящена отдельному действию для работы с датафреймами. Чтобы не запутаться во всем многообразии, нужно запомнить самые основные из них:
select()– для выбора колонок,filter()– для выбора строк по условию,mutate()– для создания новых колонок,group_by()иsummarise()– для агрегации данных.
Эти функции достаточно гибкие, чтобы их хватало для большинства задач работы с данными. Однако важный принцип tidyverse – это максимальная эксплицитность: если вам нужно, скажем, поменять местами колонки, вы используете специальную функцию relocate(), которая предназначена специально для этой задачи.
Такой код очень легко читается, да и тому, кто использует tidyverse для написания кода, позволяет мыслить более четко.
Если быть точным, то оператор
%>%был импортирован во все основные пакеты tidyverse, а сам пакет magrittr не входит в набор базовых пакетов tidyverse. Тем не менее, в самом magrittr есть ещё несколько интересных операторов.↩︎Даже наоборот, использование пайпов незначительно снижает скорость выполнения команды.↩︎
{dplyr}как только не произносят: встречаются варианты “диплаер”, “диплюр”, “диплир”, “диплёр”. Наиболее правильный — “диплаер”: название расшифровывается как data frame + plyr, где ply — это игра слов: и отсылка к семейству функцийapply(), и pliers (плоскогубцы) — именно они изображены на логотипе plyr. Сам plyr обобщал идею split-apply-combine на произвольные комбинации типов данных (списки, массивы, датафреймы). Впоследствии Уикхэм создал dplyr как более быструю и удобную альтернативу plyr с декларативным, SQL-вдохновлённым синтаксисом и фокусом исключительно на датафреймах.↩︎Как и в случае с
magrittr, пакет tidyselect не содержится в базовом tidyverse, но функции импортируются основными пакетами tidyverse.↩︎Выбранный паттерн будет найден посимвольно, если же вы хотите искать по регулярным выражениям, то вместо
contains()нужно использоватьmatches().↩︎relocate()не позволяет переименовывать колонки в отличие отselect()иrename()↩︎У функции
dplyr::summarise()есть синонимdplyr::summarize(), которая делает абсолютно то же самое. Просто потому что в американском английском и британском английском это слово пишется по-разному.↩︎
